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:
committed by
Martin L Roth
parent
25aeaac85b
commit
d2c3e26513
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user