Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 1 | |
| 2 | Received: from www.crouse-house.com ([199.45.160.146] |
| 3 | for coreboot@coreboot.org; Fri, 19 Dec 2008 23:11:59 +0100 |
| 4 | From: Jordan Crouse <jordan@cosmicpenguin.net> |
| 5 | |
| 6 | |
| 7 | Greetings. I apologize for the incompleteness of what I am about to |
| 8 | discuss. I was planning on working on it leisurely, but my employment |
| 9 | circumstances changed and I've been trying to get it completed in a |
| 10 | hurry before I had to leave it behind. |
| 11 | |
| 12 | I've been thinking a lot about LAR lately, and ways to make it more |
| 13 | extensible and robust. Marc and I have been trading ideas back and |
| 14 | forth for a number of months, and over time a clear idea of what I |
| 15 | wanted to do started to take shape. |
| 16 | |
| 17 | My goal was to add small things to LAR while retaining the overall |
| 18 | scheme. Over time, the scheme evolved slightly, but I think you'll find |
| 19 | that it remains true to the original idea. Below is the beginnings of |
| 20 | an architecture document - I did it in text form, but if met with |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 21 | aclaim, it should be wikified. This presents what I call CBFS - the |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 22 | next generation LAR for next generation Coreboot. Its easier to |
| 23 | describe what it is by describing what changed: |
| 24 | |
| 25 | A header has been added somewhere in the bootblock similar to Carl |
| 26 | Daniel's scheme. In addition to the coreboot information, the header |
| 27 | reports the size of the ROM, the alignment of the blocks, and the offset |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 28 | of the first component in the CBFS. The master header provides all |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 29 | the information LAR needs plus the magic number information flashrom needs. |
| 30 | |
| 31 | Each "file" (or component, as I style them) now has a type associated |
| 32 | with it. The type is used by coreboot to identify the type of file that |
| 33 | it is loading, and it can also be used by payloads to group items in the |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 34 | CBFS by type (i.e - bayou can ask for all components that are payloads). |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 35 | |
| 36 | The header on each "file" (or component, as I like to style them) has |
| 37 | been simplified - We now only store the length, the type, the checksum, |
| 38 | and the offset to the data. The name scheme remains the same. The |
| 39 | addtional information, which is component specific, has been moved to |
| 40 | the component itself (see below). |
| 41 | |
| 42 | The components are arranged in the ROM aligned along the specified |
| 43 | alignment from the master header - this is to facilitate partial re-write. |
| 44 | |
| 45 | Other then that, the LAR ideas remain pretty much the same. |
| 46 | |
| 47 | The plan for moving the metadata to the components is to allow many |
| 48 | different kinds of components, not all of which are groked by coreboot. |
| 49 | However, there are three essential component types that are groked by |
| 50 | coreboot, and they are defined: |
| 51 | |
| 52 | stage - the stage is being parsed from the original ELF, and stored in |
| 53 | the ROM as a single blob of binary data. The load address, start |
| 54 | address, compression type and length are stored in the component sub-header. |
| 55 | |
| 56 | payload - this is essentially SELF in different clothing - same idea as |
| 57 | SELF, with the sub-header as above. |
| 58 | |
| 59 | optionrom - This is in flux - right now, the optionrom is stored |
| 60 | unadulterated and uncompressed, but that is likely to be changed. |
| 61 | |
| 62 | Following this email are two replies containing the v3 code and a new |
| 63 | ROM tool to implement this respectively. I told you that I was trying |
| 64 | to get this out before I disappear, and I'm not kidding - the code is |
| 65 | compile tested and not run-tested. I hope that somebody will embrace |
| 66 | this code and take it the rest of the way, otherwise it will die a |
| 67 | pretty short death. |
| 68 | |
| 69 | I realize that this will start an awesome flamewar, and I'm looking |
| 70 | forward to it. Thanks for listening to me over the years - and good |
| 71 | luck with coreboot. When you all make a million dollars, send me a few |
| 72 | bucks, will you? |
| 73 | |
| 74 | Jordan |
| 75 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 76 | Coreboot CBFS Specification |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 77 | Jordan Crouse <jordan@cosmicpenguin.net> |
| 78 | |
| 79 | = Introduction = |
| 80 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 81 | This document describes the coreboot CBFS specification (from here |
| 82 | referred to as CBFS). CBFS is a scheme for managing independent chunks |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 83 | of data in a system ROM. Though not a true filesystem, the style and |
| 84 | concepts are similar. |
| 85 | |
| 86 | |
| 87 | = Architecture = |
| 88 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 89 | The CBFS architecture looks like the following: |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 90 | |
| 91 | /---------------\ <-- Start of ROM |
| 92 | | /-----------\ | --| |
| 93 | | | Header | | | |
| 94 | | |-----------| | | |
| 95 | | | Name | | |-- Component |
| 96 | | |-----------| | | |
| 97 | | |Data | | | |
| 98 | | |.. | | | |
| 99 | | \-----------/ | --| |
| 100 | | | |
| 101 | | /-----------\ | |
| 102 | | | Header | | |
| 103 | | |-----------| | |
| 104 | | | Name | | |
| 105 | | |-----------| | |
| 106 | | |Data | | |
| 107 | | |.. | | |
| 108 | | \-----------/ | |
| 109 | | | |
| 110 | | ... | |
| 111 | | /-----------\ | |
| 112 | | | | | |
| 113 | | | Bootblock | | |
| 114 | | | --------- | | |
| 115 | | | Reset | | <- 0xFFFFFFF0 |
| 116 | | \-----------/ | |
| 117 | \---------------/ |
| 118 | |
| 119 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 120 | The CBFS architecture consists of a binary associated with a physical |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 121 | ROM disk referred hereafter as the ROM. A number of independent of |
| 122 | components, each with a header prepended on to data are located within |
| 123 | the ROM. The components are nominally arranged sequentially, though they |
| 124 | are aligned along a pre-defined boundary. |
| 125 | |
| 126 | The bootblock occupies the last 20k of the ROM. Within |
| 127 | the bootblock is a master header containing information about the ROM |
| 128 | including the size, alignment of the components, and the offset of the |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 129 | start of the first CBFS component within the ROM. |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 130 | |
| 131 | = Master Header = |
| 132 | |
| 133 | The master header contains essential information about the ROM that is |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 134 | used by both the CBFS implementation within coreboot at runtime as well |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 135 | as host based utilities to create and manage the ROM. The master header |
| 136 | will be located somewhere within the bootblock (last 20k of the ROM). A |
| 137 | pointer to the location of the header will be located at offset |
| 138 | -12 from the end of the ROM. This translates to address 0xFFFFFFF4 on a |
| 139 | normal x86 system. The pointer will be to physical memory somewhere |
| 140 | between - 0xFFFFB000 and 0xFFFFFFF0. This makes it easier for coreboot |
| 141 | to locate the header at run time. Build time utilities will |
| 142 | need to read the pointer and do the appropriate math to locate the header. |
| 143 | |
| 144 | The following is the structure of the master header: |
| 145 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 146 | struct cbfs_header { |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 147 | unsigned int magic; |
| 148 | unsigned int size; |
| 149 | unsigned int align; |
| 150 | unsigned int offset; |
| 151 | }; |
| 152 | |
| 153 | The meaning of each member is as follows: |
| 154 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 155 | 'magic' is a 32 bit number that identifies the ROM as a CBFS type. The |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 156 | magic |
| 157 | number is 0x4F524243, which is 'ORBC' in ASCII. |
| 158 | |
| 159 | 'size' is the size of the ROM in bytes. Coreboot will subtract 'size' from |
| 160 | 0xFFFFFFFF to locate the beginning of the ROM in memory. |
| 161 | |
| 162 | 'align' is the number of bytes that each component is aligned to within the |
| 163 | ROM. This is used to make sure that each component is aligned correctly |
| 164 | with |
| 165 | regards to the erase block sizes on the ROM - allowing one to replace a |
| 166 | component at runtime without disturbing the others. |
| 167 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 168 | 'offset' is the offset of the the first CBFS component (from the start of |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 169 | the ROM). This is to allow for arbitrary space to be left at the beginning |
| 170 | of the ROM for things like embedded controller firmware. |
| 171 | |
| 172 | = Bootblock = |
| 173 | The bootblock is a mandatory component in the ROM. It is located in the |
| 174 | last |
| 175 | 20k of the ROM space, and contains, among other things, the location of the |
| 176 | master header and the entry point for the loader firmware. The bootblock |
| 177 | does not have a component header attached to it. |
| 178 | |
| 179 | = Components = |
| 180 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 181 | CBFS components are placed in the ROM starting at 'offset' specified in |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 182 | the master header and ending at the bootblock. Thus the total size |
| 183 | available |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 184 | for components in the ROM is (ROM size - 20k - 'offset'). Each CBFS |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 185 | component is to be aligned according to the 'align' value in the header. |
| 186 | Thus, if a component of size 1052 is located at offset 0 with an 'align' |
| 187 | value |
| 188 | of 1024, the next component will be located at offset 2048. |
| 189 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 190 | Each CBFS component will be indexed with a unique ASCII string name of |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 191 | unlimited size. |
| 192 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 193 | Each CBFS component starts with a header: |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 194 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 195 | struct cbfs_file { |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 196 | char magic[8]; |
| 197 | unsigned int len; |
| 198 | unsigned int type; |
| 199 | unsigned int checksum; |
| 200 | unsigned int offset; |
| 201 | }; |
| 202 | |
| 203 | 'magic' is a magic value used to identify the header. During runtime, |
| 204 | coreboot will scan the ROM looking for this value. The default magic is |
| 205 | the string 'LARCHIVE'. |
| 206 | |
| 207 | 'len' is the length of the data, not including the size of the header and |
| 208 | the size of the name. |
| 209 | |
| 210 | 'type' is a 32 bit number indicating the type of data that is attached. |
| 211 | The data type is used in a number of ways, as detailed in the section |
| 212 | below. |
| 213 | |
| 214 | 'checksum' is a 32bit checksum of the entire component, including the |
| 215 | header and name. |
| 216 | |
| 217 | 'offset' is the start of the component data, based off the start of the |
| 218 | header. |
| 219 | The difference between the size of the header and offset is the size of the |
| 220 | component name. |
| 221 | |
| 222 | Immediately following the header will be the name of the component, |
| 223 | which will |
| 224 | null terminated and 16 byte aligned. The following picture shows the |
| 225 | structure of the header: |
| 226 | |
| 227 | /--------\ <- start |
| 228 | | Header | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 229 | |--------| <- sizeof(struct cbfs_file) |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 230 | | Name | |
| 231 | |--------| <- 'offset' |
| 232 | | Data | |
| 233 | | ... | |
| 234 | \--------/ <- start + 'offset' + 'len' |
| 235 | |
| 236 | == Searching Alogrithm == |
| 237 | |
| 238 | To locate a specific component in the ROM, one starts at the 'offset' |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 239 | specified in the CBFS master header. For this example, the offset will |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 240 | be 0. |
| 241 | |
| 242 | From that offset, the code should search for the magic string on the |
| 243 | component, jumping 'align' bytes each time. So, assuming that 'align' is |
| 244 | 16, the code will search for the string 'LARCHIVE' at offset 0, 16, 32, etc. |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 245 | If the offset ever exceeds the allowable range for CBFS components, then no |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 246 | component was found. |
| 247 | |
| 248 | Upon recognizing a component, the software then has to search for the |
| 249 | specific name of the component. This is accomplished by comparing the |
| 250 | desired name with the string on the component located at |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 251 | offset + sizeof(struct cbfs_file). If the string matches, then the |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 252 | component |
| 253 | has been located, otherwise the software should add 'offset' + 'len' to |
| 254 | the offset and resume the search for the magic value. |
| 255 | |
| 256 | == Data Types == |
| 257 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 258 | The 'type' member of struct cbfs_file is used to identify the content |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 259 | of the component data, and is used by coreboot and other |
| 260 | run-time entities to make decisions about how to handle the data. |
| 261 | |
| 262 | There are three component types that are essential to coreboot, and so |
| 263 | are defined here. |
| 264 | |
| 265 | === Stages === |
| 266 | |
| 267 | Stages are code loaded by coreboot during the boot process. They are |
| 268 | essential to a successful boot. Stages are comprised of a single blob |
| 269 | of binary data that is to be loaded into a particular location in memory |
| 270 | and executed. The uncompressed header contains information about how |
| 271 | large the data is, and where it should be placed, and what additional memory |
| 272 | needs to be cleared. |
| 273 | |
| 274 | Stages are assigned a component value of 0x10. When coreboot sees this |
| 275 | component type, it knows that it should pass the data to a sub-function |
| 276 | that will process the stage. |
| 277 | |
| 278 | The following is the format of a stage component: |
| 279 | |
| 280 | /--------\ |
| 281 | | Header | |
| 282 | |--------| |
| 283 | | Binary | |
| 284 | | .. | |
| 285 | \--------/ |
| 286 | |
| 287 | The header is defined as: |
| 288 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 289 | struct cbfs_stage { |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 290 | unsigned int compression; |
| 291 | unsigned long long entry; |
| 292 | unsigned long long load; |
| 293 | unsigned int len; |
| 294 | unsigned int memlen; |
| 295 | }; |
| 296 | |
| 297 | 'compression' is an integer defining how the data is compressed. There |
| 298 | are three compression types defined by this version of the standard: |
| 299 | none (0x0), lzma (0x1), and nrv2b (0x02), though additional types may be |
| 300 | added assuming that coreboot understands how to handle the scheme. |
| 301 | |
| 302 | 'entry' is a 64 bit value indicating the location where the program |
| 303 | counter should jump following the loading of the stage. This should be |
| 304 | an absolute physical memory address. |
| 305 | |
| 306 | 'load' is a 64 bit value indicating where the subsequent data should be |
| 307 | loaded. This should be an absolute physical memory address. |
| 308 | |
| 309 | 'len' is the length of the compressed data in the component. |
| 310 | |
| 311 | 'memlen' is the amount of memory that will be used by the component when |
| 312 | it is loaded. |
| 313 | |
| 314 | The component data will start immediately following the header. |
| 315 | |
| 316 | When coreboot loads a stage, it will first zero the memory from 'load' to |
| 317 | 'memlen'. It will then decompress the component data according to the |
| 318 | specified scheme and place it in memory starting at 'load'. Following that, |
| 319 | it will jump execution to the address specified by 'entry'. |
| 320 | Some components are designed to execute directly from the ROM - coreboot |
| 321 | knows which components must do that and will act accordingly. |
| 322 | |
| 323 | === Payloads === |
| 324 | |
| 325 | Payloads are loaded by coreboot following the boot process. |
| 326 | |
| 327 | Stages are assigned a component value of 0x20. When coreboot sees this |
| 328 | component type, it knows that it should pass the data to a sub-function |
| 329 | that will process the payload. Furthermore, other run time |
| 330 | applications such as 'bayou' may easily index all available payloads |
| 331 | on the system by searching for the payload type. |
| 332 | |
| 333 | |
| 334 | The following is the format of a stage component: |
| 335 | |
| 336 | /-----------\ |
| 337 | | Header | |
| 338 | | Segment 1 | |
| 339 | | Segment 2 | |
| 340 | | ... | |
| 341 | |-----------| |
| 342 | | Binary | |
| 343 | | .. | |
| 344 | \-----------/ |
| 345 | |
| 346 | The header is as follows: |
| 347 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 348 | struct cbfs_payload { |
| 349 | struct cbfs_payload_segment segments; |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 350 | } |
| 351 | |
| 352 | The header contains a number of segments corresponding to the segments |
| 353 | that need to be loaded for the payload. |
| 354 | |
| 355 | The following is the structure of each segment header: |
| 356 | |
Peter Stuge | 450b23f | 2009-04-14 00:01:34 +0000 | [diff] [blame] | 357 | struct cbfs_payload_segment { |
Stefan Reinauer | 013c7cf | 2009-04-08 07:47:01 +0000 | [diff] [blame] | 358 | unsigned int type; |
| 359 | unsigned int compression; |
| 360 | unsigned int offset; |
| 361 | unsigned long long load_addr; |
| 362 | unsigned int len; |
| 363 | unsigned int mem_len; |
| 364 | }; |
| 365 | |
| 366 | 'type' is the type of segment, one of the following: |
| 367 | |
| 368 | PAYLOAD_SEGMENT_CODE 0x45444F43 The segment contains executable code |
| 369 | PAYLOAD_SEGMENT_DATA 0x41544144 The segment contains data |
| 370 | PAYLOAD_SEGMENT_BSS 0x20535342 The memory speicfied by the segment |
| 371 | should be zeroed |
| 372 | PAYLOAD_SEGMENT_PARAMS 0x41524150 The segment contains information for |
| 373 | the payload |
| 374 | PAYLOAD_SEGMENT_ENTRY 0x52544E45 The segment contains the entry point |
| 375 | for the payload |
| 376 | |
| 377 | 'compression' is the compression scheme for the segment. Each segment can |
| 378 | be independently compressed. There are three compression types defined by |
| 379 | this version of the standard: none (0x0), lzma (0x1), and nrv2b (0x02), |
| 380 | though additional types may be added assuming that coreboot understands |
| 381 | how to handle the scheme. |
| 382 | |
| 383 | 'offset' is the address of the data within the component, starting from |
| 384 | the component header. |
| 385 | |
| 386 | 'load_addr' is a 64 bit value indicating where the segment should be placed |
| 387 | in memory. |
| 388 | |
| 389 | 'len' is a 32 bit value indicating the size of the segment within the |
| 390 | component. |
| 391 | |
| 392 | 'mem_len' is the size of the data when it is placed into memory. |
| 393 | |
| 394 | The data will located immediately following the last segment. |
| 395 | |
| 396 | === Option ROMS === |
| 397 | |
| 398 | The third specified component type will be Option ROMs. Option ROMS will |
| 399 | have component type '0x30'. They will have no additional header, the |
| 400 | uncompressed binary data will be located in the data portion of the |
| 401 | component. |
| 402 | |
| 403 | === NULL === |
| 404 | |
| 405 | There is a 4th component type ,defined as NULL (0xFFFFFFFF). This is |
| 406 | the "don't care" component type. This can be used when the component |
| 407 | type is not necessary (such as when the name of the component is unique. |
| 408 | i.e. option_table). It is recommended that all components be assigned a |
| 409 | unique type, but NULL can be used when the type does not matter. |