mirror of
https://codeberg.org/canoeboot/cbwww.git
synced 2024-11-25 03:44:44 +00:00
1b9e28c3b8
make canoeboot a truly GNU FSDG compliant coreboot distro, by removing all overly positive reference to Libreboot; what remains is technical in nature, so as to provide historical context since Canoeboot is a fork of Libreboot. I've stated before that I wish to take a more neutral tone toward the FSF, in contrast to the *coldboot war* of 2023 when GNU Boot started. Canoeboot was heavily linking to Libreboot, even going so far as to call itself "inferior" and tell the reader to use Libreboot. From now on, Canoeboot will be maintained as though I actually believed in FSF propoganda. I don't, but its users do. Treat them with respect. My reason for providing Canoeboot is precisely that I wish for such people to have a high quality coreboot distro, much unlike the inferior *GNU Boot* project; inferior because to this day, it's still based on very old Libreboot, with not much changed (of any real substance) relative to the Libreboot 20220710 release on which it forked. In general, I've also found a lot of stragglers from when Canoeboot started, where paragraphs referred to Libreboot that should have actually referred to Canoeboot, or paragraphs with Libreboot-specific information that does not make sense in the Canoeboot project e.g. references to vendor scripts. The resulting canoeboot.org will now look no different to any typical reader than a typical FSF-aligned project. There is a next stage to this, which will become apparent to everyone if I have my way. Signed-off-by: Leah Rowe <info@minifree.org>
522 lines
18 KiB
Markdown
522 lines
18 KiB
Markdown
---
|
|
title: nvmutil manual
|
|
x-toc-enable: true
|
|
...
|
|
|
|
With this software, you can change the MAC address inside GbE regions
|
|
on any system that uses an Intel Flash Descriptor.
|
|
|
|
You can use the documentation below, if you wish to use `nvmutil` manually.
|
|
Continue reading...
|
|
|
|
Introduction
|
|
============
|
|
|
|
This is the manual for `nvmutil`, included in the Canoeboot,
|
|
build system (cbmk) under `util/nvmutil/`. This program lets you modify
|
|
the MAC address, correct/verify/invalidate checksums,
|
|
swap/copy and dump regions on Intel PHY NVM images,
|
|
which are small binary configuration files that go
|
|
in flash, for Gigabit (ethernet) Intel NICs.
|
|
|
|
This software is largely targeted at coreboot users,
|
|
but it can be used on most modern Intel systems, or
|
|
most systems from about 2008/2009 onwards.
|
|
|
|
NOTE: Canoeboot X200/X200T/X200S/T400/T400S/T500/W500/R400
|
|
users should know that this software does *not*
|
|
replace `ich9gen`, because that program generates entire
|
|
ICH9M IFD+GbE regions, in addition to letting you set the
|
|
MAC address. *This* program, `nvmutil`, can *also* set
|
|
the MAC address on those machines, but it operates on a
|
|
single GbE dump that is already created.
|
|
|
|
This program is operated on dumps of the GbE NVM image,
|
|
which normally goes in the boot flash (alongside BIOS/UEFI
|
|
or coreboot, IFD and other regions in the flash). The first
|
|
half of this README is dedicated to precisely this, telling
|
|
you how to dump or otherwise acquire that file; the second
|
|
half of this README then tells you how to operate on it,
|
|
using `nvmutil`.
|
|
|
|
How to download newer versions
|
|
==============================
|
|
|
|
Simply pull down the latest changes in `cbmk.git`. The `nvmutil`
|
|
software is part of our Canoeboot build system, which we called `cbmk`,
|
|
short for non**G**eNUine**B**oot**M**a**K**e.
|
|
|
|
More info about git:
|
|
|
|
* <https://git-scm.com/>
|
|
|
|
Context
|
|
=======
|
|
|
|
On many Intel systems with an IFD (Intel Flash Descriptor), the
|
|
Intel PHY (Gigabit Ethernet) stores its configuration, binary
|
|
encoded, into a special region of the main boot flash, alongside
|
|
other flash regions such as: IFD, ME, BIOS.
|
|
|
|
This includes many configurations, such as your MAC address.
|
|
The purpose of nvmutil project, is precisely to allow you to change your
|
|
MAC address. Many other useful features are also provided.
|
|
|
|
Intel defines this as the *Gigabit Ethernet Non-Volative Memory* or
|
|
just *NVM* for short. It is a 128-byte section, consisting of 64
|
|
words that are 2 bytes, stored in little-endian byte order.
|
|
|
|
Newer Intel PHYs define an *extended* area, which starts
|
|
immediately after the main one, but the `nvmutil` program
|
|
does not modify or manipulate these in any way.
|
|
|
|
The final word in the NVM section is the *checksum*; all words
|
|
must add up, truncated, to the value `0xBABA`. The hardware
|
|
itself does not calculate or validate this, and will in
|
|
fact work nicely, but software such as GNU+Linux will check
|
|
that this is correct. If the checksum is invalid, your
|
|
kernel will refuse to make use of the NIC.
|
|
|
|
This NVM section is the first 128 bytes of a 4KB region in flash.
|
|
This 4KB region is then repeated, to make an 8KB region in
|
|
flash, known as the *GbE region*. In `nvmutil`, the first part
|
|
is referred to as *part 0* and the second part as *part 1*.
|
|
|
|
Known compatible PHYs
|
|
---------------------
|
|
|
|
TODO: write a full list her ofe what actual PHYs are known to work.
|
|
|
|
It's probably all of them, but some newer ones might have
|
|
changed the standard by which they are configured. This
|
|
program actively avoids working on files that have
|
|
invalid checksums, on most commands, precisely so that
|
|
the user does not inadvertently use it on incompatible
|
|
files; it is assumed that intel would later change the
|
|
file size and/or checksum value and/or checksum location.
|
|
|
|
How to obtain the GbE file
|
|
==========================
|
|
|
|
The chip containing your BIOS/UEFI firmware (or coreboot) has
|
|
it, if you have an Intel PHY for gigabit ethernet.
|
|
|
|
The sections below will teach you how to obtain the GbE file,
|
|
containing your NIC's configuration. This is the part that
|
|
many people will struggle with, so we will dedicated an
|
|
entire next section to it:
|
|
|
|
Use flashprog
|
|
------------
|
|
|
|
NOTE: Canoeboot standardises on [flashprog](https://flashprog.org/wiki/Flashprog)
|
|
now, as of 3 May 2024, which is a fork of flashrom.
|
|
|
|
If you wish to operate on the GbE section that's already
|
|
flashed, you should *dump* the current full ROM image.
|
|
If you already have a ROM image, you do not need to dump
|
|
it, so you can skip this section.
|
|
|
|
Download flashprog here:
|
|
|
|
* <https://flashprog.org/>
|
|
|
|
Using recent flashprog versions, you can extract this region. If
|
|
your regions are unlocked, you can run flashprog on the target
|
|
system, like so:
|
|
|
|
flashprog -p internal -r rom.bin
|
|
|
|
If your system has two flash chips, the GbE region is usually
|
|
stored on SPI1 (not SPI2). Otherwise, it may be that you have
|
|
a single-flash setup. In that case, it's recommended to dump
|
|
both chips, as `spi1.rom` and `spi2.rom`; you can then cat
|
|
them together:
|
|
|
|
cat spi1.rom spi2.rom > rom.bin
|
|
|
|
If your GbE region is locked (per IFD settings), you can dump
|
|
and flash it using external flashing equipment. The Canoeboot
|
|
project has a handy guide for this; it can be used for reading
|
|
from and writing to the chip. See: [spi.md](spi.md)
|
|
|
|
If you're using an external programmer, the `-p internal`
|
|
option should be changed accordingly. Read flashprog
|
|
documentation, and make sure you have everything
|
|
properly configured.
|
|
|
|
Use ifdtool
|
|
-----------
|
|
|
|
NOTE: This has only been tested on systems that use IFDv1
|
|
(Intel Flash Descriptor, version 1). This distinction, between
|
|
v1 and v2, is made in the `ifdtool` source code, which you
|
|
should read if you're interested. Intel`s v2 specification
|
|
has more regions in it, whereas v1 systems usually
|
|
defined: IFD, GbE, PD, ME and BIOS regions.
|
|
|
|
The `ifdtool` program is a powerful tool, allowing you to
|
|
manipulate Intel Flash Descriptors. It's part of coreboot,
|
|
available in the `coreboot.git` repository
|
|
under `util/ifdtool/`. Just go in there and build it
|
|
with `make`, to get an ifdtool binary.
|
|
|
|
To make internal flashing possible later on, you might do:
|
|
|
|
ifdtool --unlock rom.bin
|
|
|
|
Running this command will create a modified image,
|
|
named `rom.bin.new`. This file will have all regions set
|
|
to read-write, per configuration in the Intel Flash Descriptor.
|
|
|
|
In addition to unlocked regions, you may wish to *neuter* the
|
|
Intel Management Engine, removing all the nasty spying features
|
|
from it, using `me_cleaner`. See:
|
|
|
|
* <https://github.com/corna/me_cleaner>
|
|
* Also available in `coreboot.git`, undir `util/`
|
|
|
|
The `me_cleaner` program is outside the scope of this
|
|
article, so you should read their documentation.
|
|
|
|
Now run this:
|
|
|
|
ifdtool -x rom.bin
|
|
|
|
Several files will be created, and the one you need to
|
|
operate on is named `flashregion_3_gbe.bin` so please
|
|
ensure that you have this file.
|
|
|
|
Read the notes below about how to use the `nvmutil` program,
|
|
operating on this file. When you're done, you can insert the
|
|
modified GbE file back into your ROM image, like so:
|
|
|
|
ifdtool -i gbe:flashregion_3_gbe.bin rom.bin
|
|
|
|
This will create the file `rom.bin.new`, which contains
|
|
your modified GbE section with the NVM images inside; this
|
|
includes your MAC address.
|
|
|
|
Refer to flashprog documentation. You may flash the new ROM
|
|
like so, if running on the same system and the regions are
|
|
read-write:
|
|
|
|
flashprog -p internal -w rom.bin.new
|
|
|
|
Newer versions of flashprog support flashing just the specified
|
|
region, like so:
|
|
|
|
flashprog -p internal --ifd -i gbe -w rom.bin.new
|
|
|
|
If you're running flashprog from host CPU on the target
|
|
system, and it's dual flash, you can just flash the
|
|
concatenated image, which you created earlier by running
|
|
the `cat` program; dual-IC flash configurations appear to
|
|
your operating system as one large flash area, as though
|
|
it were a single chip.
|
|
|
|
If you're using an external programmer, you should change
|
|
the `-p internal` parameter to something else. In this
|
|
situation, you should re-split the file accordingly, if
|
|
you have a dual-IC flash set, like so:
|
|
|
|
dd if=rom.bin.new of=spi2.rom bs=1M skip=8
|
|
dd if=rom.bin.new of=spi1.rom bs=1M count=8
|
|
|
|
These files would then be flashed externally, separately,
|
|
using an external programmer.
|
|
|
|
The *above* example (using `dd`) is for setups with 12MB
|
|
flash, where you have 8MB as SPI1 and 4MB as SPI2. SPI1
|
|
would contain the IFD, and SPI2 is the upper flash area
|
|
containing your bootblock; GbE is probably located in
|
|
SPI1. You should adjust the above parameters, according
|
|
to your configuration.
|
|
|
|
How to compile source code
|
|
==========================
|
|
|
|
The nvmutil source code is located under `util/nvmutil/` in the
|
|
cbmk repository. A makefile is included there, for you to build an
|
|
executable.
|
|
|
|
The nvmutil programs will work just fine, on any modern BSD Unix operating
|
|
system, or unix-like system such as GNU+Linux.
|
|
|
|
You must be sure to have toolchains installed, for
|
|
building; a normal libc, C compiler and linker should be enough.
|
|
GCC and LLVM have all these things included, so use whichever one
|
|
you want.
|
|
|
|
If the code is compiled on OpenBSD,
|
|
[pledge(2)](https://man.openbsd.org/pledge.2) is used.
|
|
This is done with an `ifdef` rule, so that the code still compiles
|
|
on other systems. When the `dump` command is specified, pledge
|
|
will use these promises: `stdio rpath`. When any other command
|
|
is used, these pledge promises will be used: `stdio wpath`.
|
|
|
|
The `nvmutil` software has been build-tested on `Clang`, `GCC`
|
|
and `tcc`. Only standard library functions (plus `err.h`) are
|
|
used, so you don't need any extra libraries.
|
|
|
|
How to compile it
|
|
-----------------
|
|
|
|
First, ensure that the current working directory is your
|
|
copy of the nvmutil source code!
|
|
|
|
You may run this in your terminal:
|
|
|
|
make
|
|
|
|
This will result in a binary being created named `nvm`.
|
|
Install this to wherever you want, such as `/usr/bin` (or
|
|
whatever is in your `$PATH` for userspace programs).
|
|
|
|
TODO: Add `make install` to the Makefile, portably.
|
|
|
|
How to use nvmutil
|
|
==================
|
|
|
|
You run it, passing as argument the path to a file, and you run
|
|
commands on that file. This section will tell you how to
|
|
perform various tasks, by using these commands.
|
|
|
|
In these examples, it is assumed that you have installed
|
|
the `nvm` binary to somewhere in your `$PATH`. If you haven't
|
|
done that, you could still run it in cwd for instance:
|
|
|
|
./nvm bla bla bla
|
|
|
|
Exit status
|
|
-----------
|
|
|
|
The `nvmutil` program uses `errno` extensively. The best error
|
|
handling is done this way, the Unix way. Error handling is extremely
|
|
strict, in nvmutil; on program exit, the errno message is printed (if not
|
|
zero) and the value of errno is returned (upon exit from `int main`).
|
|
|
|
The `main` function always returns `errno`, no matter what. This style
|
|
of programming (set errno and return) is a very old fashioned way of
|
|
doing things, and in many cases it is the most *correct* way.
|
|
|
|
This is why we say `zero status` and `non-zero status` in Unix
|
|
programs, when we talk about exit status. Zero is success, and
|
|
anything above zero is fail; errno is zero by default, unless
|
|
set, and it will always be set to a value above zero (if set).
|
|
|
|
All commands (except `dump`) require read and write access. The `dump`
|
|
command only requires read access on files. Where sufficient permission
|
|
is not given (read and/or write), nvmutil will exit with non-zero status.
|
|
|
|
Non-zero status will also be returned, if the target file is *not*
|
|
of size *8KB*.
|
|
|
|
Additional rules regarding exit status shall apply, depending on
|
|
what command you use. Commands are documented in the following sections:
|
|
|
|
Change MAC address
|
|
------------------
|
|
|
|
The `nvm` program lets you change the MAC address. It sets
|
|
a valid checksum, after changing the MAC address. This program
|
|
operates on *both* NVM parts, but it will only modify a given
|
|
part if the existing checksum is correct. It will exit with zero
|
|
status if at least one part is modified; otherwise, it will
|
|
exit with non-zero status.
|
|
|
|
The following rules are enforced in code:
|
|
|
|
* User cannot specify multicast addresses
|
|
* User cannot specify `00:00:00:00:00:00`
|
|
* When generating random addresses, if the right
|
|
most nibble of the left-most byte is `?` (random),
|
|
nvmutil will (in code) force the generated MAC
|
|
address to be local (not global), and will prevent
|
|
a multicast address from being generated.
|
|
|
|
A multicast address is invalid because it represents
|
|
multiple devices; you must specify a unicast address.
|
|
A global address is one uniquely assigned by the vendor,
|
|
and a local address is an overridden one. You *can* set
|
|
global MAC addresses in nvmutil, for example if you are
|
|
simply copying what was officially assigned to your NIC,
|
|
you can do that. For example, if your MAC address
|
|
was `00:de:ad:be:ef:69` as assigned by the manufacturer,
|
|
which is a global unicast MAC address, you would type:
|
|
|
|
nvm gbe.bin setmac 00:de:ad:be:ef:69
|
|
|
|
How to use (the MAC address in just an example):
|
|
|
|
nvm gbe.bin setmac 00:de:ad:be:ef:00
|
|
|
|
You can also set random MAC addresses:
|
|
|
|
nvm gbe.bin setmac ??:??:??:??:??:??
|
|
|
|
In this example, every character is random. However, you
|
|
can mix and match random characters with static ones. For
|
|
example:
|
|
|
|
nvm gbe.bin setmac 00:1f:16:??:??:??
|
|
|
|
You can also pass it without a MAC address:
|
|
|
|
nvm gbe.bin setmac
|
|
|
|
If you only type `setmac` without specifying a MAC address,
|
|
it will do the same thing as `setmac ??:??:??:??:??:??`.
|
|
|
|
This will set the last three bytes randomly, while the
|
|
MAC address would begin with `00:1f:16`.
|
|
|
|
The *reason* nvmutil doesn't alter a part with an existing
|
|
invalid checksum, is precisely so that if the algorithm
|
|
changes in future Intel PHYs, nvmutil will just fail and
|
|
not modify your file. This is because the checksum would
|
|
then be invalid, at all times. However, correct NVM parts
|
|
with otherwise invalid checksums do exist, and can be
|
|
corrected if you use the `setchecksum` command
|
|
in `nvmutil`. It is common for vendor gbe files to contain
|
|
one valid part and one invalid part, per checksum rules.
|
|
|
|
Verify checksums (and show MAC addresses)
|
|
-----------------------------------------
|
|
|
|
This command *only* requires *read* access on files.
|
|
|
|
The `nvm` program can show a hexdump of both NVM parts, and
|
|
tell you whether each one is valid (as per checksum calculation).
|
|
It also prints the MAC address from each part.
|
|
|
|
How to use:
|
|
|
|
nvm gbe.bin dump
|
|
|
|
NOTE: This will exit with zero status if at least one part
|
|
contains a valid checksum. If both parts are invalid, nvmutil
|
|
will exit with non-zero status.
|
|
|
|
Copy part
|
|
---------
|
|
|
|
This command requires read *and* write access on files.
|
|
|
|
The `nvm` program can copy one NVM part to another. It copies
|
|
the *entire* 4KB part, within the 8KB file.
|
|
|
|
Overwrite part 0 with the contents of part 1:
|
|
|
|
nvm gbe.bin copy 1
|
|
|
|
Overwrite part 1 with the contents of part 0:
|
|
|
|
nvm gbe.bin copy 0
|
|
|
|
NOTE: If the part to be copied has a bad checksum, no operation
|
|
will be performed, and nvmutil will exit with non-zero status.
|
|
Otherwise, it will (if all other conditions are met) exit with
|
|
zero status.
|
|
|
|
Swap parts
|
|
----------
|
|
|
|
This command requires read *and* write access on files.
|
|
|
|
The `nvm` program can swap both 4KB parts in the GbE
|
|
file. It does this, via simple XOR swaps.
|
|
|
|
How to use:
|
|
|
|
nvm gbe.bin swap
|
|
|
|
NOTE: This operation will be aborted if BOTH checksums
|
|
are invalid. This is to guard against accidentally
|
|
using `nvmutil` on the wrong file.
|
|
|
|
If *at least one* part is valid, nvmutil will return
|
|
with zero exit status. If both parts are invalid, it will
|
|
return non-zero.
|
|
|
|
Set valid checksum
|
|
------------------
|
|
|
|
This command requires read *and* write access on files.
|
|
|
|
The `nvm` program can calculate and sets a valid checksum, on
|
|
the desired NVM part. Usage:
|
|
|
|
Fix part 0:
|
|
|
|
nvm gbe.bin setchecksum 0
|
|
|
|
Fix part 1:
|
|
|
|
nvm gbe.bin setchecksum 1
|
|
|
|
*WARNING: NO validity checks are performed. This will simply
|
|
set the checksum. There is no feasible way to guard against
|
|
use on the wrong file, unlike with the other commands. Please
|
|
make SURE you're running this on the correct file!*
|
|
|
|
Set invalid checksum
|
|
--------------------
|
|
|
|
This command requires read *and* write access on files.
|
|
|
|
The `nvm` program can intentionally set an invalid checksum, on
|
|
the desired NVM part. Usage:
|
|
|
|
Invalidate part 0:
|
|
|
|
nvm gbe.bin brick 0
|
|
|
|
Invalidate part 1:
|
|
|
|
nvm gbe.bin brick 1
|
|
|
|
NOTE: If the part already has an invalid checksum, no operation
|
|
will be performed, and nvmutil will exit with non-zero status.
|
|
This is to guard against `nvmutil` being used on the wrong file.
|
|
|
|
This may be desirable, if you've made modifications to both
|
|
parts but you want to guarantee that only one of them is
|
|
used. Also, the `setmac` command will only operate on
|
|
parts that already have a valid checksum, so you could
|
|
run `brick` before running `setmac` (or run it afterwards).
|
|
|
|
The GNU+Linux kernel's `e1000` driver will refuse to initialise
|
|
Intel gigabit NICs that don't have a valid checksum. This
|
|
is software-defined, and not enforced by the hardware.
|
|
|
|
LICENSE
|
|
=======
|
|
|
|
This page is released under different copyright terms than most other pages
|
|
on this website.
|
|
|
|
The `nvmutil` software and documentation are released under the following
|
|
terms:
|
|
|
|
Copyright 2022 Leah Rowe
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|