Difference between revisions of "SELF"

From coreboot
Jump to: navigation, search
(Description: clarify compression)
(Add the param section)
 
(One intermediate revision by the same user not shown)
Line 10: Line 10:
 
!Description
 
!Description
 
|-
 
|-
| 1 || CODE || This segment has executable code to be copied from the data section to memory (segment data may be compressed if specified by the LAR)
+
| 'CODE' (0x45444F43) || CODE || This segment has executable code to be copied from the data section to memory.  Each CODE segment has a corresponding block of data, which may be compressed in the LAR.  Multiple segments of this type are allowed.
 
|-
 
|-
| 2 || DATA || This segment has non-executable data to be copied from the data section into memory (segment data may be compressed if specified by the LAR)
+
| 'DATA' (0x41543144) || DATA || This segment has non-executable data to be copied from the data section into memory. Each DATA segment has a corresponding block of data, which may be compressed in the LAR.  Multiple segments of this type are allowed.
 
|-
 
|-
| 3 || BSS || This segment defines a section of memory to be zeroed.  Nothing is copied into memory.
+
| 'BSS ' (0x20535342) || BSS || This segment defines a section of memory to be zeroed.  BSS segments do not have any data associated with them.  Multiple segments of this type are allowed.
 
|-
 
|-
| 4 || NAME || This segment contains a descriptive string in the data section that is used by the payload loader to identify the current payload.  Nothing is copied into memory (segment data must '''not''' be compressed)
+
| 'PARA' (0x41524150)|| PARAMS || This segment contains the contents of the .notes.pinfo section from the payload ELF.  The payload will store parameters in this section for the benefit of a chooser payload.  The parameters will be stored as a series of strings of the format "key=value\0".
 
|-
 
|-
| 5 || NOTES || This segment contains the contents of the .notes section in the data segment.  This is for use by the payload loader. Nothing is copied into memory (segment data must '''not''' be compressed)
+
| 'ENTR' (0x52544E45) || ENTRY || This segment defines the entry point for execution.  This type signifies the end of the list of segments, and it must be the last segment defined in the SELF.  It is mandatory and can only be used once.
|-
+
| 6 || ENTRY || This segment defines the entry point for execution.  This type signifies the end of the list of segments.  It is mandatory and can only be used once.
+
 
|}
 
|}
  
Line 34: Line 32:
 
     unsigned long type;
 
     unsigned long type;
 
     unsigned long offset;
 
     unsigned long offset;
     unsigned long load_addr;
+
     unsigned long long load_addr;
 
     unsigned long len;
 
     unsigned long len;
 
     unsigned long mem_len;
 
     unsigned long mem_len;
 
  };
 
  };
  
All fields are present in each segment entry, though not every field will be valid for every segment type.  The following table lists which members are used and what they mean:
+
All fields are present in each segment entry, though not every field will be valid for every segment type.  The value of each field will be stored in little endian format.  Big endian architectures will need to byte swap the value before using it. The following table lists which members are used and what they mean:
  
 
{| border="1"
 
{| border="1"
Line 55: Line 53:
 
| BSS || N/A || Start address of the block in memory to be zeroed || N/A || Length of the block in memory to be zeroed  
 
| BSS || N/A || Start address of the block in memory to be zeroed || N/A || Length of the block in memory to be zeroed  
 
|-
 
|-
| NAME || Offset of the segment in the SELF file || N/A || length of the data in the segment data section || N/A
+
| PARAM || Offset of the segment in the SELF file || N/A || length of the data in the segment data section || N/A
|-
+
| NOTES || Offset of the segment in the SELF file || N/A || length of the data in the segment data section || N/A
+
 
|-
 
|-
 
| ENTRY || N/A || Address where execution should start || N/A || N/A
 
| ENTRY || N/A || Address where execution should start || N/A || N/A
Line 64: Line 60:
 
=== Segment Section ===
 
=== Segment Section ===
  
The data section immediately follows the final entry in the segment table.  Each block of segment data is written sequentially in this section. CODE and DATA sections may be compressed, NAME and NOTES sections must be uncompressed.
+
The data section immediately follows the final entry in the segment table.  Each block of segment data is written sequentially in this section, with the start of each block aligned to a 32 bit boundary.
 +
CODE and DATA sections may be compressed according to the LAR compression scheme, the PARAM section must be uncompressed.
  
 
== Typical Use ==
 
== Typical Use ==
  
There are two usage models for the SELF.  The first is the payload loader that wishes to determine the name of the payload for a graphical chooser.  The following is the psuedo code for accomplishing this:
+
The following pseudo code shows how a SELF is loaded and run:
 
+
get_name(char *name) {
+
  ptr = SELF_start;
+
  struct self_header *header;
+
+
  do {
+
    header = (struct self_header *) ptr;
+
+
    if (header->type == SELF_NAME) {
+
            memcpy(name, SELF_start + header->offset, header->size);
+
            return 0;
+
    }
+
   
+
    ptr += sizeof(*header);
+
  } while(header->type != SELF_ENTRY);
+
+
  return -1;
+
}
+
   
+
The second usage model is actually loading and running the code - this is accomplished in a stream fashion like so:
+
  
 
  decompress_and_run(void) {
 
  decompress_and_run(void) {
Line 111: Line 88:
 
   }
 
   }
 
  }
 
  }
 +
 +
