GSoC2011(Week 5): the layout of coreboot rom and cbfstool for ARM

Hi all. How time flies. It has been 4 weeks since my last post. During this month, I have finished the design and implement of bootblock, Rom structure and cbfstool for ARM. Following I will show my changes to you all.

1. bootblock

This startup code is mainly borrowed from U-boot but changed for our use. From 0x0 to 0x1c are the interrupt vectors. I put the CBFS master header at 0x20. All the members of this structure will be re-wrote by the cbfstool so we put 0xFFFFFFFF here. Since the master header is at a fixed address, we don’t need to save the pointer of master header. This code shows like this:

.globl _start
_start:
    b    reset

    /*
     * we do not use interrupt during boot-up,
     * payload should set their own interrupt vectors.
     */
    b     hang
    b    hang
    b    hang
    b    hang
    b    hang
    b    hang
    b    hang

HEADER:
MAGIC:
    .word     0xFFFFFFFF
VER:
    .word     0xFFFFFFFF
ROMSIZE:
    .word     0xFFFFFFFF
BOOTBLOCKSIZE:
    .word     0xFFFFFFFF
ALIGN:
    .word     0xFFFFFFFF
OFFSET:
    .word     0xFFFFFFFF
ARCH:
    .word     0xFFFFFFFF
PAD:
    .word     0xFFFFFFFF

reset is the actually code we init the CPU. It sets the CPU to SVC32 mode, flush the I/D caches and disable MMU and caches. Then it goes to the board-specific code to init the RAM. After this, the RAM is ready to be used.

Then it comes to walkcbfs_asm. This function does the same thing as for X86. Since for ARM, the boot Rom is not mapped to a fixed address. So we need to use the board-specific ROMBASE to address the CBFS master header. After it finds the romstage, we can pass control to it now. Since we don’t have romcc for ARM, all the code above is written in asm.

2. ROM structure

/---------------\ <-- Start of ROM
| /-----------\ |
| | Reset     | | <- 0x0
| |-----------| |
| |IVs        | |
| |-----------| |<- 0x20
| |  master   | |
| |  header   | |
| |-----------| |
| |Boot       | |
| |Block      | |
| \-----------/ |
|               |
| /-----------\ | --|
| | Header    | |   |
| |-----------| |   |
| | Name      | |   |
| |-----------| |   |-- Component
| |Data       | |   |
| |..         | |   |
| \-----------/ | --|
|               |
| ...           |
| /-----------\ | --|
| | Header    | |   |
| |-----------| |   |
| | Name      | |   |
| |-----------| |   |-- Component
| |Data       | |   |
| |..         | |   |
| \-----------/ | --|
\---------------/

Bootblock sets the CPU to a certain status and inits the RAM on board, then it passes control to romstage.
Romstage uses the RAM as a temporary stack to continue initing the board. Then it finds the ramstage, decompress it and copy it to the RAM. After this, it passes control to the ramstage.
Ramstage shows the information of coreboot, enumerates, configures and initializes the PCI devices(if have), then passes control to the payload.

3. cbfstool

Thanks to Stefan, he gave me a hand on how to implement this.
I added a member named architecture to CBFS master header. It is used by the cbfstool to detect the architecture of a rom file.
First, when we create a rom file using bootblock, we need to tell cbfstool the architecture we want to use, since this will result in a different layout of romfile. This is done by switch the arch option and do different things.
Second, when we load a romfile, we need to detect a file’s architecture since they have different layouts. This is done by the auto_detect_architecture function called by loadrom showing as follows:

static void auto_detect_architecture(void *romarea)
{
    struct cbfs_header *master_header;
    uint32_t *header_ptr;

    /* First, Let's try arm. */
    do {
        arch = ARCH_ARM;
        // Set up physical/virtual mapping because we need to access the master header.
        offset = romarea;
        master_header = (struct cbfs_header *)phys_to_virt(0x20);
        if((void *)master_header < romarea ||
           (void *)master_header >= (romarea + romsize - sizeof(struct cbfs_header)))
            break;
        if(master_header->magic == ntohl(0x4F524243) &&
           master_header->architecture == ntohl(CBFS_ARCHITECTURE_ARM))
            return;
    } while(0);

    /* Now, Let's try x86. */
    do {
        arch = ARCH_X86;
        // Set up physical/virtual mapping because we need to access the master header.
        offset = romarea + romsize - 0x100000000ULL;
        header_ptr = (uint32_t *)phys_to_virt(0xfffffffc);
        if((void *)header_ptr < romarea ||
           (void *)header_ptr >= (romarea + romsize))
            break;
        master_header = (struct cbfs_header *)phys_to_virt(*header_ptr);
        if((void *)master_header < romarea ||
           (void *)master_header >= (romarea + romsize - sizeof(struct cbfs_header)))
            break;
        if(master_header->magic == ntohl(0x4F524243) &&
           master_header->architecture == ntohl(CBFS_ARCHITECTURE_X86))
            return;
    } while(0);

    /* Fallback to ARCH_NONE */
    arch = ARCH_NONE;
    return;
}

It will set the arch variable and this variable will be used by the function recalculate_rom_geometry showing as follows:

void recalculate_rom_geometry(void *romarea)
{
    switch (arch) {
    case ARCH_ARM:
        offset = romarea;
        master_header = (struct cbfs_header *)
            phys_to_virt(0x20);
        phys_start = (0 + ntohl(master_header->offset)) & 0xffffffff;
        phys_end = romsize  & 0xffffffff;
        break;
    case ARCH_X86:
        offset = romarea + romsize - 0x100000000ULL;
        master_header = (struct cbfs_header *)
            phys_to_virt(*((uint32_t *) phys_to_virt(0xfffffffc)));
        phys_start = (0 - romsize + ntohl(master_header->offset)) & 0xffffffff;
        phys_end =
            (0 - ntohl(master_header->bootblocksize) -
             sizeof(struct cbfs_header)) & 0xffffffff;
        break;
    default:
        printf("Unknown architecture\n");
        exit(1);
    }
    align = ntohl(master_header->align);
}

Thanks to the cbfstool programmers, you have done such a great job that I only need to do a few changes to support a new architecture.

In the next weeks, I will go on doing the porting including writing the romstage and ramstage, finding a new development board to work with and so on. Hope you all enjoy my post and Have a nice summer.
Thanks to Lord and thanks to you all!

One thought on “GSoC2011(Week 5): the layout of coreboot rom and cbfstool for ARM”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>