Drop duplicate version of the documentation/cbfs.txt file as discussed.
Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de> Acked-by: Uwe Hermann <uwe@hermann-uwe.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4797 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
@ -1,337 +0,0 @@
|
|||||||
Coreboot CBFS Specification
|
|
||||||
Jordan Crouse <jordan@cosmicpenguin.net>
|
|
||||||
|
|
||||||
= Introduction =
|
|
||||||
|
|
||||||
This document describes the coreboot CBFS specification (from here referred
|
|
||||||
to as CBFS). CBFS is a scheme for managing independent chunks of data in
|
|
||||||
a system ROM. Though not a true filesystem, the style and concepts are
|
|
||||||
similar.
|
|
||||||
|
|
||||||
= Architecture =
|
|
||||||
|
|
||||||
The CBFS architecture looks like the following:
|
|
||||||
|
|
||||||
/---------------\ <-- Start of ROM
|
|
||||||
| /-----------\ | --|
|
|
||||||
| | Header | | |
|
|
||||||
| |-----------| | |
|
|
||||||
| | Name | | |-- Component
|
|
||||||
| |-----------| | |
|
|
||||||
| |Data | | |
|
|
||||||
| |.. | | |
|
|
||||||
| \-----------/ | --|
|
|
||||||
| |
|
|
||||||
| /-----------\ |
|
|
||||||
| | Header | |
|
|
||||||
| |-----------| |
|
|
||||||
| | Name | |
|
|
||||||
| |-----------| |
|
|
||||||
| |Data | |
|
|
||||||
| |.. | |
|
|
||||||
| \-----------/ |
|
|
||||||
| |
|
|
||||||
| ... |
|
|
||||||
| /-----------\ |
|
|
||||||
| | | |
|
|
||||||
| | Bootblock | |
|
|
||||||
| | --------- | |
|
|
||||||
| | Reset | | <- 0xFFFFFFF0
|
|
||||||
| \-----------/ |
|
|
||||||
\---------------/
|
|
||||||
|
|
||||||
|
|
||||||
The CBFS architecture consists of a binary associated with a physical
|
|
||||||
ROM disk referred hereafter as the ROM. A number of independent of
|
|
||||||
components, each with a header prepended on to data are located within
|
|
||||||
the ROM. The components are nominally arranged sequentially, though they
|
|
||||||
are aligned along a pre-defined boundary.
|
|
||||||
|
|
||||||
The bootblock occupies the last 20k of the ROM. Within
|
|
||||||
the bootblock is a master header containing information about the ROM
|
|
||||||
including the size, alignment of the components, and the offset of the
|
|
||||||
start of the first CBFS component within the ROM.
|
|
||||||
|
|
||||||
= Master Header =
|
|
||||||
|
|
||||||
The master header contains essential information about the ROM that is
|
|
||||||
used by both the CBFS implementation within coreboot at runtime as well
|
|
||||||
as host based utilities to create and manage the ROM. The master header
|
|
||||||
will be located somewhere within the bootblock (high end of the ROM). A
|
|
||||||
pointer to the location of the header will be located at offset
|
|
||||||
-4 from the end of the ROM. This translates to address 0xFFFFFFFC on a
|
|
||||||
normal x86 system. The pointer will be to physical memory somewhere
|
|
||||||
between - 0xFFFF0000 and 0xFFFFFFF0. This makes it easier for coreboot
|
|
||||||
to locate the header at run time. Build time utilities will
|
|
||||||
need to read the pointer and do the appropriate math to locate the header.
|
|
||||||
|
|
||||||
The following is the structure of the master header:
|
|
||||||
|
|
||||||
struct cbfs_header {
|
|
||||||
unsigned int magic;
|
|
||||||
unsigned int version;
|
|
||||||
unsigned int romsize;
|
|
||||||
unsigned int bootblocksize;
|
|
||||||
unsigned int align;
|
|
||||||
unsigned int offset;
|
|
||||||
unsigned int pad[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
The meaning of each member is as follows:
|
|
||||||
|
|
||||||
'magic' is a 32 bit number that identifies the ROM as a CBFS type. The magic
|
|
||||||
number is 0x4F524243, which is 'ORBC' in ASCII.
|
|
||||||
|
|
||||||
'version' is a 32 bit number that identifies the version of CBFS. The current
|
|
||||||
version is 0x31313131 ('1111' in ASCII) which is endian-independent.
|
|
||||||
|
|
||||||
'romsize' is the size of the ROM in bytes. Coreboot will subtract 'size' from
|
|
||||||
0xFFFFFFFF to locate the beginning of the ROM in memory.
|
|
||||||
|
|
||||||
'bootblocksize' is the boot block size in bytes. There is no limitation on
|
|
||||||
the boot block size as in v3.
|
|
||||||
|
|
||||||
'align' is the number of bytes that each component is aligned to within the
|
|
||||||
ROM. This is used to make sure that each component is aligned correctly with
|
|
||||||
regards to the erase block sizes on the ROM - allowing one to replace a
|
|
||||||
component at runtime without disturbing the others.
|
|
||||||
|
|
||||||
'offset' is the offset of the the first CBFS component (from the start of
|
|
||||||
the ROM). This is to allow for arbitrary space to be left at the beginning
|
|
||||||
of the ROM for things like embedded controller firmware.
|
|
||||||
|
|
||||||
'pad' rounds the header to 32 bytes and reserves a little room for later use.
|
|
||||||
|
|
||||||
= Bootblock =
|
|
||||||
The bootblock is a mandatory component in the ROM. It is located in the
|
|
||||||
last bootblocksize bytes of ROM space, and contains, among other things,
|
|
||||||
the location of the master header and the entry point for the loader
|
|
||||||
firmware. The bootblock does not have a component header attached to it.
|
|
||||||
|
|
||||||
|
|
||||||
= Components =
|
|
||||||
|
|
||||||
CBFS components are placed in the ROM starting at 'offset' specified in
|
|
||||||
the master header and ending at the bootblock. Thus the total size available
|
|
||||||
for components in the ROM is (ROM size - bootblocksize - 'offset'). Each CBFS
|
|
||||||
component is to be aligned according to the 'align' value in the header.
|
|
||||||
Thus, if a component of size 1052 is located at offset 0 with an 'align' value
|
|
||||||
of 1024, the next component will be located at offset 2048.
|
|
||||||
|
|
||||||
Each CBFS component will be indexed with a unique ASCII string name of
|
|
||||||
unlimited size.
|
|
||||||
|
|
||||||
Each CBFS component starts with a header:
|
|
||||||
|
|
||||||
struct cbfs_file {
|
|
||||||
char magic[8];
|
|
||||||
unsigned int len;
|
|
||||||
unsigned int type;
|
|
||||||
unsigned int checksum;
|
|
||||||
unsigned int offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
'magic' is a magic value used to identify the header. During runtime,
|
|
||||||
coreboot will scan the ROM looking for this value. The default magic is
|
|
||||||
the string 'LARCHIVE'.
|
|
||||||
|
|
||||||
'len' is the length of the data, not including the size of the header and
|
|
||||||
the size of the name.
|
|
||||||
|
|
||||||
'type' is a 32 bit number indicating the type of data that is attached.
|
|
||||||
The data type is used in a number of ways, as detailed in the section
|
|
||||||
below.
|
|
||||||
|
|
||||||
'checksum' is a 32bit checksum of the entire component, including the
|
|
||||||
header and name.
|
|
||||||
|
|
||||||
'offset' is the start of the component data, based off the start of the header.
|
|
||||||
The difference between the size of the header and offset is the size of the
|
|
||||||
component name.
|
|
||||||
|
|
||||||
Immediately following the header will be the name of the component, which will
|
|
||||||
null terminated and 16 byte aligned. The following picture shows the
|
|
||||||
structure of the header:
|
|
||||||
|
|
||||||
/--------\ <- start
|
|
||||||
| Header |
|
|
||||||
|--------| <- sizeof(struct cbfs_file)
|
|
||||||
| Name |
|
|
||||||
|--------| <- 'offset'
|
|
||||||
| Data |
|
|
||||||
| ... |
|
|
||||||
\--------/ <- start + 'offset' + 'len'
|
|
||||||
|
|
||||||
== Searching Alogrithm ==
|
|
||||||
|
|
||||||
To locate a specific component in the ROM, one starts at the 'offset'
|
|
||||||
specified in the CBFS master header. For this example, the offset will
|
|
||||||
be 0.
|
|
||||||
|
|
||||||
From that offset, the code should search for the magic string on the
|
|
||||||
component, jumping 'align' bytes each time. So, assuming that 'align' is
|
|
||||||
16, the code will search for the string 'LARCHIVE' at offset 0, 16, 32, etc.
|
|
||||||
If the offset ever exceeds the allowable range for CBFS components, then no
|
|
||||||
component was found.
|
|
||||||
|
|
||||||
Upon recognizing a component, the software then has to search for the
|
|
||||||
specific name of the component. This is accomplished by comparing the
|
|
||||||
desired name with the string on the component located at
|
|
||||||
offset + sizeof(struct cbfs_file). If the string matches, then the component
|
|
||||||
has been located, otherwise the software should add 'offset' + 'len' to
|
|
||||||
the offset and resume the search for the magic value.
|
|
||||||
|
|
||||||
== Data Types ==
|
|
||||||
|
|
||||||
The 'type' member of struct cbfs_file is used to identify the content
|
|
||||||
of the component data, and is used by coreboot and other
|
|
||||||
run-time entities to make decisions about how to handle the data.
|
|
||||||
|
|
||||||
There are three component types that are essential to coreboot, and so
|
|
||||||
are defined here.
|
|
||||||
|
|
||||||
=== Stages ===
|
|
||||||
|
|
||||||
Stages are code loaded by coreboot during the boot process. They are
|
|
||||||
essential to a successful boot. Stages are comprised of a single blob
|
|
||||||
of binary data that is to be loaded into a particular location in memory
|
|
||||||
and executed. The uncompressed header contains information about how
|
|
||||||
large the data is, and where it should be placed, and what additional memory
|
|
||||||
needs to be cleared.
|
|
||||||
|
|
||||||
Stages are assigned a component value of 0x10. When coreboot sees this
|
|
||||||
component type, it knows that it should pass the data to a sub-function
|
|
||||||
that will process the stage.
|
|
||||||
|
|
||||||
The following is the format of a stage component:
|
|
||||||
|
|
||||||
/--------\
|
|
||||||
| Header |
|
|
||||||
|--------|
|
|
||||||
| Binary |
|
|
||||||
| .. |
|
|
||||||
\--------/
|
|
||||||
|
|
||||||
The header is defined as:
|
|
||||||
|
|
||||||
struct cbfs_stage {
|
|
||||||
unsigned int compression;
|
|
||||||
unsigned long long entry;
|
|
||||||
unsigned long long load;
|
|
||||||
unsigned int len;
|
|
||||||
unsigned int memlen;
|
|
||||||
};
|
|
||||||
|
|
||||||
'compression' is an integer defining how the data is compressed. There
|
|
||||||
are three compression types defined by this version of the standard:
|
|
||||||
none (0x0), lzma (0x1), and nrv2b (0x02), though additional types may be
|
|
||||||
added assuming that coreboot understands how to handle the scheme.
|
|
||||||
|
|
||||||
'entry' is a 64 bit value indicating the location where the program
|
|
||||||
counter should jump following the loading of the stage. This should be
|
|
||||||
an absolute physical memory address.
|
|
||||||
|
|
||||||
'load' is a 64 bit value indicating where the subsequent data should be
|
|
||||||
loaded. This should be an absolute physical memory address.
|
|
||||||
|
|
||||||
'len' is the length of the compressed data in the component.
|
|
||||||
|
|
||||||
'memlen' is the amount of memory that will be used by the component when
|
|
||||||
it is loaded.
|
|
||||||
|
|
||||||
The component data will start immediately following the header.
|
|
||||||
|
|
||||||
When coreboot loads a stage, it will first zero the memory from 'load' to
|
|
||||||
'memlen'. It will then decompress the component data according to the
|
|
||||||
specified scheme and place it in memory starting at 'load'. Following that,
|
|
||||||
it will jump execution to the address specified by 'entry'.
|
|
||||||
Some components are designed to execute directly from the ROM - coreboot
|
|
||||||
knows which components must do that and will act accordingly.
|
|
||||||
|
|
||||||
=== Payloads ===
|
|
||||||
|
|
||||||
Payloads are loaded by coreboot following the boot process.
|
|
||||||
|
|
||||||
Stages are assigned a component value of 0x20. When coreboot sees this
|
|
||||||
component type, it knows that it should pass the data to a sub-function
|
|
||||||
that will process the payload. Furthermore, other run time
|
|
||||||
applications such as 'bayou' may easily index all available payloads
|
|
||||||
on the system by searching for the payload type.
|
|
||||||
|
|
||||||
|
|
||||||
The following is the format of a stage component:
|
|
||||||
|
|
||||||
/-----------\
|
|
||||||
| Header |
|
|
||||||
| Segment 1 |
|
|
||||||
| Segment 2 |
|
|
||||||
| ... |
|
|
||||||
|-----------|
|
|
||||||
| Binary |
|
|
||||||
| .. |
|
|
||||||
\-----------/
|
|
||||||
|
|
||||||
The header is as follows:
|
|
||||||
|
|
||||||
struct cbfs_payload {
|
|
||||||
struct cbfs_payload_segment segments;
|
|
||||||
}
|
|
||||||
|
|
||||||
The header contains a number of segments corresponding to the segments
|
|
||||||
that need to be loaded for the payload.
|
|
||||||
|
|
||||||
The following is the structure of each segment header:
|
|
||||||
|
|
||||||
struct cbfs_payload_segment {
|
|
||||||
unsigned int type;
|
|
||||||
unsigned int compression;
|
|
||||||
unsigned int offset;
|
|
||||||
unsigned long long load_addr;
|
|
||||||
unsigned int len;
|
|
||||||
unsigned int mem_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
'type' is the type of segment, one of the following:
|
|
||||||
|
|
||||||
PAYLOAD_SEGMENT_CODE 0x45444F43 The segment contains executable code
|
|
||||||
PAYLOAD_SEGMENT_DATA 0x41544144 The segment contains data
|
|
||||||
PAYLOAD_SEGMENT_BSS 0x20535342 The memory speicfied by the segment
|
|
||||||
should be zeroed
|
|
||||||
PAYLOAD_SEGMENT_PARAMS 0x41524150 The segment contains information for
|
|
||||||
the payload
|
|
||||||
PAYLOAD_SEGMENT_ENTRY 0x52544E45 The segment contains the entry point
|
|
||||||
for the payload
|
|
||||||
|
|
||||||
'compression' is the compression scheme for the segment. Each segment can
|
|
||||||
be independently compressed. There are three compression types defined by
|
|
||||||
this version of the standard: none (0x0), lzma (0x1), and nrv2b (0x02),
|
|
||||||
though additional types may be added assuming that coreboot understands
|
|
||||||
how to handle the scheme.
|
|
||||||
|
|
||||||
'offset' is the address of the data within the component, starting from
|
|
||||||
the component header.
|
|
||||||
|
|
||||||
'load_addr' is a 64 bit value indicating where the segment should be placed
|
|
||||||
in memory.
|
|
||||||
|
|
||||||
'len' is a 32 bit value indicating the size of the segment within the
|
|
||||||
component.
|
|
||||||
|
|
||||||
'mem_len' is the size of the data when it is placed into memory.
|
|
||||||
|
|
||||||
The data will located immediately following the last segment.
|
|
||||||
|
|
||||||
=== Option ROMS ===
|
|
||||||
|
|
||||||
The third specified component type will be Option ROMs. Option ROMS will
|
|
||||||
have component type '0x30'. They will have no additional header, the
|
|
||||||
uncompressed binary data will be located in the data portion of the
|
|
||||||
component.
|
|
||||||
|
|
||||||
=== NULL ===
|
|
||||||
|
|
||||||
There is a 4th component type ,defined as NULL (0xFFFFFFFF). This is
|
|
||||||
the "don't care" component type. This can be used when the component
|
|
||||||
type is not necessary (such as when the name of the component is unique.
|
|
||||||
i.e. option_table). It is recommended that all components be assigned a
|
|
||||||
unique type, but NULL can be used when the type does not matter.
|
|
Reference in New Issue
Block a user