cbfstool fails: "Selected image region is not a valid CBFS."

586 views
Skip to first unread message

Michael Witten

unread,
Dec 28, 2020, 2:40:48 PM12/28/20
to chromiu...@chromium.org
I'm running the proprietary ChromeOS in "Developer Mode" on
a Chromebook laptop that was built in 2016.

It would appear that `flashrom` or `cbfstool` may be failing
to do what the documentation says it should do.

Consider this documentation:

https://chromium.googlesource.com/chromiumos/docs/+/51293c61c9cd09e4a55b698a22eae28f4ea2d703/developer_mode.md#alt-firmware

It instructs one to run:

flashrom -r /tmp/bios.bin
cbfstool /tmp/bios.bin print -r RW_LEGACY

Firstly, I had to use `sudo` and a full path for `flashrom`:

sudo /usr/sbin/flashrom -r /tmp/bios.bin

In particular:

$ sudo /usr/sbin/flashrom -r /tmp/bios.bin
flashrom 0.9.9 : a5cb316d : Nov 13 2020 18:00:28 UTC on Linux 4.4.237-19358-g17705661373a (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using default programmer "internal" with arguments "".
Calibrating delay loop... OK.
coreboot table found at 0x7ae6e000.
Found chipset "Intel Bay Trail".
Enabling flash write... Warning: Setting BIOS Control at 0x0 from 0x0b to 0x09 failed.
New value is 0x0b.
SPI Configuration is locked down.
FREG0: Flash Descriptor region (0x00000000-0x00000fff) is read-only.
FREG2: Management Engine region (0x00001000-0x001fffff) is locked.
Not all flash regions are freely accessible by flashrom. This is most likely
due to an active ME. Please see https://flashrom.org/ME for details.
At least some flash regions are read protected. You have to use a flash
layout and include only accessible regions. For write operations, you'll
additionally need the --noverify-all switch. See manpage for more details.
OK.
Found Winbond flash chip "W25Q64.W" (8192 kB, SPI) mapped at physical address 0x00000000ff800000.
Block protection could not be disabled!
Reading flash... SUCCESS

Secondly, `cbfstool` appears to reject the results:

$ cbfstool /tmp/bios.bin print -r RW_LEGACY
E: Selected image region is not a valid CBFS.
E: Failed while operating on 'RW_LEGACY' region!
E: The image will be left unmodified.

Running it via `sudo` makes no difference.

Is that the intended output?
If not, what am I doing wrong?

Thanks for your help.

Sincerely,
Michael Witten

Mike Frysinger

unread,
Dec 28, 2020, 4:10:15 PM12/28/20
to Michael Witten, chromium-os-dev
not all devices are the same.  what one exactly are you using ?  you can find the list here:

--
--
Chromium OS Developers mailing list: chromiu...@chromium.org
View archives, change email options, or unsubscribe:
https://groups.google.com/a/chromium.org/group/chromium-os-dev

Michael Witten

unread,
Dec 28, 2020, 9:55:30 PM12/28/20
to Mike Frysinger, chromiu...@chromium.org
I'm using this:

Acer CB3-131

That's not in the list you provided, but I did find there this close cousin:

Acer CB3-531

In any case, these possibilities seem plausible:

* The RW_LEGACY region has garbage in it. (most likely)
* Something is wrong with my system.
* Something is wrong with the tools. (least likely)

It appears that RW_LEGACY might be simply filled with 1 bits:

$ #!/bin/bash
$ cbfstool /tmp/bios.bin read -r RW_LEGACY -f >(od -t x1); sleep 1
0000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
*
10000000

If the RW_LEGACY region simply has garbage in it, then I suppose I can
safely write something to it. However, it would be nice to have this
confirmed before I go twiddling the bits of the firmware; I don't want
to trigger something from which I cannot recover.

Any suggestions?

Sincerely,
Michael Witten

dragon788

unread,
Dec 29, 2020, 12:35:52 AM12/29/20
to Michael Witten, Mike Frysinger, Chromium OS Development
Some devices have dummy data there, if a functional firmware has been created for RW_LEGACY for your device you could try the MrChromebox.tech script to install it.

--
--
Chromium OS Developers mailing list: chromiu...@chromium.org
View archives, change email options, or unsubscribe:
https://groups.google.com/a/chromium.org/group/chromium-os-dev
---
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-os-d...@chromium.org.

ggg

unread,
Dec 29, 2020, 12:46:40 PM12/29/20
to Chromium OS Development, Michael Witten, chromiu...@chromium.org, Mike Frysinger
On Tuesday, December 29, 2020 at 2:55:30 AM UTC Michael Witten wrote:
I'm using this:

Acer CB3-131

That's not in the list you provided, but I did find there this close cousin:

Acer CB3-531

They are both Baytrail SoC - so likely running the same FW too.

To identify which board this is, run any one of these in developer mode:
o "dmesg | fgrep DMI:"
o "dmidecode -s baseboard-product-name"
o "crossystem hwid" (or fwid)

cheers,
grant

Michael Witten

unread,
Jan 8, 2021, 4:40:21 PM1/8/21
to drag...@gmail.com, ggg, Mike Frysinger, chromiu...@chromium.org

This email provides the foll­ow­ing sec­tions below:

  • System Info

    This identifies the Chr­ome­OS sys­tem I have; it’s main­ly use­ful to help us­ers find this e­mail.

  • Using RW_LEGACY

    This is a kind of tu­tor­i­al that shows oth­ers how to fix and use the RW_LEGACY reg­i­on by means of their own know­led­ge and tools.

  • Firmware Code Paths

    This documents the rel­ev­ant code in the firm­ware of my com­pu­t­er; it is bas­ed on a rea­d­ing of the sour­ce code.

I hope it’s useful to someone else.

Sincerely,
Michael Witten

                                                                       

System Info

Grant (“ggg”) wrote:

I’m using this:

Acer CB3-131

That’s not in the list you pro­v­id­ed, but I did find there this close cous­in:

Acer CB3-531

They are both Bay­trail SoC - so like­ly run­n­ing the same FW too.

To identify which board this is, run any one of these in dev­el­o­p­er mode:

  • dmesg | fgrep DMI:
  • dmidecode -s baseboard-product-name
  • crossystem hwid" (or fwid)

Here’s my output:

dmesg | fgrep DMI:
[    0.000000] DMI: GOOGLE Gnawty, BIOS Google_Gnawty.5216.239.156 12/03/2017
sudo /usr/sbin/dmidecode -s baseboard-product-name
echo $?
0
sudo /usr/sbin/dmidecode | sed -ne '/^BIOS/,/Family:/p; /Family:/q'
BIOS Information
    Vendor: coreboot
    Version: Google_Gnawty.5216.239.156
    Release Date: 12/03/2017
    ROM Size: 8192 kB
    Characteristics:
        PCI is supported
        PC Card (PCMCIA) is supported
        BIOS is upgradeable
        Selectable boot is supported
        ACPI is supported
        Targeted content distribution is supported
    BIOS Revision: 4.0
    Firmware Revision: 0.0

Handle 0x0001, DMI type 1, 27 bytes
System Information
    Manufacturer: GOOGLE
    Product Name: Gnawty
    Version: 1.0
    Serial Number: 123456789
    UUID: Not Settable
    Wake-up Type: Reserved
    SKU Number: Not Specified
    Family: Not Specified

This is the im­por­t­ant info:

Version Google_Gnawty.5216.239.156
Release Date 12/03/2017

I will add the foll­ow­ing in­ter­es­t­ing bit of in­for­m­ation:

crossystem ro_fwid; echo
Google_Gnawty.5216.239.34

If that last num­ber (34) is the “build” num­ber, then it can be seen that there have been quite a few it­er­at­ions be­tween these 2 times:

  • The time my com­pu­t­er sys­tem was man­u­fac­t­ur­ed.

  • The time the mod­i­f­i­able firm­ware was last up­dat­ed (to build num­ber 156).

Using RW_LEGACY

dragon788 wrote:

Some devices have dum­my data there, if a func­tio­n­al firm­ware has been cr­eat­ed for RW_LEGACY for your dev­ice you could try the Mr­Chr­ome­box.tech scr­ipt to in­stall it.

The flash storage has a reg­ion nam­ed “RW_LEGACY”, which is use­ful for run­n­ing one’s own soft­ware dur­ing the ear­ly pro­c­ess of boo­t­ing a Chr­ome­OS sys­tem that is run­n­ing in Dev­el­o­p­er Mode.

Unfortunately, in my sys­tem (and ap­p­ar­ent­ly many sim­i­l­ar sys­tems of its gen­er­at­ion), the RW_LEGACY reg­i­on was not pre­p­ar­ed for easy use; in fact, all of its bits were set to the val­ue 1.

This section explains the steps you can take to fix it:

  1. Put ChromeOS in Developer Mode.
  2. Open a shell command-line prompt.
  3. Create an old-style CBFS in RW_LEGACY.
  4. Get a program of your choice.
  5. Add the program to the CBFS as the “payload”.
  6. Write the data to the flash storage.
  7. Permit the firmware to run that payload.
  8. Reboot the computer.
  9. Press [ctrl][l] (L) to run the program.
  10. ???
  11. Profit!
0. Put ChromeOS in Developer Mode

The instructions are given here. In par­tic­u­lar:

  • Enter Recovery Mode by press­ing the foll­ow­ing on the key­board:

    [esc][⟳][⏻] ([esc][refresh][power])
  • Next, enter Dev­el­o­p­er Mode by press­ing the foll­ow­ing on the key­board:

    [ctrl][d]
    [enter]

1. Open a shell command-line prompt

The instructions are given here or here. In par­tic­u­lar:

  • Log into your acc­ount.

  • Press the follow­ing on the key­board:

    [ctrl][alt][t]

  • Type “shell” at the prompt, and then press:

    [enter]

2. Create an old-style CBFS in RW_LEGACY

At a shell comm­and-line prompt, run the foll­ow­ing comm­ands (the “$ ” at the be­gin­n­ing of a line in­dic­at­es the prompt).

Create a di­r­ec­t­ory to work in:

mkdir /tmp/flash && cd /tmp/flash

Grab a copy of what’s stor­ed in the flash stor­age:

sudo /usr/sbin/flashrom -r ./00-flashrom
flashrom 0.9.9 : a5cb316d : Nov 13 2020 18:00:28 UTC on Linux 4.4.237-19358-g17705661373a (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using default programmer "internal" with arguments "".
Calibrating delay loop... OK.
coreboot table found at 0x7ae6e000.
Found chipset "Intel Bay Trail".
Enabling flash write... Warning: Setting BIOS Control at 0x0 from 0x0b to 0x09 failed.
New value is 0x0b.
SPI Configuration is locked down.
FREG0: Flash Descriptor region (0x00000000-0x00000fff) is read-only.
FREG2: Management Engine region (0x00001000-0x001fffff) is locked.
Not all flash regions are freely accessible by flashrom. This is most likely due to an active ME. Please see https://flashrom.org/ME for details. At least some flash regions are read protected. You have to use a flash layout and include only accessible regions. For write operations, you'll additionally need the --noverify-all switch. See manpage for more details.
OK.
Found Winbond flash chip "W25Q64.W" (8192 kB, SPI) mapped at physical address 0x00000000ff800000.
Block protection could not be disabled!
Reading flash... SUCCESS

Change the ownership of the resulting file:

sudo chown chronos:chronos ./00-flashrom

Get the size of the RW_LEGACY region:

cbfstool ./00-flashrom layout | grep RW_LEGACY
'RW_LEGACY' (CBFS, size 2097152, offset 4194304)

Create a fresh old-style CBFS of the same size:

cbfstool ./01-empty-cbfs create -m x86 -s 2097152
Created CBFS (capacity = 2097048 bytes)

Overwrite the RW_LEGACY reg­i­on with this emp­ty CBFS:

cbfstool ./00-flashrom write -F -r RW_LEGACY -f ./01-empty-cbfs

Ensure that RW_LEGACY now con­tains an emp­ty CBFS:

cbfstool ./00-flashrom print -r RW_LEGACY
FMAP REGION: RW_LEGACY
Name Offset Type Size Comp
(empty) 0x0 null 2097048 none

Now that RW_LEGACY con­tains an old-style CBFS, it can be man­ip­u­l­at­ed as in­ten­d­ed by all the us­u­al com­m­ands.

3. Get a program of your choice

You can place into RW_LEGACY’s CBFS any pro­gram you want to run when boo­t­ing up your com­pu­t­er. For ex­ample, here is a sim­ple pro­gram com­pos­ed of thr­ee x86 in­struc­tions:

printf '\xfa\xf4\xeb\xfd' > ./02-program

That little 4-byte pro­gram does the foll­ow­ing:

It turns off in­t­er­r­upts. (0xfa : cli )
It halts the log­i­c­al pro­cess­or. (0xf4 : hlt )
It jumps back to hlt if the pro­cess­ing is trig­g­er­ed ag­ain by some in­t­er­r­upt sig­n­al that can­n­ot be ig­nor­ed. (0xeb 0xfd : jmp -3 )

If you have a dis­as­sem­bl­er handy, you can view these facts for your­self; for in­stan­ce, you can use the objdump tool from the bin­utils pro­j­ect:

objdump --disassemble-all --target=binary --architecture=i386 ./02-program | sed -ne '/0:/,$p'
0:   fa      cli
1:   f4      hlt
2:   eb fd   jmp 0x1

The disassembler has cho­s­en to in­t­er­p­ret “eb fd” as:

jump to address 1

However, that’s not strict­ly cor­r­ect; they ac­t­u­al­ly mean:

jump back 3 bytes

Anyway, when this pro­gram is run, it shou­ld bas­ic­al­ly en­sure that your com­pu­t­er does ab­so­l­u­te­ly noth­ing in­t­er­es­t­ing; it sh­ou­ld just sit there qui­et­ly.

Therefore, it might be a good idea to find a more use­ful pro­gram some­where else; a com­m­on choi­ce is Sea­BIOS, an open-source imp­lem­en­tat­ion of the BIOS soft­ware that was tra­d­it­i­o­n­al­ly us­ed to boot a PC.

4. Add the pro­gram to the CBFS as the “payload”

A component in the CBFS is es­sen­tial­ly a file in a file sys­tem.

When this com­pu­t­er turns on, it runs a piece of soft­ware known as “the firm­ware”, which is stor­ed in a flash stor­age chip. In this com­pu­t­er, this par­tic­u­lar ver­sion of the firm­ware can be told to run some soft­ware from the RW_LEGACY re­g­i­on of the flash stor­age; the firm­ware looks for a com­po­n­ent nam­ed “payload" in the CBFS that is stor­ed in the RW_LEGACY re­g­i­on.

This “payload” com­po­n­ent can­n­ot be just the raw in­struc­tions of the pro­gram; the in­struc­tions must be en­cod­ed in a for­mat known as the “Sim­ple Ex­ec­u­t­able Loa­d­er For­mat” (“Sim­ple ELF” or “SELF”), which is a var­i­at­ion of “ELF” (the “Ex­ec­u­t­able and Link­able For­mat”), which is a com­m­on for­mat for ex­ec­u­t­ables on Lin­ux sys­tems.

The SELF en­co­d­ing pro­v­id­es the firm­ware with 2 very im­por­t­ant piec­es of in­for­m­at­ion:

Load Address The lo­c­at­ion in mem­ory where the pro­gram shou­ld be plac­ed.
Entry Address The lo­c­at­ion in mem­ory where the in­iti­al in­struc­tion of the pro­gram can be found, after the whole pro­gram is plac­ed at the Load Address.

At the time the pro­gram is loa­d­ed, the CPU has been put in 32-bit Pro­tec­t­ed Mode, and thus the pro­gram can be plac­ed any­where in mem­ory. For ex­am­ple, it can be loa­d­ed 256 MiB into mem­ory, at the foll­ow­ing ad­dress:

Load Address = 256 * 1024 * 1024
  = 268435456
  = 0x10000000

If the pro­gram is sim­ple en­ough, then the in­it­i­al in­struc­tion of the pro­gram can be lo­c­at­ed at that very same ad­dress:

Entry Address = Load Address
  = 0x10000000

Fortunately, all of these de­tails can be handl­ed by one com­m­and:

cbfstool ./00-flashrom add-flat-binary -r RW_LEGACY -f ./02-program -n payload -l 0x10000000 -e 0x10000000
W: Compression failed or would make the data bigger - disabled.

As you can see, cbfstool tries to com­press the pro­gram, but de­c­id­es that this is point­less; the war­n­ing is of no con­seq­uen­ce.

Confirm that the pro­gram is in its prop­er place:

cbfstool ./00-flashrom print -r RW_LEGACY
FMAP REGION: RW_LEGACY
Name Offset Type Size Comp
payload 0x0 simple elf 60 none
(empty) 0x80 null 2096920 none

The “payload” com­po­n­ent is lo­c­at­ed at the very top of the CBFS (at off­set 0); the com­po­n­ent is a “simple elf”; it’s size is “60” bytes; and its com­press­ion is “none”, mean­ing that it has not been com­press­ed, just as cbfstool warn­ed us.

Now, a little trick:

(Skip this un­less you are feel­ing play­ful)

The SELF pay­load can be ex­trac­t­ed:

cbfstool ./00-flashrom extract -r RW_LEGACY -n payload -m x86 -f ./03-payload
Found file payload at 0x0, type simple elf, compressed 60, size 60

Notice, though, that the ex­trac­t­ed file is quite a bit lar­g­er than 60 bytes:

du -h ./03-payload
12K     ./03-payload

The reason for this is that cbfstool pack­ag­es the pay­load as a full ELF pro­gram, mean­ing that the ex­trac­t­ed pro­gram is in fact a pro­gram that Linux would be hap­py to run.

That is one reason why the Load Ad­dr­ess was del­ib­er­ate­ly cho­s­en to have these prop­er­ties:

  • It is aligned to 4096 bytes (the mem­ory page size that Linux likes).

  • It is rel­at­ive­ly high up there in the ad­dr­ess space, so Linux won’t com­plain about per­m­iss­ions.

In order to run this pro­gram, it must be mark­ed as ex­ec­u­t­able:

chmod u+x ./03-payload

Also, by default, Chr­ome­OS does not all­ow ex­ec­u­t­ing pro­grams that are lo­c­at­ed in the /tmp di­r­ec­t­ory; for sec­ur­ity, the file sys­tem lo­c­at­ed there has been moun­t­ed with­out the nec­es­s­ary per­m­iss­ion. Thus, the /tmp mount point must be re­mount­ed with the prop­er “exec” op­tion:

sudo mount -o remount,exec /tmp

Now, run the pro­gram:

$ ./03-payload
Segmentation fault (core dumped)

Woops! The kernel will have re­p­or­t­ed the prob­lem:

dmesg | grep 03-payload
[ 7906.089053] traps: 03-payload[4678] general protection ip:10000000 sp:ff915c30 error:0 in 03-payload[10000000+1000]

The CPU rais­ed the “gen­er­al pro­tec­tion” ex­cep­tion when it was told to run the “cli” in­struc­tion; that’s be­cause the priv­il­ege lev­el is not suf­fic­i­ent to run the “cli” in­struc­tion. Even if the CPU could have gott­en past the “cli” in­struc­tion, the “hlt” in­struc­tion re­quir­es the high­est hard­ware-lev­el priv­il­ege; this pro­gram can­not be run in “user space”.

However, you could try all this ag­ain with an al­t­er­n­at­ive pro­gram that does not re­q­ui­re these priv­il­eg­ed in­struc­tions. For ex­am­ple, con­sid­er this pro­gram in­stead:

printf '\x04\x01\xeb\xfc' > ./04-program

That program simp­ly keeps ad­d­ing 1 to the “AL” reg­is­ter:

objdump --disassemble-all --target=binary --architecture=i386 ./04-program | sed -ne '/0:/,$p'
0:   04 01   add $0x1,%al
2:   eb fc   jmp 0x0

Remove the exis­t­ing pay­load:

cbfstool ./00-flashrom remove -r RW_LEGACY -n payload

Add the new pro­gram:

cbfstool ./00-flashrom add-flat-binary -r RW_LEGACY -f ./04-program -n payload -l 0x10000000 -e 0x10000000
W: Compression failed or would make the data bigger - disabled.

Extract the pay­load:

cbfstool ./00-flashrom extract -r RW_LEGACY -n payload -m x86 -f ./05-payload
Found file payload at 0x0, type simple elf, compressed 60, size 60

Marked it as ex­ec­u­t­able:

chmod u+x ./05-payload

Run it:

$ ./05-payload

Your CPU will be pegg­ed to 100% as it fur­i­ous­ly in­crem­ents the AL reg­i­s­ter; kill the pro­gram by ty­p­ing:

[ctrl][c]

You can run it in the back­ground, and then use the top com­m­and to see the vig­or with which that pro­gram per­forms ar­ith­met­ic:

$ ./05-payload &
[1] 5204
$ top

You should see some lines like this in top:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5182 chronos 20 0 152 4 0 R 77.5 0.0 0:10.09 05-payload

Press [q] or [ctrl][c] to quit top, and then for the sake of your com­pu­t­er, plea­se kill the pay­load pro­gram:

$ pkill 05-payload
[1]+  Terminated    ./05-payload

At this point, you’d better put the more res­pec­t­able pro­gram back in place:

cbfstool ./00-flashrom remove -r RW_LEGACY -n payload
cbfstool ./00-flashrom add-flat-binary -r RW_LEGACY -f ./02-program -n payload -l 0x10000000 -e 0x10000000
W: Compression failed or would make the data bigger - disabled.
5. Write the data to the flash storage

Currently, you’ve been man­ip­u­l­at­ing only your copy of the data that are in the flash stor­age; you need to write your copy of the data to the flash stor­age itself. Spec­if­ic­al­ly, you need to ov­er­write the RW_LEGACY re­g­ion:

sudo /usr/sbin/flashrom -w ./00-flashrom -i RW_LEGACY
flashrom 0.9.9 : a5cb316d : Nov 13 2020 18:00:28 UTC on Linux 4.4.237-19358-g17705661373a (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using default programmer "internal" with arguments "".
Calibrating delay loop... OK.
coreboot table found at 0x7ae6e000.
Found chipset "Intel Bay Trail".
Enabling flash write... Warning: Setting BIOS Control at 0x0 from 0x0b to 0x09 failed.
New value is 0x0b.
SPI Configuration is locked down.
FREG0: Flash Descriptor region (0x00000000-0x00000fff) is read-only.
FREG2: Management Engine region (0x00001000-0x001fffff) is locked.
Not all flash regions are freely accessible by flashrom. This is most likely due to an active ME. Please see https://flashrom.org/ME for details. At least some flash regions are read protected. You have to use a flash layout and include only accessible regions. For write operations, you'll additionally need the --noverify-all switch. See manpage for more details.
OK.
Found Winbond flash chip "W25Q64.W" (8192 kB, SPI) mapped at physical address 0x00000000ff800000.
Block protection could not be disabled!
spi_write_cmd failed during command execution at address 0x0
spi_simple_write_cmd failed during command execution
spi_simple_write_cmd failed during command execution
Erasing and writing flash chip... Verifying flash... VERIFIED.
SUCCESS
6. Permit the firmware to run that payload

The firmware must be gran­t­ed per­m­iss­ion to load and run the pro­gram from the RW_LEGACY re­g­i­on of the flash stor­age; per­miss­ion is gran­t­ed by set­t­ing the foll­ow­ing flag:

dev_boot_legacy

If that flag is set to “0”, then the firm­ware has not yet been gran­t­ed per­miss­ion:

sudo crossystem dev_boot_legacy; echo
0

In that case, set it to “1”:

sudo crossystem dev_boot_legacy=1

Check that the flag is prop­er­ly set:

sudo crossystem dev_boot_legacy; echo
1
7. Reboot the computer

Turn it off. Turn it back on.

8. Press [ctrl][l] (L) to run the program

When in Developer Mode, the firm­ware will boot to a warn­ing scr­een; you can press the foll­ow­ing keys on the key­board to load and run the pro­gram from the RW_LEGACY re­g­i­on:

[ctrl][l] (L)

If there is a prob­lem loa­d­ing the pro­gram, the firm­ware will beep twice at you. Oth­er­wise, the pro­gram will be run.

In the case of the little pro­gram in­stall­ed ab­ove, your com­pu­t­er shou­ld es­s­en­t­ial­ly just free­ze; there will be no beeps, and most oth­er in­put (e.g., from the key­board) will have no eff­ect.

Press the power but­ton on the key­board to turn the mach­ine off, and then sit back in your chair, look out the win­dow, and won­der to your­self “What am I do­ing with my life? Ser­ious­ly. What am I doing?

9. ???

A great time to think ab­out the poss­ib­il­it­ies is while show­er­ing. Make sure you keep the water hot, and use high-qual­ity, sen­s­u­al soaps.

10. Profit!

Please share some of your gains with a wor­thy com­pu­t­ing pro­j­ect.

Firmware Code Paths

I found these pri­m­ary doc­u­ments use­ful in get­t­ing a quick ov­er­view of how the firm­ware op­er­at­es:

These source code repositories provided details:

In short:

  • At power-on, the “RO” firm­ware runs; it loads, ver­if­ies, and runs some “RW” firm­ware.

  • The RW firm­ware in­i­tial­iz­es the hard­ware and then runs a “pay­load” call­ed “Depth­char­ge”.

  • In Developer Mode, Depth­char­ge waits for the user to tell it what to do; if things were con­fig­ur­ed to allow the user to do so, the user may press [ctrl][l] (L) on the key­board to run the pro­gram stor­ed in the “RW_LEGACY” re­g­i­on (or area) of the flash stor­age.

In more detail:

  • At power-on, a Chrome­OS “device” (by which Goo­gle means “com­pu­ter”) runs the read-only (RO) firm­ware; this RO firm­ware is bas­ic­al­ly meant to be nev­er alt­er­ed for the life of the com­pu­t­er (though it can be ov­er­writ­t­en if the com­pu­t­er is mech­an­ic­al­ly man­ip­u­l­at­ed to allow do­ing so, there­by voi­d­ing any warr­an­ty).

  • The RO firm­ware ver­if­ies that one of the 2 read-write (RW; up­dat­able) firm­ware imag­es is cryp­to­graph­ic­al­ly sign­ed by Goo­gle; if so, the RO firm­ware runs the cho­s­en RW firm­ware.

  • The RW firm­ware image con­sti­t­ut­es a core­boot “file sys­tem” (CBFS); the core­boot soft­ware in­itial­iz­es the hard­ware, and then loads a pay­load from the CBFS and runs it.

  • The pay­load in ques­tion is Goo­gle’s “Depth­charge” soft­ware, which is des­ign­ed to load, poss­ib­ly ver­ify, and then run one of 2 Linux kern­els that are stor­ed in the com­pu­t­er’s non-vol­at­ile stor­age. Under nor­m­al cir­cum­stan­c­es, Depth­char­ge ver­i­f­ies that the kern­el is cryp­to­graph­ic­al­ly sign­ed by Goo­gle and then runs it; how­ev­er, when a Chr­ome­OS sys­tem is con­fig­ur­ed to run in “Dev­el­o­p­er Mode”, Depth­char­ge paus­es the boo­t­ing pro­c­ess to seek in­t­er­ac­tion from the user of the com­pu­t­er.

  • In Developer Mode, Depth­char­ge dis­plays some in­for­m­at­ion on the scr­een and then waits for user in­put to de­cide what to load and run; or, after a time­out, a kern­el is loa­d­ed as us­u­al.

    • If the user presses [ctrl][d] on the key­board, Depth­char­ge loads and runs the kern­el as us­u­al, though ver­i­f­ic­ation of the kern­el may not be per­for­m­ed if the following flag is set to 0:

      dev_boot_signed_only

    • If there is no user in­put with­in a cer­tain am­ount of time, then Depth­char­ge be­hav­es as though the user press­ed [ctrl][d] on the key­board.

    • If the user presses [ctrl][l] (L) on the key­board, and the flag to allow “legacy” boo­t­ing is set (i.e., the flag dev_boot_legacy must be non-zero), then Depth­char­ge loads a pro­gram from the flash stor­age, and runs it.

      • The flash storage has its data laid out in re­g­i­ons (or areas) de­scr­ib­ed by an “FMAP” data str­uc­t­ure.

        The program in ques­t­ion is stor­ed in the “RW_LEGACY” re­g­i­on of the flash stor­age: The data in the RW_LEGACY re­g­i­on con­sti­t­ute a CBFS data str­uc­t­ure; at least one “com­po­n­ent” of the CBFS data str­uc­t­ure con­sti­t­ut­es the pro­gram. In the case of my com­pu­t­er’s off­ic­i­al firm­ware, the pro­gram must be lo­c­at­ed in the com­po­n­ent nam­ed “payload”.

        The program is en­co­d­ed in the “Sim­ple Ex­ec­u­t­able Loa­d­er For­mat” (“Sim­ple ELF” or “SELF”), which is a var­i­ation of “ELF” (the “Ex­ec­u­t­able and Link­able For­mat”), which is a com­m­on for­mat for ex­ec­u­t­ables on Linux-based op­er­at­ing sys­tems.

The following is the func­tion call se­q­uen­ce when the user suc­ces­ful­ly gets Depth­char­ge to run the pro­gram in the RW_LEGACY re­g­ion:

Software Function Source
Depthcharge main src/vboot/{main.c,rw_main.c}
Depthcharge vboot_select_and_load_kernel src/vboot/stages.c
vboot_fw.a VbSelectAndLoadKernel firmware/lib/vboot_api_kernel.c
vboot_fw.a VbBootDeveloper firmware/lib/vboot_api_kernel.c
Depthcharge VbExLegacy src/vboot/callbacks/legacy.c
Depthcharge load_payload_and_run src/vboot/callbacks/legacy.c
RW_LEGACY *payload_entry WHATEVER YOU WANT!!!111

A particular stic­king point for me was the fact that the CBFS in the RW_LEGACY re­g­i­on is in­ten­d­ed to be the old-style data str­uc­t­ure, which has a mas­ter head­er at the end of it; I had ac­tu­al­ly man­ag­ed to shoe­horn a new-style CBFS into the re­g­i­on, and ev­ery­thing ab­out it wor­k­ed just dan­dy, ex­cept the firm­ware re­f­us­ed to touch it:

Software Function Source
Depthcharge main src/vboot/{main.c,rw_main.c}
Depthcharge vboot_select_and_load_kernel src/vboot/stages.c
vboot_fw.a VbSelectAndLoadKernel firmware/lib/vboot_api_kernel.c
vboot_fw.a VbBootDeveloper firmware/lib/vboot_api_kernel.c
Depthcharge VbExLegacy src/vboot/callbacks/legacy.c
libpayload cbfs_load_payload payloads/libpayload/libcbfs/cbfs.c
libpayload cbfs_get_file_content payloads/libpayload/libcbfs/cbfs_core.c
libpayload cbfs_get_file payloads/libpayload/libcbfs/cbfs_core.c
libpayload cbfs_get_header payloads/libpayload/libcbfs/cbfs_core.c

The following is the point of fail­ure if there is no mas­t­er head­er (spec­if­ic­al­ly, if there is no “magic” str­ing of byt­es to in­di­c­ate the like­ly pres­en­ce of a mas­t­er head­er):

if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
    ERROR("Could not find valid CBFS master header at %x: "
          "%x vs %x.\n", CBFS_HEADER_ROM_ADDRESS, CBFS_HEADER_MAGIC,
          ntohl(header->magic));
    if (header->magic == 0xffffffff) {
        ERROR("Maybe ROM is not mapped properly?\n");
    }
    return CBFS_HEADER_INVALID_ADDRESS;
}

The result is this:

  • cbfs_get_header() returns CBFS_HEADER_INVALID_ADDRESS.

  • cbfs_get_file() returns NULL.

  • cbfs_get_file_content() returns NULL.

  • cbfs_load_payload() returns NULL.

  • VbExLegacy() returns 1.

  • VbBootDeveloper() beeps twice at you and then waits for more in­put (key­board com­bin­ations) from the us­er:

    [...]

    if (allow_legacy)
      VbExLegacy();
    else
      VBDEBUG(("VbBootDeveloper() - "
         "Legacy boot is disabled\n"));

    VbExBeep(120, 400);
    VbExSleepMs(120);
    VbExBeep(120, 400);

    [...]

As an aside, I’ll note that it was not by look­ing at this code that I fig­ur­ed out the prob­lem with using a new-style CBFS (one with­out a mas­t­er head­er); rath­er, I took a sneak peek at Mr­Chome­box’s re­p­os­i­t­ory for the Sea­BIOS code. In that re­p­os­i­t­ory, there is a script that creat­es the CBFS used to store Sea­BIOS in the RW_LEGACY re­g­i­on of a Chr­ome­book bas­ed on a Bay Trail SoC; in par­tic­u­lar, that script creat­es an old-style CBFS:

cbfstool ${filename} create -m x86 -s 0x00200000

It was that single line that made it clear to me that a CBFS with­out a mas­t­er head­er will not work af­t­er all.

Julius Werner

unread,
Jan 8, 2021, 7:20:48 PM1/8/21
to Michael Witten, drag...@gmail.com, ggg, Mike Frysinger, Chromium OS dev
Hi Michael, apologies for not seeing this earlier. I added the documentation you followed not too long ago and it seems that there were still some details to iron out. It sounds like you figured everything out by yourself by now... in fact, your write-up is so good that I hope you don't mind if I just link to it to help the next people trying to figure out this issue. I've proposed an update to the documentation here: https://chromium-review.googlesource.com/c/chromiumos/docs/+/2618653

Note that the RW_LEGACY region always needs to have an "old-style" CBFS, even on current generation Chromebooks. The difference between "old-style" and "new-style" is just the extra presence of the master header... when you already have an empty new style CBFS in RW_LEGACY, you can simply convert it to old style by manually running `cbfstool add-master-header`. See the code that does this in the current Chrome OS build system here: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/31d87e2/sys-boot/chromeos-bootimage/chromeos-bootimage-0.0.3.ebuild#266

However, cbfstool offers no easy way to create a new CBFS in a completely empty FMAP section, so I think in the end the instructions you posted (creating a dummy CBFS file and copying that in) are still the simplest way to solve that problem, and that's also how our own build system used to do it back in the day: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/firmware-atlas-11827.12.B/sys-boot/chromeos-seabios/chromeos-seabios-9999.ebuild#22

Michael Witten

unread,
Jan 12, 2021, 3:25:19 PM1/12/21
to Julius Werner, drag...@gmail.com, ggg, Mike Frysinger, Chromium OS dev
Thank you for the kind words, Jules.

Please indeed use my email or its contents in anyway that you wish.

Sincerely,
Michael Witten

Michael Witten

unread,
Jan 12, 2021, 3:30:47 PM1/12/21
to Julius Werner, drag...@gmail.com, ggg, Mike Frysinger, Chromium OS dev
> Thank you for the kind words, Jules.

Sorry for misspelling your name, Julius.
Reply all
Reply to author
Forward
0 new messages