Docs/tutorial: Wrap the text in part?.md to 72 characters

Signed-off-by: Martin Roth <gaumless@gmail.com>
Change-Id: I4f0a07b4ab729aafdb4a1149a7617cd34392cf12
Reviewed-on: https://review.coreboot.org/c/coreboot/+/64967
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Elyes Haouas <ehaouas@noos.fr>
This commit is contained in:
Martin Roth
2022-06-04 19:52:42 -06:00
committed by Martin L Roth
parent 25aeaac85b
commit d2c3e26513
3 changed files with 348 additions and 313 deletions

View File

@ -2,11 +2,11 @@ Tutorial, part 1: Starting from scratch
=========================================== ===========================================
This tutorial will guide you through the process of setting up a working This tutorial will guide you through the process of setting up a working
coreboot toolchain. In same cases you will find specific instructions for Debian (apt-get), coreboot toolchain. In same cases you will find specific instructions
Fedora (dnf) and Arch Linux (pacman) based package management systems. Use the for Debian (apt-get), Fedora (dnf) and Arch Linux (pacman) based package
instructions according to your system. management systems. Use the instructions according to your system.
** Note: Summaries of each of the steps are at the end of the document. ** **Note: Summaries of each of the steps are at the end of the document.**
Download, configure, and build coreboot Download, configure, and build coreboot
@ -16,13 +16,15 @@ Download, configure, and build coreboot
### Step 1 - Install tools and libraries needed for coreboot ### Step 1 - Install tools and libraries needed for coreboot
Debian based distros: Debian based distros:
`sudo apt-get install -y bison build-essential curl flex git gnat libncurses5-dev m4 zlib1g-dev` `sudo apt-get install -y bison build-essential curl flex git gnat`
`libncurses5-dev m4 zlib1g-dev`
Arch based distros: Arch based distros:
`sudo pacman -S base-devel curl git gcc-ada ncurses zlib` `sudo pacman -S base-devel curl git gcc-ada ncurses zlib`
Redhat based distros: Redhat based distros:
`sudo dnf install git make gcc-gnat flex bison xz bzip2 gcc g++ ncurses-devel wget zlib-devel patch` `sudo dnf install git make gcc-gnat flex bison xz bzip2 gcc g++`
`ncurses-devel wget zlib-devel patch`
### Step 2 - Download coreboot source tree ### Step 2 - Download coreboot source tree
@ -36,8 +38,8 @@ cd coreboot
### Step 3 - Build the coreboot toolchain ### Step 3 - Build the coreboot toolchain
Please note that this can take a significant amount of time. Use `CPUS=` to Please note that this can take a significant amount of time. Use `CPUS=`
specify number of `make` jobs to run in parallel. to specify number of `make` jobs to run in parallel.
This will list toolchain options and supported architectures: This will list toolchain options and supported architectures:
@ -53,12 +55,12 @@ make crossgcc-aarch64 CPUS=$(nproc) # build Aarch64 toolchain
make crossgcc-riscv CPUS=$(nproc) # build RISC-V toolchain make crossgcc-riscv CPUS=$(nproc) # build RISC-V toolchain
``` ```
Note that the i386 toolchain is currently used for all x86 platforms, including Note that the i386 toolchain is currently used for all x86 platforms,
x86_64. including x86_64.
Also note that you can possibly use your system toolchain, but the results are Also note that you can possibly use your system toolchain, but the
not reproducible, and may have issues, so this is not recommended. See step 5 results are not reproducible, and may have issues, so this is not
to use your system toolchain. recommended. See step 5 to use your system toolchain.
### Step 4 - Build the payload - coreinfo ### Step 4 - Build the payload - coreinfo
@ -117,7 +119,8 @@ make savedefconfig
cat defconfig cat defconfig
``` ```
There should only be two lines (or 3 if you're using the system toolchain): There should only be two lines (or 3 if you're using the system
toolchain):
```Text ```Text
CONFIG_PAYLOAD_ELF=y CONFIG_PAYLOAD_ELF=y
@ -134,8 +137,8 @@ At the end of the build, you should see:
`Build emulation/qemu-i440fx (QEMU x86 i440fx/piix4)`` `Build emulation/qemu-i440fx (QEMU x86 i440fx/piix4)``
This means your build was successful. The output from the build is in the build This means your build was successful. The output from the build is in
directory. build/coreboot.rom is the full rom file. the build directory. build/coreboot.rom is the full rom file.
Test the image using QEMU Test the image using QEMU
@ -157,8 +160,8 @@ Start QEMU, and point it to the ROM you just built:
qemu-system-x86_64 -bios build/coreboot.rom -serial stdio qemu-system-x86_64 -bios build/coreboot.rom -serial stdio
``` ```
You should see the serial output of coreboot in the original console window, and You should see the serial output of coreboot in the original console
a new window will appear running the coreinfo payload. window, and a new window will appear running the coreinfo payload.
Summary Summary
@ -168,10 +171,10 @@ Summary
### Step 1 summary - Install tools and libraries needed for coreboot ### Step 1 summary - Install tools and libraries needed for coreboot
Depending on your distribution you have installed the minimum additional Depending on your distribution you have installed the minimum additional
software requirements to continue with downloading and building coreboot. software requirements to continue with downloading and building
Not every distribution has the tools, that would be required, coreboot. Not every distribution has the tools, that would be required,
installed by default. In the following we shortly introduce the purpose of the installed by default. In the following we shortly introduce the purpose
installed packages: of the installed packages:
* `build-essential` or `base-devel` are the basic tools for building software. * `build-essential` or `base-devel` are the basic tools for building software.
* `git` is needed to download coreboot from the coreboot git repository. * `git` is needed to download coreboot from the coreboot git repository.
@ -180,67 +183,72 @@ installed packages:
are needed to build the coreboot toolchain. `gcc` and `gnat` have to be are needed to build the coreboot toolchain. `gcc` and `gnat` have to be
of the same version. of the same version.
If you started with a different distribution or package management system you If you started with a different distribution or package management
might need to install other packages. Most likely they are named slightly system you might need to install other packages. Most likely they are
different. If that is the case for you, we'd like to encourage you to contribute named slightly different. If that is the case for you, we'd like to
to the project and submit a pull request with an update for this documentation encourage you to contribute to the project and submit a pull request
for your system. with an update for this documentation for your system.
### Step 2 summary - Download coreboot source tree ### Step 2 summary - Download coreboot source tree
This will download a 'read-only' copy of the coreboot tree. This just means This will download a 'read-only' copy of the coreboot tree. This just
that if you made changes to the coreboot tree, you couldn't immediately means that if you made changes to the coreboot tree, you couldn't
contribute them back to the community. To pull a copy of coreboot that would immediately contribute them back to the community. To pull a copy of
allow you to contribute back, you would first need to sign up for an account on coreboot that would allow you to contribute back, you would first need
gerrit. to sign up for an account on gerrit.
### Step 3 summary - Build the coreboot toolchain. ### Step 3 summary - Build the coreboot toolchain.
This builds one of the coreboot cross-compiler toolchains for X86 platforms.
Because of the variability of compilers and the other required tools between This builds one of the coreboot cross-compiler toolchains for X86
the various operating systems that coreboot can be built on, coreboot supplies platforms. Because of the variability of compilers and the other
and uses its own cross-compiler toolchain to build the binaries that end up as required tools between the various operating systems that coreboot can
part of the coreboot ROM. The toolchain provided by the operating system (the be built on, coreboot supplies and uses its own cross-compiler toolchain
'host toolchain') is used to build various tools that will run on the local to build the binaries that end up as part of the coreboot ROM. The
system during the build process. toolchain provided by the operating system (the 'host toolchain') is
used to build various tools that will run on the local system during the
build process.
### Step 4 summary - Build the payload ### Step 4 summary - Build the payload
To actually do anything useful with coreboot, you need to build a payload to To actually do anything useful with coreboot, you need to build a
include into the rom. The idea behind coreboot is that it does the minimum amount payload to include into the rom. The idea behind coreboot is that it
possible before passing control of the machine to a payload. There are various does the minimum amount possible before passing control of the machine
payloads such as grub or SeaBIOS that are typically used to boot the operating to a payload. There are various payloads such as grub or SeaBIOS that
system. Instead, we used coreinfo, a small demonstration payload that allows the are typically used to boot the operating system. Instead, we used
user to look at various things such as memory and the contents of the coreboot coreinfo, a small demonstration payload that allows the user to look at
file system (CBFS) - the pieces that make up the coreboot rom. various things such as memory and the contents of the coreboot file
system (CBFS) - the pieces that make up the coreboot rom.
### Step 5 summary - Configure the build ### Step 5 summary - Configure the build
This step configures coreboot's build options using the menuconfig interface to This step configures coreboot's build options using the menuconfig
Kconfig. Kconfig is the same configuration program used by the linux kernel. It interface to Kconfig. Kconfig is the same configuration program used by
allows you to enable, disable, and change various values to control the coreboot the linux kernel. It allows you to enable, disable, and change various
build process, including which mainboard(motherboard) to use, which toolchain to values to control the coreboot build process, including which
use, and how the runtime debug console should be presented and saved. mainboard(motherboard) to use, which toolchain to use, and how the
Anytime you change mainboards in Kconfig, you should always run `make distclean` runtime debug console should be presented and saved. Anytime you change
before running `make menuconfig`. Due to the way that Kconfig works, values will mainboards in Kconfig, you should always run `make distclean` before
be kept from the previous mainboard if you skip the clean step. This leads to a running `make menuconfig`. Due to the way that Kconfig works, values
hybrid configuration which may or may not work as expected. will be kept from the previous mainboard if you skip the clean step.
This leads to a hybrid configuration which may or may not work as
expected.
### Step 6 summary - Build coreboot ### Step 6 summary - Build coreboot
You may notice that a number of other pieces are downloaded at the beginning of You may notice that a number of other pieces are downloaded at the
the build process. These are the git submodules used in various coreboot builds. beginning of the build process. These are the git submodules used in
By default, the _blobs_ submodule is not downloaded. This git submodule may be various coreboot builds. By default, the _blobs_ submodule is not
required for other builds for microcode or other binaries. To enable downloading downloaded. This git submodule may be required for other builds for
this submodule, select the option "Allow use of binary-only repository" in the microcode or other binaries. To enable downloading this submodule,
"General Setup" menu of Kconfig select the option "Allow use of binary-only repository" in the "General
This attempts to build the coreboot rom. The rom file itself ends up in the Setup" menu of Kconfig This attempts to build the coreboot rom. The rom
build directory as 'coreboot.rom'. At the end of the build process, the build file itself ends up in the build directory as 'coreboot.rom'. At the end
displayed the contents of the rom file. of the build process, the build displayed the contents of the rom file.
### Step 7 summary - Install QEMU ### Step 7 summary - Install QEMU
@ -253,11 +261,11 @@ process in a virtualised environment.
Here's the command line instruction broken down: Here's the command line instruction broken down:
* `qemu-system-x86_64` * `qemu-system-x86_64`
This starts the QEMU emulator with the i440FX host PCI bridge and PIIX3 PCI to This starts the QEMU emulator with the i440FX host PCI bridge and PIIX3
ISA bridge. PCI to ISA bridge.
* `-bios build/coreboot.rom` * `-bios build/coreboot.rom`
Use the coreboot rom image that we just built. If this flag is left out, the Use the coreboot rom image that we just built. If this flag is left out,
standard SeaBIOS image that comes with QEMU is used. the standard SeaBIOS image that comes with QEMU is used.
* `-serial stdio` * `-serial stdio`
Send the serial output to the console. This allows you to view the coreboot Send the serial output to the console. This allows you to view the
boot log. coreboot boot log.

