OFW NAND FLASH Updater

From OLPC
Jump to navigation Jump to search

Introduction

(This information applies to OFW Q2D07 and later)

OFW can rewrite the OLPC NAND FLASH from a file on a removable disk (USB or SD) or a network server. This is useful for recovering a system whose NAND FLASH has been damaged. The normal usage pattern is:

  1. (Assume that the OLPC has security enabled, which is the most common situation)
  2. The user powers-on the XO then immediately presses all four right-side game buttons simultaneously (releasing them when instructed to)
  3. OFW searches for a file named "fs.zip" in the following locations
    1. disk:\fs.zip (USB mass-storage device)
    2. sd:\fs.zip (SD card)
    3. http:\\172.18.0.1\fs.zip (school server)
  4. If fs.zip is found, OFW looks inside it for data.img and data.sig, validating data.img according to the signature in data.sig. See Firmware Security for details of that process. If validation fails, the system displays an error message and reboots.
  5. data.img contains a sequence of command lines that control the NAND FLASH reflashing process. The actual binary data that will go into the NAND FLASH is in a separate (much larger) file; the lines in data.img sequence the overall process and validate (via a hash) individual pieces of the binary data in the other file. So the large file that contains the complete NAND FLASH image is not signed directly; the control file is signed, and it contains hashes that validate the large file.

It is also possible to invoke the updater from the ok prompt on XOs that are not secure. In this case, the command file does not have to be signed. The procedure for doing so is not as streamlined as it could be...

This procedure can handle both unpartitioned and partitioned NAND FLASH layouts. The partition map format is "RedBoot" (for "documentation" of this format, see the Linux kernel file drivers/mtd/redboot.c). For partitioned layouts, the updater can:

  • Create a new partition map on an previously unpartitioned NAND FLASH
  • Erase an only partition map and replace it with a new one
  • Erase an old partition map and revert the NAND FLASH to an unpartitioned layout
  • Write data to an individual partition, leaving other partitions untouched

Updater Commands

These commands may appear inside the "data.img" file that controls the update process.

partitions: boot 20 user 300 ...
The name is the partition name. The number is how many erase blocks to reserve. -1 means "the remainder of the NAND FLASH" The partitions will be created in the order given.
set-partition: 1
set-partition: boot
Restricts following commands to the partition specified (either by number or name)
0 means the entire device, unpartitioned
1 means the first partition that was created by the "partitions:" line, etc
Prior to the execution of this command, or if this command is not used, the partition number is 0, i.e. the entire device.
The numeric form doesn't work right prior to Q2E13
erase-all
Erases the entire contents of the partition, or the entire NAND FLASH if the partition number is 0. The bad block table at the end of the device, and any blocks that are marked as bad in that table, are left untouched. If erase-all is used with partition number 0, it will erase any partition table that is already present. If you want to erase everything and also make a partition table, first do "erase-all", then do "partitions".
data: blocks.img
Selects a file that contains the raw block data for subsequent eblock: commands.
The given filename is expanded to ${DN}\${filename}, where DN is the OFW name of the device from which this specification file (i.e. the files containing these commands) was loaded.
eblock: 23 sha256 001122334455...
Writes the next 128 KiB block of data from the file specified by the previous data: command to the next good NAND FLASH erase block within the current partition.
Prior to writing the data to the NAND FLASH, the file data is hashed using sha256 and compared to the given hash value (in ASCII hex, 0x00, 0x11, 0x22, ... in this example). At the moment, the only supported hash function is sha256.
The number "23" is an ordinal number for ease of referring to specific lines within the file. The first "eblock:" line for a given partition should start with 0, and successive lines should increment the number. In the absence of bad blocks, that ordinal number would reflect the actual erase block offset within the partition, but bad blocks will cause the offset to "drift".
cleanmarkers
Installs JFFS2 cleanmarkers in the out-of-band area for all eblocks (within the currently partition) that have not already been written.
mark-pending: 0
Marks block 0 (in this example) as "not yet ready for use". mark-complete: will subsequently mark it as ready. The marker goes in out-of-band area of NAND FLASH so it doesn't interfere with normal data. The intended use is to pre-mark a critical block - for example the one containing the filesystem root directory - as pending, then write the filesystem data to that block and other blocks. Finally, after everything has been written, you go back and mark-complete: the critical block. If the process gets interrupted before the complete filesystem has been written, the critical block will still be in the pending state, so the firmware will know not to trust the filesystem.
mark-complete: 0
See mark-pending:
bytes: 23 4 80e 08 8091a2b3c4d5e6f7
Writes arbitrary data to an arbitrary offset within a page or its out-of-band data area. In this example, 23 (hex) is the erase block number (within the current partition), 4 is the page number, 80e is the offset within the page, 08 is the length, and 8091a2b3c4d5e6f7 is 8 bytes of binary data expressed in hex - 0x80, 0x91, 0xa2, ... 0xf7 .
The NAND FLASH hardware page size is 0x800 bytes, followed by 0x40 bytes of out-of-band data, so this example writes 8 bytes of data beginning at offset 0x0e within the out-of-band area.
(This command is intended for extraordinary circumstances; it should be unnecessary for most use cases.)