== Changelog ==
 +
 +
* Replace the NAME and NOTE sections with the PARAMS section
 +
* Change ID of each segment to 4 text characters
 +
* Each block of data needs to be 32 bit aligned
 +
* Specified that all the segment header members are stored in little endian
 +
* Changed the load address in the segment header structure to 64 bits.
 +
* Clarified the compression of the code / data segments

Latest revision as of 22:20, 15 May 2008

SELF stands for Simple Executable Loader Format. It is a very simple take on the standard [ELF] executable format. It is proposed that SELF be the the standard format for payload code stored in a LAR file and loaded and executed by coreboot-v3. The bayou chooser will also load and run payloads in the SELF format.

Description

Each SELF file is defined as a group of different segments. Each segment either loads data into memory, zeroes a section of memory, or provides information to coreboot or the payload. The segments can be one of the following types:

ID Segment Description
'CODE' (0x45444F43) CODE This segment has executable code to be copied from the data section to memory. Each CODE segment has a corresponding block of data, which may be compressed in the LAR. Multiple segments of this type are allowed.
'DATA' (0x41543144) DATA This segment has non-executable data to be copied from the data section into memory. Each DATA segment has a corresponding block of data, which may be compressed in the LAR. Multiple segments of this type are allowed.
'BSS ' (0x20535342) BSS This segment defines a section of memory to be zeroed. BSS segments do not have any data associated with them. Multiple segments of this type are allowed.
'PARA' (0x41524150) PARAMS This segment contains the contents of the .notes.pinfo section from the payload ELF. The payload will store parameters in this section for the benefit of a chooser payload. The parameters will be stored as a series of strings of the format "key=value\0".
'ENTR' (0x52544E45) ENTRY This segment defines the entry point for execution. This type signifies the end of the list of segments, and it must be the last segment defined in the SELF. It is mandatory and can only be used once.

Format

A SELF file is comprised of two parts: the segment table and the data section. Each is described below.

Segment Table

The segment table is located at the start of the ELF file, with one entry per segement. Each segment is identified by its type (as listed above). The structure of the header entry is as follows:

struct self_header {
    unsigned long type;
    unsigned long offset;
    unsigned long long load_addr;
    unsigned long len;
    unsigned long mem_len;
};

All fields are present in each segment entry, though not every field will be valid for every segment type. The value of each field will be stored in little endian format. Big endian architectures will need to byte swap the value before using it. The following table lists which members are used and what they mean:

Type offset load_addr len mem_len
CODE Offset of the segment in the SELF file address where the code should be copied in memory length of the data in the segment data section length of the data in memory
DATA Offset of the segment in the SELF file address where the code should be copied in memory length of the data in the segment data section length of the data in memory
BSS N/A Start address of the block in memory to be zeroed N/A Length of the block in memory to be zeroed
PARAM Offset of the segment in the SELF file N/A length of the data in the segment data section N/A
ENTRY N/A Address where execution should start N/A N/A

Segment Section

The data section immediately follows the final entry in the segment table. Each block of segment data is written sequentially in this section, with the start of each block aligned to a 32 bit boundary. CODE and DATA sections may be compressed according to the LAR compression scheme, the PARAM section must be uncompressed.

Typical Use

The following pseudo code shows how a SELF is loaded and run:

decompress_and_run(void) {
  ptr = SELF_start;

  while(1) {
    header = (struct self_header *) ptr;
    switch(header->type) {
       case TYPE_CODE:
       case TYPE_DATA:
           dlen = decompress(SELF_start + header->offset, header->load_addr, header->len);
           memset(header->load_addr + dlen, 0, header->mem_len - dlen);
           break;
       case BSS:
            memset(header->load_addr, 0, header->len);
            break;
       case LOAD:
            return jump_to(header->load_addr);
    }
    
    ptr += sizeof(*header);
  }
}

Changelog

  • Replace the NAME and NOTE sections with the PARAMS section
  • Change ID of each segment to 4 text characters
  • Each block of data needs to be 32 bit aligned
  • Specified that all the segment header members are stored in little endian
  • Changed the load address in the segment header structure to 64 bits.
  • Clarified the compression of the code / data segments