View File

@ -4,28 +4,29 @@
If you already have an account, skip to Step 2. If you already have an account, skip to Step 2.
Otherwise, go to <https://review.coreboot.org> in your preferred web browser. Otherwise, go to <https://review.coreboot.org> in your preferred web
Select **Sign in** in the upper right corner. browser. Select **Sign in** in the upper right corner.
Select the appropriate sign-in. For example, if you have a Google account, Select the appropriate sign-in. For example, if you have a Google
select **Google OAuth2** (gerrit-oauth-provider plugin). **Note:** Your account, select **Google OAuth2** (gerrit-oauth-provider plugin).
username for the account will be the username of the account you used to **Note:** Your username for the account will be the username of the
sign-in with. (ex. your Google username). account you used to sign-in with. (ex. your Google username).
## Step 2a: Set up SSH keys ## Step 2a: Set up SSH keys
If you prefer to use an HTTP password instead, skip to Step 2b. If you prefer to use an HTTP password instead, skip to Step 2b.
If you do not have an SSH key set up on your account already (as is the case If you do not have an SSH key set up on your account already (as is the
with a newly created account), follow the instructions below; otherwise, case with a newly created account), follow the instructions below;
doing so could overwrite an existing key. otherwise, doing so could overwrite an existing key.
In a terminal, run `ssh-keygen -t ed25519` and confirm the default path In a terminal, run `ssh-keygen -t ed25519` and confirm the default path
`.ssh/id_ed25519`. `.ssh/id_ed25519`.
Make a passphrase -- remember this phrase. It will be needed whenever you use Make a passphrase -- remember this phrase. It will be needed whenever
this public key. **Note:** You might want to use a short password, or you use this public key. **Note:** You might want to use a short
forego the password altogether as you will be using it very often. password, or forego the password altogether as you will be using it very
often.
Copy the content of `.ssh/id_ed25519.pub` (notice the ".pub" suffix Copy the content of `.ssh/id_ed25519.pub` (notice the ".pub" suffix
as you need to send the public key) into the textbox "New SSH Key" at as you need to send the public key) into the textbox "New SSH Key" at
@ -33,17 +34,19 @@ https://review.coreboot.org/settings/#SSHKeys and save it.
## Step 2b: Set up an HTTP Password ## Step 2b: Set up an HTTP Password
Alternatively, instead of using SSH keys, you can use an HTTP password. To do so, Alternatively, instead of using SSH keys, you can use an HTTP password.
after you select your name and click on **Settings** on the left-hand side, rather To do so, after you select your name and click on **Settings** on the
than selecting **SSH Public Keys**, select **HTTP Password**. left-hand side, rather than selecting **SSH Public Keys**, select **HTTP
Password**.
Click **Generate Password**. This should fill the "Password" box with a password. Copy Click **Generate Password**. This should fill the "Password" box with a
the password, and add the following to your `$HOME/.netrc` file: password. Copy the password, and add the following to your
`$HOME/.netrc` file:
machine review.coreboot.org login YourUserNameHere password YourPasswordHere machine review.coreboot.org login YourUserNameHere password YourPasswordHere
where YourUserNameHere is your username, and YourPasswordHere is the password you where YourUserNameHere is your username, and YourPasswordHere is the
just generated. password you just generated.
If your system is behind a snooping HTTPS proxy, you might also have to If your system is behind a snooping HTTPS proxy, you might also have to
make its SSL certificate known to curl, a system specific operation. make its SSL certificate known to curl, a system specific operation.
@ -55,26 +58,28 @@ certificate verification in git:
The `--global` argument sets it for all git transfers of your local The `--global` argument sets it for all git transfers of your local
user, `false` means not to validate the certificate. user, `false` means not to validate the certificate.
If that still doesn't allow you to pull or push changes to the server, the If that still doesn't allow you to pull or push changes to the server,
proxy is likely tampering with the data stream, in which case there's nothing the proxy is likely tampering with the data stream, in which case
we can do. there's nothing we can do.
## Step 3: Clone coreboot and configure it for submitting patches ## Step 3: Clone coreboot and configure it for submitting patches
On Gerrit, click on the **Browse** tab in the upper left corner and select On Gerrit, click on the **Browse** tab in the upper left corner and
**Repositories**. From the listing, select the "coreboot" repo. You may have select **Repositories**. From the listing, select the "coreboot" repo.
to click the next page arrow at the bottom a few times to find it. You may have to click the next page arrow at the bottom a few times to
find it.
If you are using SSH keys, select **ssh** from the tabs under "Project If you are using SSH keys, select **ssh** from the tabs under "Project
coreboot" and run the "clone with commit-msg hook" command that's provided. coreboot" and run the "clone with commit-msg hook" command that's
This should prompt you for your id_rsa passphrase, if you previously set one. provided. This should prompt you for your id_rsa passphrase, if you
previously set one.
**Note:** if the **ssh** option is not showing, check that you have a username **Note:** if the **ssh** option is not showing, check that you have a
set. Click the profile picture at the top right and select **User Settings**, username set. Click the profile picture at the top right and select
then set your username in the **Profile** section. **User Settings**, then set your username in the **Profile** section.
If you are using HTTP, instead, select **http** from the tabs under "Project coreboot" If you are using HTTP, instead, select **http** from the tabs under
and run the command that appears. "Project coreboot" and run the command that appears.
Now is a good time to configure your global git identity, if you haven't Now is a good time to configure your global git identity, if you haven't
already. already.
@ -82,30 +87,32 @@ already.
git config --global user.name "Your Name" git config --global user.name "Your Name"
git config --global user.email "Your Email" git config --global user.email "Your Email"
Finally, enter the local git repository and set up repository specific hooks Finally, enter the local git repository and set up repository specific
and other configurations. hooks and other configurations.
cd coreboot cd coreboot
make gitconfig make gitconfig
## Step 4: Submit a commit ## Step 4: Submit a commit
An easy first commit to make is fixing existing checkpatch errors and warnings An easy first commit to make is fixing existing checkpatch errors and
in the source files. To see errors that are already present, build the files in warnings in the source files. To see errors that are already present,
the repository by running `make lint` in the coreboot directory. Alternatively, build the files in the repository by running `make lint` in the coreboot
if you want to run `make lint` on a specific directory, run: directory. Alternatively, if you want to run `make lint` on a specific
directory, run:
util/lint/lint-007-checkpatch <filepath> util/lint/lint-007-checkpatch <filepath>
where `filepath` is the filepath of the directory (ex. `src/cpu/amd/car`). where `filepath` is the filepath of the directory (ex.
`src/cpu/amd/car`).
Any changes made to files under the src directory are made locally, Any changes made to files under the src directory are made locally,
and can be submitted for review. and can be submitted for review.
Once you finish making your desired changes, use the command line to stage Once you finish making your desired changes, use the command line to
and submit your changes. An alternative and potentially easier way to stage stage and submit your changes. An alternative and potentially easier way
and submit commits is to use git cola, a graphical user interface for git. For to stage and submit commits is to use git cola, a graphical user
instructions on how to do so, skip to Step 4b. interface for git. For instructions on how to do so, skip to Step 4b.
## Step 4a: Use the command line to stage and submit a commit ## Step 4a: Use the command line to stage and submit a commit
@ -119,20 +126,21 @@ To commit the change, run
git commit -s git commit -s
**Note:** The -s adds a signed-off-by line by the committer. Your commit should be **Note:** The -s adds a signed-off-by line by the committer. Your commit
signed off with your name and email (i.e. **Your Name** **\<Your Email\>**, based on should be signed off with your name and email (i.e. **Your Name**
what you set with git config earlier). **\<Your Email\>**, based on what you set with git config earlier).
Running git commit first checks for any errors and warnings using lint. If Running git commit first checks for any errors and warnings using lint.
there are any, you must go back and fix them before submitting your commit. If there are any, you must go back and fix them before submitting your
You can do so by making the necessary changes, and then staging your commit again. commit. You can do so by making the necessary changes, and then staging
your commit again.
When there are no errors or warnings, your default text editor will open. When there are no errors or warnings, your default text editor will
This is where you will write your commit message. open. This is where you will write your commit message.
The first line of your commit message is your commit summary. This is a brief The first line of your commit message is your commit summary. This is a
one-line description of what you changed in the files using the template brief one-line description of what you changed in the files using the
below: template below:
<filepath>: Short description <filepath>: Short description
@ -143,29 +151,30 @@ For example,
**Note:** It is good practice to use present tense in your descriptions **Note:** It is good practice to use present tense in your descriptions
and do not punctuate your summary. and do not punctuate your summary.
Then hit Enter. The next paragraph should be a more in-depth explanation of the Then hit Enter. The next paragraph should be a more in-depth explanation
changes you've made to the files. Again, it is good practice to use present of the changes you've made to the files. Again, it is good practice to
tense. Ex. use present tense. Ex.
Fix space prohibited between function name and open parenthesis, Fix space prohibited between function name and open parenthesis,
line over 80 characters, unnecessary braces for single statement blocks, line over 80 characters, unnecessary braces for single statement
space required before open brace errors and warnings. blocks, space required before open brace errors and warnings.
When you have finished writing your commit message, save and exit the text When you have finished writing your commit message, save and exit the
editor. You have finished committing your change. If, after submitting your text editor. You have finished committing your change. If, after
commit, you wish to make changes to it, running `git commit --amend` allows submitting your commit, you wish to make changes to it, running `git
you to take back your commit and amend it. commit --amend` allows you to take back your commit and amend it.
When you are done with your commit, run `git push` to push your commit to When you are done with your commit, run `git push` to push your commit
coreboot.org. **Note:** To submit as a private patch, use to coreboot.org. **Note:** To submit as a private patch, use `git push
`git push origin HEAD:refs/for/master%private`. Submitting as a private patch origin HEAD:refs/for/master%private`. Submitting as a private patch
means that your commit will be on review.coreboot.org, but is only visible to means that your commit will be on review.coreboot.org, but is only
yourself and those you add as reviewers. This mode isn't perfect: Somebody who visible to yourself and those you add as reviewers. This mode isn't
knows the commit ID can still fetch the change and everything it refers (e.g. perfect: Somebody who knows the commit ID can still fetch the change and
parent commits). everything it refers (e.g. parent commits).
This has been a quick primer on how to submit a change to Gerrit for review This has been a quick primer on how to submit a change to Gerrit for
using git. You may wish to review the [Gerrit code review workflow review using git. You may wish to review the [Gerrit code review
workflow
documentation](https://gerrit-review.googlesource.com/Documentation/intro-user.html#code-review), documentation](https://gerrit-review.googlesource.com/Documentation/intro-user.html#code-review),
especially if you plan to work on multiple changes at the same time. especially if you plan to work on multiple changes at the same time.
@ -196,14 +205,14 @@ in-depth explanation of the changes you've made to the files. Again, it
is good practice to use present tense. Ex. is good practice to use present tense. Ex.
Fix space prohibited between function name and open parenthesis, Fix space prohibited between function name and open parenthesis,
line over 80 characters, unnecessary braces for single statement blocks, line over 80 characters, unnecessary braces for single statement
space required before open brace errors and warnings. blocks, space required before open brace errors and warnings.
Then press Enter two times to move the cursor to below your description. Then press Enter two times to move the cursor to below your description.
To the left of the text boxes, there is an icon with an downward arrow. To the left of the text boxes, there is an icon with an downward arrow.
Press the arrow and select "Sign Off." Make sure that you are signing off Press the arrow and select "Sign Off." Make sure that you are signing
with your name and email (i.e. **Your Name** **\<Your Email\>**, based on what off with your name and email (i.e. **Your Name** **\<Your Email\>**,
you set with git config earlier). based on what you set with git config earlier).
Now, review each of your changes and mark either individual changes or Now, review each of your changes and mark either individual changes or
an entire file as Ready to Commit by marking it as 'Staged'. To do an entire file as Ready to Commit by marking it as 'Staged'. To do
@ -234,11 +243,11 @@ and the commit succeeds, move to the command line and run `git push`.
Your commits can now be seen on review.coreboot.org if you select "Your" Your commits can now be seen on review.coreboot.org if you select "Your"
and click on "Changes" and can be reviewed by others. Your code will and click on "Changes" and can be reviewed by others. Your code will
first be reviewed by build bot (Jenkins), which will either give you a warning first be reviewed by build bot (Jenkins), which will either give you a
or verify a successful build; if so, your commit will receive a +1. Other warning or verify a successful build; if so, your commit will receive a
users may also give your commit +1. For a commit to be merged, it needs +1. Other users may also give your commit +1. For a commit to be merged,
to receive a +2. **Note:** A +1 and a +1 does not make a +2. Only certain users it needs to receive a +2. **Note:** A +1 and a +1 does not make a +2.
can give a +2. Only certain users can give a +2.
## Step 6 (optional): bash-git-prompt ## Step 6 (optional): bash-git-prompt
@ -255,9 +264,11 @@ as this one is specific to bash.
Alternatively, follow the instructions below: Alternatively, follow the instructions below:
Run the following two commands in the command line: Run the following two commands in the command line:
cd ```Bash
git clone https://github.com/magicmonty/bash-git-prompt.git .bash-git-prompt --depth=1 cd
git clone https://github.com/magicmonty/bash-git-prompt.git \
.bash-git-prompt --depth=1
```
**Note:** cd will change your directory to your home directory, so the **Note:** cd will change your directory to your home directory, so the
git clone command will be run there. git clone command will be run there.
@ -269,36 +280,38 @@ Finally, open the `~/.bashrc` file and append the following two lines:
Now, whenever you are in a git repository, it will continuously display Now, whenever you are in a git repository, it will continuously display
its state. its state.
There also are additional configurations that you can change depending on your There also are additional configurations that you can change depending
preferences. If you wish to do so, look at the "All configs for .bashrc" section on your preferences. If you wish to do so, look at the "All configs for
on <https://github.com/magicmonty/bash-git-prompt>. Listed in that section are .bashrc" section on <https://github.com/magicmonty/bash-git-prompt>.
various lines that you can copy, uncomment and add to your .bashrc file to Listed in that section are various lines that you can copy, uncomment
change the configurations. Example configurations include avoid fetching remote and add to your .bashrc file to change the configurations. Example
status, and supporting versions of Git older than 1.7.10. configurations include avoid fetching remote status, and supporting
versions of Git older than 1.7.10.
## Appendix: Miscellaneous Advice ## Appendix: Miscellaneous Advice
### Updating a commit after running git push: ### Updating a commit after running git push:
Suppose you would like to update a commit that has already been pushed to the Suppose you would like to update a commit that has already been pushed
remote repository. If the commit you wish to update is the most recent to the remote repository. If the commit you wish to update is the most
commit you have made, after making your desired changes, stage the files recent commit you have made, after making your desired changes, stage
(either using git add or in git cola), and amend the commit. To do so, the files (either using git add or in git cola), and amend the commit.
if you are using the command line, run `git commit --amend`. If you are To do so, if you are using the command line, run `git commit --amend`.
using git cola, click on the gear icon located on the upper left side under If you are using git cola, click on the gear icon located on the upper
**Commit** and select **Amend Last Commit** in the drop down menu. Then, stage left side under **Commit** and select **Amend Last Commit** in the drop
the files you have changed, commit the changes, and run git push to push the down menu. Then, stage the files you have changed, commit the changes,
changes to the remote repository. Your change should be reflected in Gerrit as and run git push to push the changes to the remote repository. Your
a new patch set. change should be reflected in Gerrit as a new patch set.
If, however, the commit you wish to update is not the most recent commit you If, however, the commit you wish to update is not the most recent commit
have made, you will first need to checkout that commit. To do so, find the you have made, you will first need to checkout that commit. To do so,
URL of the commit on <https://review.coreboot.org> and go to that page; if find the URL of the commit on <https://review.coreboot.org> and go to
the commit is one that you previously pushed, it can be found by selecting that page; if the commit is one that you previously pushed, it can be
**My** and then **Changes** in the upper left corner. To checkout this commit, found by selecting **My** and then **Changes** in the upper left corner.
in the upper right corner, click on **Download**, and copy the command listed To checkout this commit, in the upper right corner, click on
next to checkout by clicking **Copy to clipboard**. Then, run the copied **Download**, and copy the command listed next to checkout by clicking
command in your coreboot repository. Now, the last commit should be the most **Copy to clipboard**. Then, run the copied command in your coreboot
recent commit to that patch; to update it, make your desired changes, stage repository. Now, the last commit should be the most recent commit to
the files, then amend and push the commit using the instructions in the above that patch; to update it, make your desired changes, stage the files,
then amend and push the commit using the instructions in the above
paragraph. paragraph.

View File

@ -1,31 +1,32 @@
# Writing unit tests for coreboot # Writing unit tests for coreboot
## Introduction ## Introduction
General thoughts about unit testing coreboot can be found in General thoughts about unit testing coreboot can be found in [Unit
[Unit testing coreboot](../technotes/2020-03-unit-testing-coreboot.md). testing coreboot](../technotes/2020-03-unit-testing-coreboot.md).
Additionally, [code coverage](../technotes/2021-05-code-coverage.md) support Additionally, [code coverage](../technotes/2021-05-code-coverage.md)
is available for unit tests. support is available for unit tests.
This document aims to guide developers through the process of adding and writing This document aims to guide developers through the process of adding and
unit tests for coreboot modules. writing unit tests for coreboot modules.
As an example of unit under test, `src/device/i2c.c` (referred hereafter as UUT As an example of unit under test, `src/device/i2c.c` (referred hereafter
"Unit Under Test") will be used. This is simple module, thus it should be easy as UUT "Unit Under Test") will be used. This is simple module, thus it
for the reader to focus solely on the testing logic, without the need to spend should be easy for the reader to focus solely on the testing logic,
too much time on digging deeply into the source code details and flow of without the need to spend too much time on digging deeply into the
operations. That being said, a good understanding of what the unit under test is source code details and flow of operations. That being said, a good
doing is crucial for writing unit tests. understanding of what the unit under test is doing is crucial for
writing unit tests.
This tutorial should also be helpful for developers who want to follow This tutorial should also be helpful for developers who want to follow
[TDD](https://en.wikipedia.org/wiki/Test-driven_development). Even though TDD [TDD](https://en.wikipedia.org/wiki/Test-driven_development). Even
has a different work flow of building tests first, followed by the code that though TDD has a different work flow of building tests first, followed
satisfies them, the process of writing tests and adding them to the tree is the by the code that satisfies them, the process of writing tests and adding
same. them to the tree is the same.
## Analysis of unit under test ## Analysis of unit under test First of all, it is necessary to
First of all, it is necessary to precisely establish what we want to test in a precisely establish what we want to test in a particular module. Usually
particular module. Usually this will be an externally exposed API, which can be this will be an externally exposed API, which can be used by other
used by other modules. modules.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
@ -34,66 +35,70 @@ used by other modules.
.. code-block:: c .. code-block:: c
int i2c_read_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t *data, int i2c_read_field(unsigned int bus, uint8_t chip, uint8_t reg,
uint8_t mask, uint8_t shift) uint8_t *data, uint8_t mask, uint8_t shift)
int i2c_write_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t data, int i2c_write_field(unsigned int bus, uint8_t chip, uint8_t reg,
uint8_t mask, uint8_t shift) uint8_t data, uint8_t mask, uint8_t shift)
For sake of simplicity, let's focus on `i2c_read_field` in this document. For sake of simplicity, let's focus on `i2c_read_field` in this
document.
``` ```
Once the API is defined, the next question is __what__ this API is doing (or Once the API is defined, the next question is __what__ this API is doing
what it will be doing in case of TDD). In other words, what outputs we are (or what it will be doing in case of TDD). In other words, what outputs
expecting from particular functions, when providing particular input parameters. we are expecting from particular functions, when providing particular
input parameters.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
.. code-block:: c .. code-block:: c
int i2c_read_field(unsigned int bus, uint8_t chip, uint8_t reg, uint8_t *data, int i2c_read_field(unsigned int bus, uint8_t chip, uint8_t reg,
uint8_t mask, uint8_t shift) uint8_t *data, uint8_t mask, uint8_t shift)
This is a method which means to read content of register `reg` from i2c device This is a method which means to read content of register `reg` from
on i2c `bus` and slave address `chip`, applying bit `mask` and offset `shift` i2c device on i2c `bus` and slave address `chip`, applying bit `mask`
to it. Returned data should be placed in `data`. and offset `shift` to it. Returned data should be placed in `data`.
``` ```
The next step is to determine all external dependencies of UUT in order to mock The next step is to determine all external dependencies of UUT in order
them out. Usually we want to isolate the UUT as much as possible, so that the to mock them out. Usually we want to isolate the UUT as much as
test result depends __only__ on the behavior of UUT and not on the other possible, so that the test result depends __only__ on the behavior of
modules. While some software dependencies may be hard to be mock (for example UUT and not on the other modules. While some software dependencies may
due to complicated dependencies) and thus should be simply linked into the test be hard to be mock (for example due to complicated dependencies) and
binaries, all hardware dependencies need to be mocked out, since in the thus should be simply linked into the test binaries, all hardware
user-space host environment, targets hardware is not available. dependencies need to be mocked out, since in the user-space host
environment, targets hardware is not available.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
`i2c_read_field` is calling `i2c_readb`, which eventually invokes `i2c_read_field` is calling `i2c_readb`, which eventually invokes
`i2c_transfer`. This method simply calls `platform_i2c_transfer`. The last `i2c_transfer`. This method simply calls `platform_i2c_transfer`. The
function in the chain is a hardware-touching one, and defined separately for last function in the chain is a hardware-touching one, and defined
different SOCs. It is responsible for issuing transactions on the i2c bus. separately for different SOCs. It is responsible for issuing
For the purpose of writing unit test, we should mock this function. transactions on the i2c bus. For the purpose of writing unit test,
we should mock this function.
``` ```
## Adding new tests ## Adding new tests
In order to keep the tree clean, the `tests/` directory should mimic the `src/` In order to keep the tree clean, the `tests/` directory should mimic the
directory, so that test harness code is placed in a location corresponding to `src/` directory, so that test harness code is placed in a location
UUT. Furthermore, the naming convention is to add the suffix `-test` to the UUT corresponding to UUT. Furthermore, the naming convention is to add the
name when creating a new test harness file. suffix `-test` to the UUT name when creating a new test harness file.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
Considering that UUT is `src/device/i2c.c`, test file should be named Considering that UUT is `src/device/i2c.c`, test file should be named
`tests/device/i2c-test.c`. When adding a new test file, it needs to be `tests/device/i2c-test.c`. When adding a new test file, it needs to
registered with the coreboot unit testing infrastructure. be registered with the coreboot unit testing infrastructure.
``` ```
Every directory under `tests/` should contain a Makefile.inc, similar to what Every directory under `tests/` should contain a Makefile.inc, similar to
can be seen under the `src/`. Register a new test in Makefile.inc, by what can be seen under the `src/`. Register a new test in Makefile.inc,
__appending__ test name to the `tests-y` variable. by __appending__ test name to the `tests-y` variable.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
@ -103,10 +108,11 @@ __appending__ test name to the `tests-y` variable.
tests-y += i2c-test tests-y += i2c-test
``` ```
Next step is to list all source files, which should be linked together in order Next step is to list all source files, which should be linked together
to create test binary. Usually a tests requires only two files - UUT and test in order to create test binary. Usually a tests requires only two files
harness code, but sometimes more is needed to provide the test environment. - UUT and test harness code, but sometimes more is needed to provide the
Source files are registered in `<test_name>-srcs` variable. test environment. Source files are registered in `<test_name>-srcs`
variable.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
@ -117,9 +123,10 @@ Source files are registered in `<test_name>-srcs` variable.
i2c-test-srcs += src/device/i2c.c i2c-test-srcs += src/device/i2c.c
``` ```
Above minimal configuration is a basis for further work. One can try to build Above minimal configuration is a basis for further work. One can try to
and run test binary either by invoking `make tests/<test_dir>/<test_name>` or by build and run test binary either by invoking `make
running all unit tests (whole suite) for coreboot `make unit-tests`. tests/<test_dir>/<test_name>` or by running all unit tests (whole suite)
for coreboot `make unit-tests`.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
@ -135,31 +142,34 @@ running all unit tests (whole suite) for coreboot `make unit-tests`.
make unit-tests make unit-tests
``` ```
When trying to build test binary, one can often see linker complains about When trying to build test binary, one can often see linker complains
`undefined reference` to couple of symbols. This is one of solutions to about `undefined reference` to couple of symbols. This is one of
determine all external dependencies of UUT - iteratively build test and resolve solutions to determine all external dependencies of UUT - iteratively
errors one by one. At this step, developer should decide either it's better to build test and resolve errors one by one. At this step, developer should
add an extra module to provide necessary definitions or rather mock such decide either it's better to add an extra module to provide necessary
dependency. Quick guide through adding mocks is provided later in this doc. definitions or rather mock such dependency. Quick guide through adding
mocks is provided later in this doc.
## Writing new tests ## Writing new tests
In coreboot, [Cmocka](https://cmocka.org/) is used as unit test framework. The In coreboot, [Cmocka](https://cmocka.org/) is used as unit test
project has exhaustive [API documentation](https://api.cmocka.org/). Let's see framework. The project has exhaustive [API
how we may incorporate it when writing tests. documentation](https://api.cmocka.org/). Let's see how we may
incorporate it when writing tests.
### Assertions ### Assertions
Testing the UUT consists of calling the functions in the UUT and comparing the Testing the UUT consists of calling the functions in the UUT and
returned values to the expected values. Cmocka implements comparing the returned values to the expected values. Cmocka implements
[a set of assert macros](https://api.cmocka.org/group__cmocka__asserts.html) to [a set of assert
compare a value with an expected value. If the two values do not match, the test macros](https://api.cmocka.org/group__cmocka__asserts.html) to compare a
value with an expected value. If the two values do not match, the test
fails with an error message. fails with an error message.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
In our example, the simplest test is to call UUT for reading our fake devices In our example, the simplest test is to call UUT for reading our fake
registers and do all calculation in the test harness itself. At the end, let's devices registers and do all calculation in the test harness itself.
compare integers with `assert_int_equal`. At the end, let's compare integers with `assert_int_equal`.
.. code-block:: c .. code-block:: c
@ -191,24 +201,25 @@ fails with an error message.
### Mocks ### Mocks
#### Overview #### Overview
Many coreboot modules are low level software that touch hardware directly. Many coreboot modules are low level software that touch hardware
Because of this, one of the most important and challenging part of directly. Because of this, one of the most important and challenging
writing tests is to design and implement mocks. A mock is a software component part of writing tests is to design and implement mocks. A mock is a
which implements the API of another component so that the test can verify that software component which implements the API of another component so that
certain functions are called (or not called), verify the parameters passed to the test can verify that certain functions are called (or not called),
those functions, and specify the return values from those functions. Mocks are verify the parameters passed to those functions, and specify the return
especially useful when the API to be implemented is one that accesses hardware values from those functions. Mocks are especially useful when the API to
components. be implemented is one that accesses hardware components.
When writing a mock, the developer implements the same API as the module being When writing a mock, the developer implements the same API as the module
mocked. Such a mock may, for example, register a set of driver methods. Behind being mocked. Such a mock may, for example, register a set of driver
this API, there is usually a simulation of real hardware. methods. Behind this API, there is usually a simulation of real
hardware.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
For purpose of our i2c test, we may introduce two i2c devices with set of For purpose of our i2c test, we may introduce two i2c devices with
registers, which simply are structs in memory. set of registers, which simply are structs in memory.
.. code-block:: c .. code-block:: c
@ -266,16 +277,17 @@ this API, there is usually a simulation of real hardware.
}; };
``` ```
Cmocka uses a feature that gcc provides for breaking dependencies at the link Cmocka uses a feature that gcc provides for breaking dependencies at the
time. It is possible to override implementation of some function, with the link time. It is possible to override implementation of some function,
method from test harness. This allows test harness to take control of execution with the method from test harness. This allows test harness to take
from binary (during the execution of test), and stimulate UUT as required control of execution from binary (during the execution of test), and
without changing the source code. stimulate UUT as required without changing the source code.
coreboot unit test infrastructure supports overriding of functions at link time. coreboot unit test infrastructure supports overriding of functions at
This is as simple as adding a `name_of_function` to be mocked into link time. This is as simple as adding a `name_of_function` to be
<test_name>-mocks variable in Makefile.inc. The result is that the test's mocked into <test_name>-mocks variable in Makefile.inc. The result is
implementation of that function is called instead of coreboot's. that the test's implementation of that function is called instead of
coreboot's.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
@ -284,44 +296,45 @@ implementation of that function is called instead of coreboot's.
i2c-test-mocks += platform_i2c_transfer i2c-test-mocks += platform_i2c_transfer
Now, dev can write own implementation of `platform_i2c_transfer`. This Now, dev can write own implementation of `platform_i2c_transfer`.
implementation instead of accessing real i2c bus, will write/read from This implementation instead of accessing real i2c bus, will
fake structs. write/read from fake structs.
.. code-block:: c .. code-block:: c
int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, int platform_i2c_transfer(unsigned int bus, struct i2c_msg
int count) *segments, int count)
{ {
} }
``` ```
#### Checking mock's arguments #### Checking mock's arguments
A test can verify the parameters provided by the UUT to the mock function. The A test can verify the parameters provided by the UUT to the mock
developer may also verify that number of calls to mock is correct and the order function. The developer may also verify that number of calls to mock is
of calls to particular mocks is as expected (See correct and the order of calls to particular mocks is as expected (See
[this](https://api.cmocka.org/group__cmocka__call__order.html)). The Cmocka [this](https://api.cmocka.org/group__cmocka__call__order.html)). The
macros for checking parameters are described Cmocka macros for checking parameters are described
[here](https://api.cmocka.org/group__cmocka__param.html). In general, in mock [here](https://api.cmocka.org/group__cmocka__param.html). In general, in
function, one makes a call to `check_expected(<param_name>)` and in the mock function, one makes a call to `check_expected(<param_name>)` and in
corresponding test function, `expect*()` macro, with description which parameter the corresponding test function, `expect*()` macro, with description
in which mock should have particular value, or be inside a described range. which parameter in which mock should have particular value, or be inside
a described range.
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
In our example, we may want to check that `platform_i2c_transfer` is fed with In our example, we may want to check that `platform_i2c_transfer` is
number of segments bigger than 0, each segment has flags which are in fed with number of segments bigger than 0, each segment has flags
supported range and each segment has buf which is non-NULL. We are expecting which are in supported range and each segment has buf which is
such values for _every_ call, thus the last parameter in `expect*` macros is non-NULL. We are expecting such values for _every_ call, thus the
-1. last parameter in `expect*` macros is -1.
.. code-block:: c .. code-block:: c
static void mock_expect_params_platform_i2c_transfer(void) static void mock_expect_params_platform_i2c_transfer(void)
{ {
unsigned long int expected_flags[] = {0, I2C_M_RD, I2C_M_TEN, unsigned long int expected_flags[] = {0, I2C_M_RD,
I2C_M_RECV_LEN, I2C_M_NOSTART}; I2C_M_TEN, I2C_M_RECV_LEN, I2C_M_NOSTART};
/* Flags should always be only within supported range */ /* Flags should always be only within supported range */
expect_in_set_count(platform_i2c_transfer, segments->flags, expect_in_set_count(platform_i2c_transfer, segments->flags,
@ -330,8 +343,8 @@ in which mock should have particular value, or be inside a described range.
expect_not_value_count(platform_i2c_transfer, segments->buf, expect_not_value_count(platform_i2c_transfer, segments->buf,
NULL, -1); NULL, -1);
expect_in_range_count(platform_i2c_transfer, count, 1, INT_MAX, expect_in_range_count(platform_i2c_transfer, count, 1,
-1); INT_MAX, -1);
} }
And the checks below should be added to our mock And the checks below should be added to our mock
@ -347,11 +360,11 @@ in which mock should have particular value, or be inside a described range.
``` ```
#### Instrument mocks #### Instrument mocks
It is possible for the test function to instrument what the mock will return to It is possible for the test function to instrument what the mock will
the UUT. This can be done by using the `will_return*()` and `mock()` macros. return to the UUT. This can be done by using the `will_return*()` and
These are described in `mock()` macros. These are described in [the Mock Object
[the Mock Object section](https://api.cmocka.org/group__cmocka__mock.html) of section](https://api.cmocka.org/group__cmocka__mock.html) of the Cmocka
the Cmocka API documentation. API documentation.
```eval_rst ```eval_rst
.. admonition:: Example .. admonition:: Example
@ -361,17 +374,18 @@ the Cmocka API documentation.
``` ```
### Test runner ### Test runner
Finally, the developer needs to implement the test `main()` function. All tests Finally, the developer needs to implement the test `main()` function.
should be registered there and cmocka test runner invoked. All methods for All tests should be registered there and cmocka test runner invoked. All
invoking Cmocka test are described methods for invoking Cmocka test are described
[here](https://api.cmocka.org/group__cmocka__exec.html). [here](https://api.cmocka.org/group__cmocka__exec.html).
```eval_rst ```eval_rst
.. admonition:: i2c-test example .. admonition:: i2c-test example
We don't need any extra setup and teardown functions for i2c-test, so let's We don't need any extra setup and teardown functions for i2c-test, so
simply register test for `i2c_read_field` and return from main value which is let's simply register test for `i2c_read_field` and return from main
output of Cmocka's runner (it returns number of tests that failed). value which is output of Cmocka's runner (it returns number of tests
that failed).
.. code-block:: c .. code-block:: c