Examples

The following examples show the contents of the control file for some specific tasks.

No Partitions

In this example we erase the entire NAND FLASH and create an unpartitioned layout.

data:  os650.img
erase-all
mark-pending: 0
eblock: 0 sha256 e2c5475df63ebc2a5c32d344d826637c089e522b51ee48316379d6a0c2d8a4d1
eblock: 1 sha256 22cf80f3a2431d345e5d509a9d8d6c8346fe35966e44ce048dc4d9f1ed4c4674
...
eblock: 923 sha256 2958d28bc5539c18213b7467d4237b1b05bbc144a21800e6f469c24ed5b809b7
eblock: 924 sha256 dbae292d72a2e22534849472efbc679d734bd393b5a2302aa82c4e0ce3f3974e
cleanmarkers
mark-complete: 0

Make a Partition Map and Fill Some Partitions

This example erases the NAND and creates a new layout with three partitions "boot", "root", and "user". "boot" has space for 0x80 erase blocks (16 MBytes) minus however may bad blocks happen to be in that range. "root" has space for 0xc00 erase blocks (384 MBytes) less bad blocks. "user" is the rest of the NAND. The "boot" and "root" partitions are populated with filesystem data, while the "user" partition is left empty (i.e. in the erased state).

data:  os999.img
erase-all
partitions:  boot 80  root c00  user -1
set-partition: 1
mark-pending: 0
eblock: 0 sha256 ff3227e680963cb0a5e24fdbdaf1aa5437c9ce400761f7c5a462d75f1f18f204
eblock: 1 sha256 289a9e81513229f14d7ee6c0d9eb588ffd7c7e87e146da42b2102a0cc2f9598f
...
eblock: 37 sha256 02eb0c9c03c10bf9cc3a590fb5e8dbe1bc519caf75c26975002bf5c62291a199
cleanmarkers
mark-complete: 0
set-partition: 2
mark-pending: 0
eblock: 0 sha256 2e27f6c6abfde30947944773d85b7cccb0d2ebb91e5a29fbc6d71e884a05a90a
...
eblock: 85a sha256 e2c5475df63ebc2a5c32d344d826637c089e522b51ee48316379d6a0c2d8a4d1
cleanmarkers
mark-complete: 0

Replace the Contents of One Partition

In this example we assume that the NAND has already been partitioned, and we just write to the first partition.

set-partition: 1
mark-pending: 0
eblock: 0 sha256 98040b869b8ed044b1547bdca07c09a207d32b02187d334f0168f09ea34cb9a5
...
eblock: 63 sha256 f9a9d78e786fdf48ecc2349070ce22e98b81ff4a9854f9729effec3b88702dcd
cleanmarkers
mark-pending: 1

Using Partitions

OFW Partition Syntax

When OFW tries to open a file on NAND FLASH, in the absence of an explicit partition specfication:

  • If the NAND FLASH is unpartitioned, OFW assumes that a JFFS2 filesystem fills the entire FLASH
  • If the NAND FLASH is partitioned, OFW looks for a partition named "boot" and uses that one

To specify an explicit partition to OFW, put partition_name, before the pathname, for example:

  ok dir nand:root,\bin\

Don't create a partition whose name begins with "\", because that will confuse OFW.

Linux Partition Syntax

If the NAND device driver (e.g. mtd/nand/cafe.c) contains partition support, it will create a separate mtdN device for each partition. So the kernel cmdline could contain, for example:

root=mtd1 rootfstype=jffs2

The number sequence depends in part on the individual NAND device driver - the order in which it creates partitions after having parsed a partition specification (either from a RedBoot partition map, or some other partition map, or a commandline partition spec, depending on which partition mapping mechanisms the driver includes). For that reason, it is probably best to specify the partition by name:

root=mtd:root rootfstype=jffs2

The stuff after the ':' is the partition name.

From userland, you can say, for example:

mount -t jffs2 mtd:user /usr

Using the Updater in Non-Secure Mode

If you have a developer key and can get to the OFW "ok" prompt, you can use the NAND FLASH updater without having to sign the control file.

update-nand u:\data.img

When testing this way in non-secure mode, the control file can have any name you want, subject to file system naming limitations. The name "data.img" is required only in the context of a signed "fs.zip" bundle.