Early boot

From OLPC
Jump to navigation Jump to search
  This page is monitored by the OLPC team.


Pencil.png NOTE: The contents of this page are not set in stone, and are subject to change!

This page is a draft in active flux ...
Please leave suggestions on the talk page.

Pencil.png

Draft of early boot upgrade/init procedures designed by Michael Stone and C. Scott Ananian.

Early userland startup steps

Stage 1: Initramfs

See the source code for more details. Instructions are available for building initramfsen.

  1. Control is passed to the initramfs' /init program.
    • This program runs python2.5 as PID 1.
  2. /init executes the theft deterrence protocol, checking its 'am I stolen?' flag and looking for a valid activation lease.
  3. If successful, /init will fork and hand over control to user-land.

...(sometime later, or immediately if already activated)

Stage 2: NAND

  1. callback (as pid NNN)
  2. mount /sysroot, unmount usb/sd
  3. copy /security/lease to /sysroot/security/lease if first boot (activation)
  4. parse chosen/bootpath, swing /versions/current
  5. make minimal userland context (mount --move /sysroot /)
  6. ideally protect PID 1, RTC <- vserver delta time

Stage 3: Userland

Perhaps, we're booting a custom userland. In that case, /sbin/olpc_init.py will contain something like:

|def run():  
|    os.exec('/sbin/init')

and will be imported and run by PID 1.

Perhaps we're booting from a backup OS. Assuming that we've only got one partition to deal with:

  1. make new config w/ swapped current and alt
    • (ie. create a /versions/configs/XXX w/ new current, alt)
  2. then swing /versions/boot symlink

If multiple partitions are present:

  1. Make boot:/boot/alt/alt point to ../`basename(readlink boot:/boot)`
  2. Make boot:/boot point to boot-versions/`basename(readlinke boot:/boot/alt)`

In either case:

  1. Make the /versions/running symlink point to pristine/<hash>
  2. Set $current equal to the basename of readlink of /versions/running (which should be a hash)
  3. mount /home /versions/run/$current/home (or /home from home partition)
  4. mount /security /versions/run/$current/security (or /security from boot partition)
  5. mount /versions /versions/run/$current/versions
  6. chroot /versions/run/$current (mount --move ?)

Finally, as suggested above:

if exists '/sbin/olpc_init.py':
  sys.path = ['/sbin'] + sys.path
  from olpc_init import run
  run(<parameters?>)
else:
  exec '/sbin/init --init'

Notes on P_SF_RUN

P_SF_RUN:
 off = allow mod = run from /versions/run/X
 on  = pristine  = run from /versions/run/X

switch on->off: set the unlink flags on /versions/run
      off->on:  create immutably-tagged /versions/run/a,b from /versions/a,b

List of directories in boot partition

 /boot -> boot-versions/<hash>
 /boot-alt -> boot/alt
 /boot-versions/<version>/{runos.zip,runrd.zip,etc}
 /boot-versions/<version>/alt -> ../<alternate version>
 /security

List of directories in root partition

 /sys, /proc, /ofw   vfs
 /versions/pristine/{hashes}
 /versions/contents/{hashes}  (contents files for the corresponding pristine tree)
 /versions/configs/`mkdtemp`/current -> ../../pristine/<hash> (backwards compatibility; don't use)
 /versions/configs/`mkdtemp`/alt     -> ../../pristine/<hash> (backwards compatibility; don't use)
 /versions/boot -> configs/<something> (backwards compatibility; don't use)
 /versions/running -> pristine/<hash>  (version we booted from; hash matches /boot symlink from boot partition)
 /versions/updates/<hash>   (temporary space for updates, preserved in case update
                             net connection drops & updater is restarted)
 /versions/run/{hashes}
 /security
 /boot -> versions/boot/current/boot (backwards compatibility; don't use)
 /boot-alt -> versions/boot/alt/boot (backwards compatibility; don't use)

List of directories in home partition

 /home

Upgrade procedure

Upgrade procedure, creating new b from a (w.l.o.g)
 Rainbow: (ATC gives <version> <hash> <priority>)
 -1: Check that /versions/pristine/<hash> doesn't already exist.
  If unpartitioned:
   0. Create new /versions/configs/$c <- where $c = mkdtemp
   1. Create /versions/configs/$c/current -> ../../pristine/`basename(readlink /versions/running)`
   2. Swap /versions/boot to point to configs/$c, save old contents in $old
  If partitioned:
   0-2. Make /boot/alt point to ../`basename(readlink /versions/running)`
  3a. Delete the tree(s) pointed to from /versions/configs/$old which are not pointed to by
     /versions/running (revisit when multiple trees)
  3b. Delete corresponding members of /boot-versions if using a boot partition
  4. Delete /versions/configs/$old.
  4b. Delete corresponding member of /boot-versions if using a boot partition.
  5. Invoke 'olpc-updater <version>'
     in new container:
[MICHAEL WILL REWRITE STARTING FROM HERE]
  NOTE THAT /upgrade must live in same bind-mount as /current if we're to be able to clone it.
  MORE LIKELY THAT RAINBOW WILL CREATE /upgrade FOR US AS CLONE OF /current
           /current (ro-bind mount from /versions/a)
           /upgrade (initially empty)
 OLPC updater:
  6. clone /current to /upgrade
  7. upgrade /upgrade by hook or crook
[END MICHAEL REWRITES]
  8. exit
 Rainbow:
  9. Verify /versions/updates/<hash> matches <hash>
 10. Move /versions/updates/<hash> to /versions/pristine/<hash>
 10b. Create /versions/run/<hash> from /versions/pristine/<hash> according to P_SF_RUN setting
 If unpartitioned:
  11. Make a new config /versions/configs/$d (d = mkdtemp)
  12. Create 'current' symlink to /versions/pristine/<hash>
  13. Create 'alt' symlink to *realpath of* /versions/running
  14. Swing /versions/boot to /versions/configs/$d
       (atomic!  iff we do file move of new symlink)
  15. Delete /versions/configs/$c
 If partitioned:
  11. Copy /versions/pristine/<hash>/boot to boot:/boot-versions/<hash>
  12. Make boot:/boot-versions/<hash>/alt point to what boot:/boot currently points to
  13. Atomically swing boot:/boot to point to /boot-versions/<hash>
 16. If <priority> reboot. (Ask Eben & sugar folks)

Open Questions

  1. Are thawed trees persistent?
    1. when I use a frozen tree?
    2. when I upgrade
  2. Is "thawness" global? Or per-OS-version?
  3. Can thawed trees be frozen for temporary read-only use?
  4. Space limits for upgrader?
  5. UI for:
    1. P_SF_RUN
    2. which image you boot (esp if more than two)
    3. Rest of security UI
  6. Configuration versioning / globalness
    1. do security settings persist across updates
    2. do we inherit a security configuration from the 'old' version when upgrading?
  7. Loadable kernel modules
    1. Bind-mount /lib/modules read-only? (Doesn't fix the problem, really)

Related pages