Workaround for battery discharge in dev-mode
Introduction
Issue 362105 describes a painfully annoying problem for people who put their Chromebooks in dev-mode so they can use them more like a standard laptop. The tl;dr version is that if you've completely replaced or disabled ChromeOS and the battery runs all the way down, it forgets that it was configured to allow non-ChromeOS images to boot, locking you out of your own device. If this happens to you, here's how to get back in.
Note: If your machine boots up in ChromeOS, you probably haven't lost anything:
If you're no longer in dev-mode, enter it again and reboot
Go into crosh (CTRL-ALT-T)
Type "shell" to get a shell.
run sudo crossystem dev_boot_legacy=1
reboot
press CTRL-L when you see the scary boot screen
If your machine doesn't boot ChromeOS and only gives you the "ChromeOS is missing or damaged" screen with every boot, then the following may help.
This process is long and annoying, but it's better than losing all your data.
Impacted Devices
The issue has been resolved in newer devices, but most likely will not be backported to older ones. Here are all the devices impacted (the project names are listed; see the Developer Information for ChromeOS Devices page for product names):
- mario & alex & zgb
- stumpy & lumpy
- snow
- parrot
- stout
- butterfly
- link
- spring & skate
- peppy & pepto
- falco & wolf & leon
- panther & monroe
- squawks & quawks & clapper & swanky & kip
- zako
- big & blaze
- veyron
How to recover
These instructions assume you have another Linux machine to do this on, because
- I know that works, and 2) I don't have any Mac or Windows machines.
Here's what we're going to do:
Stay in developer mode
If your Linux data is in a separate disk partition that you've created or taken over, you still may be okay. But best not to risk it. Certainly don't go through the recovery process, because that will wipe the disk.
Download a recovery image
If you go to www.google.com/chromeos/recovery, you'll find instructions for running a Linux script that will download and format a USB stick for you. Follow them, but don't remove the USB stick afterwards, and really don't insert it in your Chromebook. [Update: okay, you used to find instructions there, but they're gone. Look here instead. I've filed a bug.]
Note: My USB stick shows up as /dev/sdc
. If yours is something else, use that
instead in the examples below.
Modify the recovery image so we can mount it
The root filesystem on the recovery image is marked with some unsupported ext2 flags, so that if you try to mount it you'll see a message like this:
$ sudo mount /dev/sdc3 /mnt
mount: wrong fs type, bad option, bad superblock on /dev/loop0,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so
Exit code 32
$
We need to clear those flag bits so we can make changes to the filesystem. To do this, we need to know the offset (in bytes) of the beginning of the rootfs partition. You can use the GNU parted tool to find this out:
$ sudo parted /dev/sdc
GNU Parted 2.3
Using /dev/sdc
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit B
(parted) print
Error: The backup GPT table is not at the end of the disk, as it should be.
This might mean that another operating system believes the disk is smaller.
Fix, by moving the backup to the end (and removing the old backup)?
Fix/Ignore/Cancel? I
Warning: Not all of the space available to /dev/sdc appears to be used, you can
fix the GPT to use all of the space (an extra 3115136 blocks) or continue with
the current setting?
Fix/Ignore? I
Model: Kingston DT 100 G2 (scsi)
Disk /dev/sdc: 3926949888B
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Number Start End Size File system Name Flags
11 32768B 8421375B 8388608B RWFW
6 8421376B 8421887B 512B KERN-C
7 8421888B 8422399B 512B ROOT-C
9 8422400B 8422911B 512B reserved
10 8422912B 8423423B 512B reserved
2 10485760B 27262975B 16777216B KERN-A
4 27262976B 44040191B 16777216B KERN-B
8 44040192B 882900991B 838860800B ext4 OEM
12 950009856B 966787071B 16777216B fat16 EFI-SYSTEM boot
5 966787072B 968884223B 2097152B ROOT-B
3 968884224B 2269118463B 1300234240B ext2 ROOT-A
1 2269118464B 2315255807B 46137344B ext2 STATE
(parted) quit
$
Note that we do not want to repair any of the GPT headers. Just answer "I" (ignore) when asked about them.
The rootfs partition is partition 3, which begins 968884224 bytes into the disk. That's the magic number we need to remember. (We could just refer to /dev/sdc3 with an offset of 0, but this process works on binary images too.)
This script will modify the ext2 flags bits in the rootfs filesystem header so we can mount it. Copy it into a file and mark it as executable.
#!/bin/bash
is_ext2() {
local rootfs="$1"
local offset="${2-0}"
# Make sure we're checking an ext2 image
local sb_magic_offset=$((0x438))
local sb_value=$(sudo dd if="$rootfs" skip=$((offset + sb_magic_offset)) \
count=2 bs=1 2>/dev/null)
local expected_sb_value=$(printf '\123\357')
if [ "$sb_value" = "$expected_sb_value" ]; then
return 0
fi
return 1
}
enable_rw_mount() {
local rootfs="$1"
local offset="${2-0}"
# Make sure we're checking an ext2 image
if ! is_ext2 "$rootfs" $offset; then
echo "enable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2
return 1
fi
local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte
# Dash can't do echo -ne, but it can do printf "\NNN"
# We could use /dev/zero here, but this matches what would be
# needed for disable_rw_mount (printf '\377').
printf '\000' |
sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \
conv=notrunc count=1 bs=1 2>/dev/null
}
[ -n "$2" ] || exit 1
enable_rw_mount $1 $2
Provide the USB device and the byte offset as arguments to the script, and now we can mount the rootfs from the recovery image:
$ sudo ./enable_rw_mount.sh /dev/sdc 968884224
$ sudo mount /dev/sdc3 /mnt
$ ls /mnt
bin/ dev/ home/ lib64/ media/ opt/ proc/ sbin/ tmp/ var/
debugd/ etc/ lib/ lost+found/ mnt/ postinst@ root/ sys/ usr/
Change the chromeos-install script to just fix the flags
The recovery image would normally run the /usr/sbin/chromeos-install
script,
which would wipe the SSD and restore everything. We don't want that, so we'll
just modify that script to restore the dev-mode flags to allow our custom image
to boot again.
Create the script we want:
$ cat > /tmp/foo.txt
#!/bin/bash
crossystem dev_boot_legacy=1 dev_boot_usb=1
sleep 5
exit
^D
$
Replace the original script:
$ sudo cp /tmp/foo.txt /mnt/usr/sbin/chromeos-install
$ ls -l /mnt/usr/sbin/chromeos-install
-rwxr-xr-x 1 root root 76 Jun 16 16:44 /mnt/usr/sbin/chromeos-install*
$ cat /mnt/usr/sbin/chromeos-install
#!/bin/bash
crossystem dev_boot_legacy=1 dev_boot_usb=1
sleep 5
exit
$
Note that it's executable, and has the content we want. Unmount the USB stick.
$ sudo umount /mnt
Recover the dev-mode flags
Now you can insert this recovery image into your Chromebook. When it goes through the normal "Verifying the integrity of your recovery media" process, it may complain that the rootfs is not verified, but it will continue on anyway because we're in developer mode. It will then proceed to the "System recovery" step, but don't panic - it's going to run your modified script instead. That should only take a few seconds. Once it completes, remove the USB stick and when it reboots, your Ctrl-L and Ctrl-U shortcuts should work again.