This document describes the basic workflow to follow, after you've made a change to the Linux Kernel in the Chromium OS sources, to submit a your changes to the Chromium OS repository, and to submit your changes upstream to the official Linux Kernel repository. What commit message should I use?Code ChangesFor changes which cannot be submitted upstream to the official Linux Kernel repository, the commit message is important. We use the following conventions:
An example subject line is: CHROMIUM: ARM: tegra: Add initial support for aebl Do not include configuration changes (i.e. changes to files within chromeos/config) with other code changes. See the next section for these. Files may not be suitable for submission upstream because they have Chromium OS-specific information, or may be based on other changes which are local to the Chromium OS project. Such changes may not be upstreamed, but the Chromium OS project team will continue to maintain the changes. Configuration ChangesWhen a commit involves configuration changes, make sure that any code changes are separated out into a different commit. The configuration commit should contain only changes to files within the chromeos/config directory tree. The commit message should start with CHROMIUM: config: An example message is: CHROMIUM: config: enable aebl config How do I send a patch upstream?Changes to parts of the kernel which are not purely Chrome OS- specific should be upstreamed where possible. This includes just about any part of the kernel: ARM- and x86-specific changes, driver patches and changes within the main kernel and mm source. You can start with a code review if you like. Take a look on the kernel mailing list to get a feel for how people submit and review patches. To upstream, create a remote to track upstream. For example the main kernel: git remote add upstream git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.gitYou can then create a commit within this branch. This can be done either by cherry-picking the commit from another branch and perhaps changing the commit message: git cherry-pick my-changeor using git am to turn a patch into a commit: git am my-change.patchor manually applying a patch, and then committing: patch -p1 < my-change.patchgit add ...git commit# create a suitable messageLike any kernel patch you should use checkpatch.pl to make sure it is clean (see below). Also see Documentation/SubmittingPatches.txt in the kernel source tree for instructions. You can use 'git show HEAD' to see your patch. To send upstream, you can create patch files with 'git format-patch', and then email then. This creates a set of patch files named '000n-<something>' where 'n' is incremented starting from 1, and "something" comes from the first line of each change description. You can use get_maintainer.pl to figure out who to send it to. # turn top commit into a patch
If you are sending a series of patches it is nice to include a cover letter. This turns up as patch zero in the series. Pass the --cover-letter flag to 'git format-patch' and it will create a 0000-subject file which you can edit to contain your cover letter. When you use 'git send-email' you can send files 000* to send the cover letter and all your patches as one email set. Another flow that might work is to send email directly, without going through 'git format-patch'. For example you can email the top five commits to the mailing list with something like: git send-email --to=... -cc=... --signoff --subject-prefix=... --annotate HEAD~5The --annotate lets you edit them before they go out, which is probably a good idea in this case! When replying to an email thread with an updated patch, use the something like the following to attach your email to the thread: git send-email --thread --no-chain-reply-to --in-reply-to=<message id> --to=... --cc=... --signoff --subject-prefix=... --annotate 0002-...You can find the message id under the label <Message-Id> in gmail in the 'Show Original' link in the drop down options for the email you want to reply to. There is a video here: http://www.youtube.com/watch?v=LLBrBBImJt4 The patch flow throughout the video is:
Patch checklist: (at 34:30 of the video)
Which copyright header should I use?When adding new files to the kernel, please add a regular Google copyright header to them. In particular this is true for any code that will eventually find its way upstream (which should include practically everything we do). The main reason for this is that there's no concept of "The Chromium OS Authors" outside of our project, since it refers to the AUTHORS file that isn't bundled with the kernel. /*
* Copyright (C) 2013 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
How do I check my patches are correct?There are two aspects of having correct patches to send upstream: not having Chromium OS-specific details, and meeting all the Linux kernel requirements. For the following sections, you will need to have created a patch file using git format-patch. Also note that you will have to recreate the patch file, and re-check your patch file each time you check in code to your source tree. Remove Chromium OS-specific DetailsVerifying these details is as simple as loading the patch file in your favorite editor. Edit the file manually to become compliant; this will, of course, have no affect on the source or commit message stored by git.
Once all of the above is true, you can move on to checking for compliance with the Linux Kernel guidelines. Check for Compliance with Linux Kernel RequirementsYou should use this perl script to check that your patch conforms to the kernel coding standard. It is kept in the linux kernel tree. git format-patch HEAD~scripts/checkpatch.pl 0001-my-change.patch# make improvementsgit add ...git commit --amend# rinse and repeatAutomating the Compliance ChecksThis script might be useful also, as it checks a series of patches, checks for Chrome OS-specific commit tags and prints a summary at the end. Put it in your path and run it from anywhere. #! /bin/shKERNEL=/path/to/src/third_party/kernel/scripts/OUT=$(tempfile)while (( "$#" )); do ERRCP= ERR= checkpatch.pl $1 || ERRCP=1 grep BUG= $1 && ERR="$ERR BUG" grep TEST= $1 && ERR="$ERR TEST" grep "Change-Id" $1 && ERR="$ERR Change-Id" grep "Review URL" $1 && ERR="$ERR Review URL" if [ -n "${ERR}" ]; then echo "Bad $1 ($ERR)" >>$OUT else echo "OK $1" >>$OUT fi shiftdonecat $OUTHow do I backport an upstream patch?Let's suppose you've spotted a juicy new commit in Linus's upstream linux kernel tree that you just must have. NAME git-cherry-pick - Apply the changes introduced by some existing commitsSYNOPSIS git cherry-pick [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...DESCRIPTION Given one or more existing commits, apply the change each one introduces, recording a new commit for each. This requires your working tree to be clean (no modifications from the HEAD commit).OPTIONS ...
-x When recording the commit, append to the original commit message a note that indicates which commit this change was cherry-picked from. Append the note only for cherry picks without conflicts. Do not use this option if you are cherry-picking from your private branch because the information is useless to the recipient. If on the other hand you are cherry-picking between two publicly visible branches (e.g. backporting a fix to a maintenance branch for an older release from a development branch), adding this information can be useful.First, add Linus's tree as a remote to the chromium-os kernel tree (assuming the chromium-os root is cd ~/chromiumos/src/third_party/kernelgit remote add linus git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.gitgit remote updateThis will take a little while as git fetches all upstream commits. Luckily, git is smart and won't refetch commits already in the chromium-os tree. Once the tree is updated, take a brief look at whats been happening upstream recently to a particular path ( git log --oneline linus/master /path/of/interestWe can view that juicy commit using its upstream hash: git show <upstream_commit_hash>To backport the commit to the chromium-os tree, first start a new branch from the current Tip of Tree (ToT). repo sync .repo start my_upstream_commit .git cherry-pick -x -s <upstream_commit_hash>Add TEST= and BUG= lines at the bottom of the patch description. Also, remember to keep the patch subject intact with only an addition of UPSTREAM: or BACKPORT: as a new prefix. Now, the upstream commit is on its own branch, let's upload it to gerrit, like usual: repo upload .This will generate a gerrit change for review. After review, submit the patch in gerrit like usual. Kernel ConfigurationKernel configuration in Chromium OS has an extra level of indirection from the normal .config file. So do the instructions - see this page for more information. How to quickly test kernel modifications (the fastest way)Please take a look at doc on network-based development. While setting up your environment might appear to be harder and more time consuming, in many cases it will allow to test kernel modifications much faster and easier than the ways described below. How to quickly test kernel modifications (the fast way)Do an incremental build of the kernel: (chroot) $ FEATURES="noclean" cros_workon_make --board=${BOARD} --install chromeos-kernelUpdate the kernel on the target: (chroot) $ ~/trunk/src/scripts/update_kernel.sh --remote <ip of target>Note that using cros_workon_make leaves build artifacts in your source directory under the "build" directory. When you do a regular emerge of the kernel (and are cros_work'ed on) this will slow things down because the entire source directory gets copied. So delete the "build" directory when you're done. Dealing with a bad kernel installationOne problem with this fast approach is that it requires an already installed and booted target system. If you update with a bad kernel so that it no longer boots, this approach is no longer available. The system is generally recoverable by booting physical media (USB stick or SD card) and copying its kernel blob over your kernel partition: # Assuming you boot physical media as sdb, and your local disk is sda,$ dd if=/dev/sdb2 of=/dev/sda2Dealing with partition corruption due to bad kernel recoveryOne time I really screwed up my system by recovering (after bad kernel installation) with 'dd if=/dev/sdb of=/dev/sda'. I forgot the '2' after each drive specification. $ a=$(uuidgen)$ cgpt add -i 3 -u $a /dev/sdawhich generates and installs a new GUID for sda3. Dealing with issues - preparing the environmentBelow are described some problems you might encounter. If instructions above work, you might skip them. We assume that you want to boot using the most recently built image. First, to prepare for other steps: # cd to the image directory
SSHD keysIf sshd on the target machine complains about missing keys: # Mount stateful partition
Public key authorizationupdate_kernel.sh uses for authorization keys that, depending on your configuration, might not be present in your image. If that's the case, you will be prompted for password during script execution. To fix it, run the following commands in your image directory: # Mount root filesystemiptables configurationIptables - again, depending on your configuration - might be configured to refuse all the incoming connections, in which case update_kernel.sh will be unable to ssh to your target machine. If you encounter this problem, to fix it:
Dealing with issues - cleaning upTo build new image after modifications to one or more of the partitions, simply run: (chroot) $ ./pack_partitions.sh chromiumos_image.binHow to test kernel modifications (the slow way)Note: there is more information (possibly more useful too) in the disk format document, and more specifically here. Check out the tree somewhere as usual, make the chroot, build packages, build image, blah blah blah. Create a bootable USB key from that image. We'll modify that key with our testing kernel. At this point you need to ~/trunk/src/scripts $ cros_workon start --board=<your platform> chromeos-kernel~/trunk/src/scripts $ repo sync chromiumos/third_party/kernelThen, still inside
~/trunk/src/scripts $ export BUILD_DIR=/tmp/kernel # pick any new directory you likeWhere
Renaming of the make will produce ${BUILD_DIR}/arch/<your_target_arch>/boot/{bzImage|uImage}, which is the kernel image you want to try. The next step varies depending on whether your hardware has an EFI BIOS, legacy BIOS or u-boot. You can ether copy the kernel to your USB stick and tell the bootloader to use your new kernel, possibly with extra debugging arguments, or use netboot/NFS for u-boot equipped targets (see network_based_development for details).
If you need your module to be present on the target, you can scp it from the build location to your target (provided your target is set for Testing with an EFI BIOS
Copy the new blackadder$ mount | grep vfat/dev/sdc12 on /media/disk type vfat (rw,nosuid,nodev,uhelper=hal,shortname=mixed,uid=100135,utf8,umask=077,flush)blackadder$ ls -l /media/disk/efi/boot/total 6600-rwx------ 1 wfrichar root 262656 Apr 21 10:21 bootx64.efi*-rwx------ 1 wfrichar root 2851056 Apr 21 10:12 bzImage*-rwx------ 1 wfrichar root 1040 Apr 21 08:51 grub.cfg*-rwx------ 1 wfrichar root 2821296 Apr 19 11:19 vmlinuz*blackadder$ cat /media/disk/efi/boot/grub.cfg set timeout=10set default=0menuentry "bzImage normal" { linux /efi/boot/bzImage quiet console=tty2 init=/sbin/init boot=local rootwait root=/dev/sda3 ro noresume noswap i915.modeset=1 loglevel=1}menuentry "bzImage serial normal" { linux /efi/boot/bzImage earlyprintk=serial,ttyS0,115200 console=ttyS0,115200 i nit=/sbin/init boot=local rootwait root=/dev/sda3 ro noresume noswap i915.modese t=1 loglevel=7}menuentry "bzImage serial add_efi_memmap" { linux /efi/boot/bzImage add_efi_memmap earlyprintk=serial,ttyS0,115200 console =ttyS0,115200 init=/sbin/init boot=local rootwait root=/dev/sda3 ro noresume nos wap i915.modeset=1 loglevel=7}menuentry "vmlinuz normal" { linux /efi/boot/vmlinuz quiet console=tty2 init=/sbin/init boot=local rootwait root=/dev/sda3 ro noresume noswap i915.modeset=1 loglevel=1}menuentry "vmlinuz serial debug" { linux /efi/boot/vmlinuz earlyprintk=serial,ttyS0,115200 console=ttyS0,115200 i nit=/sbin/init boot=local rootwait root=/dev/sda3 ro noresume noswap i915.modese t=1 loglevel=7}When the USB key boots, I'll see a menu that lets me select which boot path to use. Testing with a legacy BIOSCopy the new blackadder$ mount | grep sdc3/dev/sdc3 on /media/C-KEYFOB type ext3 (rw,nosuid,nodev,uhelper=hal)blackadder$ ls -l /media/C-KEYFOB/boottotal 6940lrwxrwxrwx 1 root root 19 Apr 23 01:55 System.map -> System.map-2.6.32.9-rw-r--r-- 1 root root 1313402 Apr 23 00:12 System.map-2.6.32.9-rw-r----- 1 root root 2851056 Apr 26 10:30 bzImagelrwxrwxrwx 1 root root 15 Apr 23 01:55 config -> config-2.6.32.9-rw-r--r-- 1 root root 74534 Apr 23 00:12 config-2.6.32.9-rw-r--r-- 1 root root 409 Apr 23 01:53 extlinux.conf-r--r--r-- 1 root root 14336 Apr 23 01:53 extlinux.syslrwxrwxrwx 1 root root 16 Apr 23 01:55 vmlinuz -> vmlinuz-2.6.32.9-rw-r--r-- 1 root root 2821296 Apr 23 00:12 vmlinuz-2.6.32.9blackadder$ cat /media/C-KEYFOB/boot/extlinux.conf DEFAULT chromeos-usbPROMPT 1TIMEOUT 20label chromeos-usb menu label chromeos-usb kernel vmlinuz append quiet console=tty2 init=/sbin/init boot=local rootwait root=/dev/sdb3 ro noresume noswap i915.modeset=1 loglevel=1label chromeos-test menu label chromeos-test kernel bzImage append console=tty1 init=/sbin/init boot=local rootwait root=/dev/sdb3 ro noresume noswap i915.modeset=1 loglevel=7When the USB key boots, I can hit TAB to see the list of boot choices, and can pick the one I want by entering the label. Debugging messagesWith either bootloader, you can debug early kernel failures by increasing the verbosity and location of kernel debug messages. You can modify the config files without rebuilding anything. The default boot args have this: quiet console=tty2 loglevel=1Using args like these instead may be helpful: console=tty1 loglevel=7Working on several kernel issues
To create separate builds get per kernel git branch, while in the cloned kernel source tree root create a build directory for your current branch, for instance: mkdir ../build/<branch_name>and then just add kmake () {Modifying H2C Bios kernel command linePlace kernel blob into a file ( vbutil_kernel --repack <modified_kernel> --config <new_cmd_line> \--signprivate <path_to>/vboot_reference/tests/devkeys/<key> \ --oldblob <original_kernel>
where The command line to boot a kernel with verified rootfs disabled can be obtain by editing the regular command line as follows: vbutil_kernel --verify <original_kernel> --verbose | tail -1 | sed 's/dm_verity[^ ]\+//gs|verity /dev/sd%D%P /dev/sd%D%P ||s| root=/dev/dm-0 | root=/dev/sd%D%P |s/dm="[^"]\+" //' > new_cmd_lineInstalling onto SSDInstead of booting the kernel from USB as described above, it can be installed directly on the SSD of the target device. With modern H2C Bios, this requires signing the blob with the development key and booting with the target machine's development mode switch set appropriately. Also, since there are two kernel/root partition pairs in our partition scheme, we need to select which one we want to use. Usually we stay with the current pair. To sign with the devkey as per the Disk Format doc http://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format#TOC-Quick-development: vbutil_kernel --pack new_kern.bin --keyblock /usr/share/vboot/devkeys/kernel.keyblock --signprivate <keys_path>/kernel_data_key.vbprivk --version 1 --config config.txt --bootloader /lib64/bootstub/bootstub.efi --vmlinuz vmlinuzTransfer Identify the preferred kernel partition. This will be either
Copy the image to the partition. dd if=new_kern.bin of=/dev/sda2
localhost ~ # dev_debug_vboot :TEST: verify HD kernel B with firmware A keyKey block: Size: 0x4b8 Flags: 7 !DEV DEV !REC :
localhost ~ # cgpt show /dev/sda start size part contents :
4096 32768 2 Label: "KERN-A"
Type: ChromeOS kernel UUID: B87DAA9E-E82E-B449-B93A-5EB0BD81BCEC Attr: priority=3 tries=0 successful=1 :
36864 32768 4 Label: "KERN-B"
Type: ChromeOS kernel UUID: 4581FC5C-58D1-8148-9FC4-E4B983C90782 Attr: priority=0 tries=0 successful=0 :Getting a Kernel TraceRun the following commands on the target. This needs to be done just once after an install. touch /var/lib/crash_sender_pausedtouch /home/chronos/"Consent To Send Stats"chown chronos:chronos /var/lib/crash_sender_pausedchown chronos:chronos /home/chronos/"Consent To Send Stats"sync; sync; syncThe crashes will then appear in /var/spool/crash. Loading Kernel modules from outside the root filesystemIf you need to load kernel modules from a location other than the root filesystem, module locking must be disabled. Either a kernel command line option can be used: lsm.module_locking=0Or, on images with dm-verity disabled (--noenable_rootfs_verification), the restriction can be disabled via the exposed sysctl: echo 0 >/proc/sys/kernel/chromiumos/module_lockingBlacklisting Kernel modules for individual overlaysIf you need to blacklist kernel modules for specific overlays. Modify the overlay-<name>/chromeos-base/chromeos-bsp-<name>/chromeos-bsp-<name>-<version>.ebuild file. Add the following two lines to the end of the src_install() function: insinto "/etc/modprobe.d"doins "${FILESDIR}/<blacklist file>"The ${FILESDIR} variable points to the files/ directory within the chromeos-bsp-<name>/ directory. Within this directory, add your <blacklist file> (ex cros-blacklist.conf). For each kernel module you wish to blacklist, add the following line to <blacklist file>: blacklist <module name>You can also use # comments within these files to explain why the kernel module needs to be blacklisted. Building and installing kernel-next on a specific overlayIf given target device is not building kernel-next, you can switch by unmerging the standard kernel and then building kernel-next normally: cros_workon --board=${BOARD} stop sys-kernel/chromeos-kernelemerge-${BOARD} --unmerge sys-kernel/chromeos-kernelcros_workon --board=${BOARD} start sys-kernel/chromeos-kernel-next cros_workon_make --board=${BOARD} sys-kernel/chromeos-kernel-next --install ~/trunk/src/scripts/update_kernel.sh --board=${BOARD} --remote=hostname... |
