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:
_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:
{
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:
{
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!
Hi Hamo,
Thanks for the update. I look forward to reading about your progress. I hope your exams have gone well.
Marc