Chromebook devices are automated in the lab using Servo boards, which gives access to low-level hardware controls. It connects via USB on the host and either a dedicated debug power on the Chromebook or a USB Type-C for more recent models.
Alternatively, SuzyQ USB-C cables can be used for the same purposes. The documentation below is common for both interfaces.
Dependencies
Using Servo boards requires some software packages to be installed on
the host. These are available in the Collabora Sysadmin Debian
repository. On LAVA dispatchers controlled by Chef, they are
automatically installed by the
controller.rb
recipe.
The steps below are useful when debugging Chromebooks on an arbitrary computer, to install these packages and dependencies manually after installing Collabora’s apt key:
$ wget https://repositories.collabora.co.uk/sysadmin/debian/pool/tools/c/collabora-archive-keyring/collabora-archive-keyring_0.3debian10.1_all.deb
$ sudo dpkg -i collabora-archive-keyring_0.3debian10.1_all.deb
$ sudo sh -c 'echo "deb https://repositories.collabora.co.uk/sysadmin/debian bullseye tools" >> /etc/apt/sources.list'
$ sudo apt update
$ sudo apt install docker-servod-tools
Developer mode
In order to use Chromebooks with Servo boards, it is necessary to enable developer mode. Follow the steps below to do this on any Chrome OS device:
-
Reboot the Chromebook and put it in recovery mode with
Esc
+Refresh
+Power
. Note that the power button could be on the side of the case.Note: to enter Recovery mode on Chromeboxes (e.g.
puff
), press the recovery button (located right above the K-Slot) with a paper clip and then press the power button. Release the recovery button after a second. -
Enter developer mode with
Ctrl-D
, thenEnter
to turn OS verification off -
Wait for the Chromebook to reboot and set up developer mode
-
Press
Ctrl-D
to let it boot Chrome OS -
Open a terminal on the device with
Ctrl
+Alt
+→
and log in asroot
(no password required).
Note: With some Dell Chromebooks and Chromeboxes, open the terminal with Ctrl
+ Alt
+
Fn
+ F2
.
Note: If root
doesn’t work, log in with chronos
and then run sudo su
.
Note: With some other Chromebooks, such as trogdor
and volteer
, open the
terminal with Ctrl
+ Alt
+ t
. Then open the shell with shell
followed by
sudo su
.
See the Chromium OS documentation for more details about the Firmware Keyboard Interface and Opening a VT-2 terminal.
Recovery
In case something went wrong, for example if the device fails to boot again or if an unknown root password has been set up, the factory OS image can be reinstalled on the Chromebook. Follow the Device OS recovery instructions provided by Google.
In a nushell, on Linux:
- create a recovery media (USB stick or SD card) using this script:
$ wget https://dl.google.com/dl/edgedl/chromeos/recovery/linux_recovery.sh $ chmod 0755 linux_recovery.sh $ sudo bash linux_recovery.sh
- follow the instructions to create the recovery media
- insert it in the Chromebook and restart it in recovery mode
It should automatically perform a full OS recovery.
Servo board serial number and running servod
Predefined udev
rules will match the VID/PID of known Servo boards and CCD capable devices upon connection with the host and google-docker-servo
services will start accordingly.
The rules can be found in /etc/udev/rules.d/99-docker-servo.rules
:
# google-docker-servo* matches on our usbmisc child device, then we specify
# SUBSYSTEMS/DRIVERS to walk up from the specific interface, to the overall
# device, which will actually have a serial
# Servo v2
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5002", ENV{MAJOR}=="189", TAG+="systemd", ENV{SYSTEMD_WANTS}+="google-docker-servo@$name.service", ENV{ID_MODEL}="Google Servo control board %n"
# Servo Micro
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="501a", ENV{MAJOR}=="189", TAG+="systemd", ENV{SYSTEMD_WANTS}+="google-docker-servo@$name.service", ENV{ID_MODEL}="Google Servo Micro control board %n"
# Cr50 (Case Close Debugging)
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5014", ENV{MAJOR}=="189", TAG+="systemd", ENV{SYSTEMD_WANTS}+="google-docker-servo@$name.service", ENV{ID_MODEL}="Google Cr50 %n"
The idVendor
should always be 18d1
for Google products. The idProduct
tells which kind of Servo board has been detected.
To find the VID/PID of the connected Servo/CCD capable device, look for this kind of kernel messages while plugging the USB cable of the Servo board or the SuzyQable:
$ sudo journalctl -kf
Oct 26 18:20:51 debian kernel: usb 5-2.3.3.1.3.2: new full-speed USB device number 12 using xhci_hcd
Oct 26 18:20:51 debian kernel: usb 5-2.3.3.1.3.2: New USB device found, idVendor=18d1, idProduct=5014, bcdDevice= 1.00
Oct 26 18:20:51 debian kernel: usb 5-2.3.3.1.3.2: New USB device strings: Mfr=1, Product=2, SerialNumber=11
Oct 26 18:20:51 debian kernel: usb 5-2.3.3.1.3.2: Product: Cr50
Oct 26 18:20:51 debian kernel: usb 5-2.3.3.1.3.2: Manufacturer: Google Inc.
Oct 26 18:20:51 debian kernel: usb 5-2.3.3.1.3.2: SerialNumber: 20006046-8D23B055
All the known types should be covered by the predefined udev
rules; if this is a new type of Servo board, add a new rule.
The logs also report the serial number for the connected device. The SerialNumber
value is used to create a unique google-docker-servo
service and it needs to be added to the/etc/google-docker-servo.conf
file on the host.
Each line in the file should have:
- A device name which will be used to create symlinks to device nodes and to name the
servod
docker container - The device serial number
- A unique network port
- The device board name
- The device model (only needed for certain Chromebooks)
For example, using the kernel log above
to configure a servod
service on port 9902 to control the jelboz
Chromebook:
jelboz-local, 20006046-8D23B055, 9902, zork, dalboz
After the file has been edited, replug the Servo board and check that a
google-docker-servo
service is starting as expected:
$ sudo journalctl -f
Oct 26 18:22:59 debian systemd[1]: Starting "Google Servo control board manager"...
Oct 26 18:23:00 debian run-servod[100102]: INFO:root:Device path: /dev/bus/usb/005/013
Oct 26 18:23:00 debian run-servod[100102]: INFO:root:Board serial: b'20006046-8D23B055'
Oct 26 18:23:00 debian run-servod[100102]: INFO:root:Board configuration: {'servo-name': 'jelboz-local', 'serial-number': '20006046-8D23B055', 'port-number': '9902', 'board-name': 'zork', 'board-model': 'dalboz'}
[...]
Oct 26 18:23:07 debian systemd[1]: Started "Google Servo control board manager".
The google-docker-servo
service will start a docker container that runs the servod
server to control the connected device. The server’s port is mapped to the network port on the host specified in the /etc/google-docker-servo.conf
file:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4763462e7cf8 registry.gitlab.collabora.com/lava/hdctools-docker:release-1022.1-1 "bash /start_servod.…" About a minute ago Up About a minute 0.0.0.0:9902->9999/tcp jelboz-local-docker_servod
The docker container is named after the device’s local alias defined in the /etc/google-docker-servo.conf
file.
Some device nodes will be automatically created with symlinks for the cr50 and EC debug consoles:
$ ls -l /dev/google-servo/jelboz-local/
total 0
lrwxrwxrwx 1 root root 10 Oct 26 18:23 cr50-uart -> /dev/pts/6
lrwxrwxrwx 1 root root 10 Oct 26 18:23 ec-uart -> /dev/pts/8
A /dev/ttyUSB*
device will be created for the AP debug console:
$ ls -la /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 10 Oct 26 18:23 /dev/ttyUSB1
Low-level Chromebook controls can be accessed through the dut-control
tool available in the docker container, or through the XML-RPC API.
A quick manual check to confirm that the Servo interface is working as expected can be done with this command:
$ docker exec jelboz-local-docker_servod dut-control -i
*************
* CONTROL
*************
accum_clear_ctrls DOC: List of available controls to clear underlying accumulators. Use this in conjunction with 'avg_power_rails' to clear after reading, to ensure a fresh sample on the next timestamp.
------------------------------- GET: {'drv': 'servo_metadata', 'subtype': 'tagged_controls', 'interface': 'servo', 'tag': 'accum_clear_ctrls', 'cmd': 'get', 'interface_prefix': '', 'control_name': 'accum_clear_ctrls'}
------------------------------- SET: {'drv': 'servo_metadata', 'subtype': 'tagged_controls', 'interface': 'servo', 'tag': 'accum_clear_ctrls', 'cmd': 'set', 'interface_prefix': '', 'control_name': 'accum_clear_ctrls'}
adc_ez_config_ctrls DOC: List of available controls to run easy configuration on all known ADC controls.
[...]
Controls can also be get/set using the XML-RPC API, by connecting to the servod
server running in the docker container.
For example, to get the cold_reset
state using the API in a Python script:
#!/usr/bin/env python3
from xmlrpc import client
remote_uri = 'http://0.0.0.0:9902'
client = client.ServerProxy(remote_uri, verbose=False)
print(client.get('cold_reset'))
Serial console and power control
The main control to be used for automation is the cold_reset
one, which
essentially turns the device off when enabled.
To get the current status:
$ docker exec jelboz-local-docker_servod dut-control cold_reset
cold_reset:on
In a separate terminal, monitor the embedded controller console output to check when the firmware starts booting:
$ sudo cat /dev/google-servo/jelboz-local/ec-uart
Then turn the power on and watch the firmware boot, and turn it off again:
$ docker exec jelboz-local-docker_servod dut-control cold_reset:off
# check the ec-uart console output for some activity
$ docker exec jelboz-local-docker_servod dut-control cold_reset:on
If this worked as expected, congratulations! Your Chromebook is now ready to be automated in the LAVA test lab.
Upgrading the Servo v4 firmware
There are many versions of the Servo v4 firmware. It’s recommended to upgrade it to a recent version whenever possible, as older versions have shown some issues with certain boards and Depthcharge versions.
You can check the current Servo v4 firmware version using the CLI that
the Servo runs in the first serial terminal it enumerates
(/dev/ttyUSB0
in the example below, it could be different in your
setup):
$ miniterm /dev/ttyUSB0
> version
Board: 3
RO: servo_v4_v2.3.22-ecb74cc56
RW: servo_v4_v2.3.22-ecb74cc56
Build: servo_v4_v2.3.22-ecb74cc56
2019-07-23 18:07:15 @chromeos-legacy-release-us-central2-c-x32-40-2efr
The servo_updater
tool (installed from the
dependencies above) can be used to flash the Servo v4
firmware. To use it, first clone the firmware-tools
repo. Then make
sure the Servo v4 is connected to your host and run:
$ cd firmware-tools
$ sudo PATH=$PWD/bin:$PATH LD_LIBRARY_PATH=$PWD/lib servo_updater -f <firmware_file>
The servo_v4_fw
directory in firmware-tools
includes some tested
Servo v4 firmware binaries. You can usually find these binaries in the
ChromeOS SDK (usr/share/servo_updater/firmware/
inside the cros-build
chroot).
If everything goes well you should see an output like this:
Current servo_v4 version is servo_v4_v2.3.22-ecb74cc56
Available servo_v4 version is servo_v4_v2.4.35-f1113c92b
Updating to recommended version.
usb_updater2 -d 18d1:501b -n servo_v4_fw/servo_v4_v2.4.35-f1113c92b.bin
read 131072(0x20000) bytes from servo_v4_fw/servo_v4_v2.4.35-f1113c92b.bin
Found device.
found interface 4 endpoint 6, chunk_len 64
READY
-------
start
target running protocol version 6 (type 1)
maximum PDU size: 1024
Flash protection status: 0008
version: servo_v4_v2.3.22-ecb74cc56
key_version: 0
min_rollback: -1
offset: writable at 0x10000
sending 0xe760 bytes to 0x10000
-------
update complete
image updated
usb_updater2 -d 18d1:501b -n servo_v4_fw/servo_v4_v2.4.35-f1113c92b.bin
read 131072(0x20000) bytes from servo_v4_fw/servo_v4_v2.4.35-f1113c92b.bin
Found device.
found interface 4 endpoint 6, chunk_len 64
READY
-------
start
target running protocol version 6 (type 1)
maximum PDU size: 1024
Flash protection status: 0008
version: servo_v4_v2.3.22-ecb74cc56
key_version: 0
min_rollback: -1
offset: writable at 0
sending 0xe8d4 bytes to 0
-------
update complete
image updated
If you have more than one Servo v4 interface connected to the host, you
can specify which one you want to flash using the -s <serial_number>
option of servo_updater
. The serial number of an interface can also be
retrieved from its CLI using the serialno
command:
> serialno
Serial number: C1706310161