Compare commits

...

127 Commits

Author SHA1 Message Date
Leah Rowe 489a81eb6d Merge pull request 'fix smbios_product_name for t1700 mt and sff' (#452) from Ronanand0/lbmk:fix-smbios-prod-name-for-t1700 into master
Reviewed-on: https://codeberg.org/libreboot/lbmk/pulls/452
2026-09-18 12:23:58 +02:00
Ronanand0 272e306ba2 Update config/coreboot/t1700sff_bmrc_12mb/config/libgfxinit_txtmode 2026-09-18 11:14:03 +02:00
Ronanand0 f1f7fa2925 Update config/coreboot/t1700mt_bmrc_12mb/config/libgfxinit_txtmode 2026-09-18 11:13:11 +02:00
Ronanand0 9e189bbd06 Update config/coreboot/t1700mt_bmrc_12mb/config/libgfxinit_corebootfb 2026-09-18 11:12:28 +02:00
Ronanand0 688e541c58 Update config/coreboot/t1700sff_bmrc_12mb/config/libgfxinit_corebootfb 2026-09-18 11:10:47 +02:00
Leah Rowe 387e6dd771 mk: much safer forx loop
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 21:14:08 +01:00
Leah Rowe a0951d1127 minor cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 11:06:12 +01:00
Leah Rowe f59e5d8e2b rom.sh: remove redundant check
if_build / empty mode are a given here, since this
is a premake function which only executes if
the mode string is empty and/or if_build is empty

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:55:19 +01:00
Leah Rowe 4530c6f2e3 rom.sh: put coreboot dry checks in mkhelper
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:52:52 +01:00
Leah Rowe e0714ad929 rom.sh: check grub dry build in mkhelper
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:46:53 +01:00
Leah Rowe 058a70a16e pcsx-redux: check dry build in mkhelper
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:45:16 +01:00
Leah Rowe e1c2525783 lib.sh: make build_sbase a macro
sh macros are cool

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:40:55 +01:00
Leah Rowe 69875b8e10 xbmk: general cleanup
note: mecleaner check removed in vendor.sh, because
it's already guaranteed to be fetched. the check will
never indicate failure, so we can just assume that
the me cleaner python script exists.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:33:43 +01:00
Leah Rowe 1722964f66 mk: add safety check for grep -o usage
very unlikely not to have it, but we deal in
certainty, not rm -Rf /

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:33:43 +01:00
Leah Rowe 63596046d1 rom.sh: simplify add_uboot
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 10:33:36 +01:00
Leah Rowe 40b120c26b remove ccache from dependencies
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 07:23:18 +01:00
Leah Rowe bf654d4c19 rom.sh: just remove the coreboot cook function
ccache isn't used at all in any of the configs

ensuring that this remains the case is much
cleaner. coreboot will never enable it by default,
precisely because of how buggy it is.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 07:20:25 +01:00
Leah Rowe 94ff1ec49a inject.sh: simplify variable init and end message
the modified/not message is pointless, because the
message indicating tarball rebuild will suffice

variable initialisation simplified (global newvar)

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 02:22:11 +01:00
Leah Rowe 08021d71c2 rom.sh: simplify add_uboot
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 02:06:00 +01:00
Leah Rowe 856551a36d mk: add forx function for shorthand loops
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 01:53:56 +01:00
Leah Rowe 7c025e1036 release.sh: remove -m option
-m src can skip building binaries

this is pointless. i always want them.

i won't use it, and i'm the only person
who will ever use ./mk release

i'm going to add a -t option in the future
to allow e.g. ./mk -t coreboot

this would do -f but create a tarball of
the source, versioned. e.g.
coreboot-libreboot-27.05_src.tar.xz

or something like that. this would allow
more granular control, if you just want to
get sources.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-17 01:13:36 +01:00
Leah Rowe 60a2f5cbff rom.sh: disable ccache on coreboot builds
this fixes a build issue i was having on ./mk release,
and it's also a preventative bug fix.

instead of forcing it to be enabled, we now force
it to be disabled. all current configs already disable
it, and disabled is the default.

just in case, disable it by force. i encountered build
errors on ./mk release, due to stale build artifacts.

i had no issues on normal lbmk.git, doing builds, but
./mk release builds everything in bulk. we want the
release build process to be as reliable as possible.

this won't actually affect build speed much, due to
lbmk's design (clean builds before running make).

work is needed upstream, to make ccache more reliable.
ccache is fine when you're re-building the same board
a lot, but there's just no way it can be used reliably
when building lots of very different boards, where the
code greatly differs in coreboot.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 23:27:53 +01:00
Leah Rowe 3b565ce056 vendor.sh: minor cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 21:06:39 +01:00
Leah Rowe 089875ac1f mk: error handling on command -v
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 11:43:58 +01:00
Leah Rowe 2dc01a93b9 mk: tidy up xbmk_sanitize_version
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 11:21:56 +01:00
Leah Rowe cebae0ed80 mk: rename autoconfargs to configureargs
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 10:58:00 +01:00
Leah Rowe d165f14a4d mk: general cleanup and awk appreciation
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 10:39:52 +01:00
Leah Rowe 5afd77433d mk: tidy up handle_defconfig
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 09:41:40 +01:00
Leah Rowe 08ec187842 wip
defconfig file test unnecessary in check_defconfig
because it's already checked in handle_defconfig

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 09:25:55 +01:00
Leah Rowe 2dc4a4d16b mk: clean up run_make_command_real
merge check_cmake with run_make_command_real

tidied up some redundant checks

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 07:54:16 +01:00
Leah Rowe ca55077032 mk: tidy up check_cmake
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 07:25:31 +01:00
Leah Rowe 113dac006f variable ./mk location, based on user input
when calling ./mk, or from PATH, an absolute path
is created to ./mk

this will likely be different than mk, but it might
be a different script. perhaps the operator is making
a copy of the mk script temporarily - obviously not
advised, no, but here we have a problem because then
lbmk is still running ./mk everywhere

run arg0 instead, now called "mk"

./mk is still hardcoded in release.sh, because we
do need to make sure we're using the right script
there

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-16 05:52:06 +01:00
Leah Rowe 88887c0163 mk: fix check_cross_compiler call
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 22:15:16 +01:00
Leah Rowe 0c41ea82dd mk: move config back to getopt
really pointless doing it here. do it in the loop.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 22:10:37 +01:00
Leah Rowe bbc56b714b fix build error on no-makefile projects
e.g. biosutilities

the subshell screws up error handling. this
patch changes it to old behaviour.

some projects don't have makefiles. the
non-zero exit also prevents further call
to copy_elf when no binaries are created,
as in this example.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 21:17:10 +01:00
Leah Rowe 6a5b4c98d6 mk: clean up getopt flags
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 21:11:51 +01:00
Leah Rowe 50eec6d485 mk: simplify single_tree_build
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 20:58:40 +01:00
Leah Rowe 40b1a3e0bb Revert "init.sh: re-initialise upstream src .git"
This reverts commit cf079dbd17.

we don't need it anymore. we don't bother cleaning sources
for releases, because tehy're never dirtied. we build
using ./mk release which does everything fresh.

the git-clean feature was only used on ./mk -c, which was
removed because it's not needed for the same reason as
above. lbmk always cleans and re-builds everything when
metadata changes, otherwise storing builds out of tree
in a cache directory.

get rid of this dead code.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 20:42:33 +01:00
Leah Rowe 59cbc1784c mk: remove -c and -x commands (clean/xgcc-clean)
the user never runs these. it's not needed. the design
of lbmk already cleans everything, or caches everything,
between builds. everything cached out of tree.

it's not expected to ever need to clean manually, so just
remove the option. knobs are for nobs.

releases don't need it either, because we tar everything
before building, thus eliminating all build artifacts.
we do this on a fresh copy of lbmk on ./mk release

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 20:38:08 +01:00
Leah Rowe 6725b616f3 mk: skip build if makefile check fails
this was the previous behaviour, and prevents
single-tree builds from proceeding with
use of copy_elf

otherwise you get a bunch of build errors

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 20:24:08 +01:00
Leah Rowe 7507655d34 simplified make-clean handling
no point using distclean, because the context there
is providing clean sources for distribution, but we
use ./mk release which tars everything up before ever
running any build commands.

make-clean is enough

distclean is a stupid gnuism anyway, and most makefiles
that have it will just do the same as clean anyway

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 20:20:03 +01:00
Leah Rowe 2aad50cd59 even more tidy up run_make_command
tidy it all the way up

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 19:51:55 +01:00
Leah Rowe f7b9c9e410 mk: tidy up run_make_command
yeah, this reverses the last change

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 19:03:39 +01:00
Leah Rowe 4878cec84d mk: optimise make-clean check
only check makefiles if if_not_make_clean is set

this avoids unnecessary disk usage

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 18:06:52 +01:00
Leah Rowe 04be963383 mk: remove unnecessary check
on dry builds, if_not_make_clean will also be empty

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 18:06:14 +01:00
Leah Rowe 5043b6dc97 mk: abuse an absurd number of sh macros
just the right amount of absurd

this is why i don't need to use python

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 17:08:05 +01:00
Leah Rowe a65d804f1e add dir check
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 10:37:06 +01:00
Leah Rowe cf079dbd17 init.sh: re-initialise upstream src .git
we have git-clean in use for projects, but that
only affects lbmk.git

now we re-initialise .git in upstream projects,
when .git is missing. this ensures consistent
cleaning behaviour between lbmk.git and the
libreboot releases.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 10:32:38 +01:00
Leah Rowe 828578cc57 mk: use correct elddir for coreboot xgcc
in practise, it was always correct because on projects
that used coreboot xgcc, the tree would always be called
default.

however, this is a bug. the logic uses a correct directory
name for coreboot in src/, but not elf/

this patch makes the two consistent, programattically.

this is therefore a preventative bugfix.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-15 09:16:28 +01:00
Leah Rowe 7cb4cdf0f2 mk: turn on git-clean by default, except coreboot
libreboot's policy is to thoroughly clean sources per
build, because we cache builds out of tree and avoid
re-builds if they exist; these and the sources are
deleted if metadata in config/ changes per project,
tree and/or target.

the problem is that this change only affects lbmk.git

it doesn't affect release archives, where project sources
do not have git-init applied to them. this will be
addressed.

can't use it on coreboot, because it will delete xgcc
tarballs in a way currently not handled, and handling
it will mean adding a project-specific hack.

the xgcc tarballs could be built out-of-tree, and this
will have to be done, otherwise coreboot will have to be
made gitclean="y" for now.

everything else is fair game.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 18:01:57 +01:00
Leah Rowe 300f2cb434 mk: remove u-boot-specific git-clean handling
yes, make it generalised. use a new variable in
mkhelper.cfg, gitclean and gitcleanargs

not enabled by default, but u-boot enables it. i'm
considering whether to use this by default, as it
is the general policy of lbmk to clean everything
just after a build, as builds are cached out of
tree. this way, we can do re-builds safely for each
project. there are probably a lot of subtle bugs that
might be fixed if we used this

the problem is that this is currently only used on
lbmk.git, but not on libreboot release archives which
lack .git directories; the main one is initialised in
lbmk, but not in upstream sources. we could just initialise
those.

in fact, that is probably what i'm going to do.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 17:46:34 +01:00
Leah Rowe 2c94101884 mk: remove cleanargs from git-clean
totally worthless

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 17:35:19 +01:00
Leah Rowe 08f93ec812 mk: redirect readlink err to /dev/null
i had this before. forgot to add it in the new
design. oops.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 13:23:10 +01:00
Leah Rowe e99be6e5dc mk: ruthlessly simplify findpath()
i love eval, printf and awk

eval, printf and awk are the best things ever

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 12:47:01 +01:00
Leah Rowe e075a79867 err even louder
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 12:27:42 +01:00
Leah Rowe cd52750fec mk: further simplify err()
yes, just awk everything, double-quoted

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 12:25:35 +01:00
Leah Rowe f115bdfe37 mk: add error check on xbmkpwd init
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 12:19:08 +01:00
Leah Rowe 76bf71ff65 mk: simplified findpath()
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 12:08:53 +01:00
Leah Rowe c4695497f5 mk: simplified error functions
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:54:52 +01:00
Leah Rowe d9ca4265ef mk: remove xprintf
totally useless function. all it does is print
quotes. just printf the args into awk

this does literally the same thing. the output
will literally be the same.

unclear thinking == unclear code

right thinking == this patch

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:45:28 +01:00
Leah Rowe b32dd39262 move findpath and err functions to mk
otherwise, it's totally broken. i also now include
lib.sh later.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:37:34 +01:00
Leah Rowe c6900c8571 init.sh: remove redundant sha512sum init
it's done in xbmk_init. the initial value
is never used.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:33:15 +01:00
Leah Rowe c0402ef642 mk: simplify xbmkpwd initialisation
do it from mk instead. we don't need to run pwd
anymore, because we just get the path and cd
to it, setting that as the path.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:30:49 +01:00
Leah Rowe 16e04411f2 mk: include lib.sh earlier
this means we can now cd to wrkdir using findpath,
and it means the cd command can be wrapped in x_

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:11:04 +01:00
Leah Rowe b09cd4ada4 mk: call xbmk_init through x_
the function never returns 1 at the moment, but
this is a useful future trap.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:07:56 +01:00
Leah Rowe abee462f2a mk: run xbmk_init here, not from init.sh
it should be clear on first reading, what the actual
control flow is. hiding the call in init.sh obscures
first reading.

now it is absolutely clear on first reading, that
xbmk_init is called before going through everything
else in mk.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 11:07:24 +01:00
Leah Rowe cb49e77947 delete straggler
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 10:09:22 +01:00
Leah Rowe 93b49afa3f mk: remove gcc/gnat matching logic (obsolete)
coreboot has this now:

commit c421847fe2fef61586eb313206a4be0f2e491974
Author: Matt DeVillier <matt.devillier@gmail.com>
Date:   Mon Dec 29 10:12:17 2025 -0600

    util/crossgcc: Fix GNAT detection for gnat-15

this one is advisory instead, telling the user to
create such a symlink as we did. this is much less
invasive.

our own check was bad, because it basically silences
what is otherwise an error. coreboot's approach is
more correct, so we will defer to that instead.

note that this means older coreboot (for fam15h) is
no longer covered, but those trees don't use gnat
anyway as libgfxinit is unused on those targets

this lbmk patch removes 61 sloc of dead code, which
makes me very happy.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 10:05:16 +01:00
Leah Rowe 6c3791ce81 mk: rename trees() to main()
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 09:33:30 +01:00
Leah Rowe d17b06f589 merge tree.sh into mk
mk is so tiny now, and will likely never get
bigger. tree.sh is effectively the main script
now, so let's treat it as such.

i'll start splitting tree.sh instead. e.g.
move gcc setup to its own file.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 09:26:37 +01:00
Leah Rowe 2fc37b4b47 use -mindepth alongside -maxdepth in find
use of maxdepth 1 does not exclude the main
directory, which is undesired in these contexts,
though excluded in practise due to how find is
actually used.

technically, mindepth should be used, just in
case, as a defensive measure. the context here
is files and directories within a main directory,
used as arguments in other commands.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 08:48:16 +01:00
Leah Rowe 4ebede5b99 tree.sh: fix globbing in multi-tree command args
this solves a bug that does not yet manifest, because
this bug *can't* currently trigger any error due to
lbmk's design. this is therefore a preventative fix,
for reasons that will become clear.

we previously put arguments in a variable, in a way
that didn't handle globbing. now we avoid a variable
and use "$@" instead, which solves the problem.

this also means that the main logic in mk can be
cleaner, as trees-specific control logic is now
placed entirely in tree.sh's main.

this means that we can now also wrap x_ around trees()

this was never a problem in the past, because all of
the arguments for trees commands never have globbing;
config names are always e.g. foo_bar, not foo bar

in commands where globbing did need to be handled,
those commands were never trees commands. e.g.
you had ./mk inject filename

yes, this is a design improvement, or a preventative
bug fix. pick your poison.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 08:06:51 +01:00
Leah Rowe a82328904e mk: clean up printf command
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 00:36:10 +01:00
Leah Rowe 823a1fd011 mk: put all includes in one place
the previous design flaw was fixed by recent
refactors, such that i can now . include all
of lbmk at once, and have control logic right
after that.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 00:14:55 +01:00
Leah Rowe 5fb0d1098f mk: simplified command handling
just do includes in mk again. common.sh was stupidly
small, just pointless.

replace the entire command dispatcher with eval, printf
and awk, because i can, and it further reduces sloccount.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-14 00:05:48 +01:00
Leah Rowe dcaa15ab01 common.h: re-order includes
the new order more reliably indicates which order
everything is executed in, by virtue of the functions
provided in each file.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 22:25:15 +01:00
Leah Rowe f5f6464c60 79 lines
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 20:55:30 +01:00
Leah Rowe 74c374a3a2 use awk instead
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 20:38:54 +01:00
Leah Rowe de09b71e0a init.sh: tidy up main loop
the new loop is incredibly novel in nature, and will
break if anyone but me ever touches it. it also
reduces sloccount by two lines.

i did it because i can, and it's perfectly safe.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 20:12:03 +01:00
Leah Rowe eb23cd3de8 split up include/
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 15:33:21 +01:00
Leah Rowe 07ed4e940b more build system cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 15:28:15 +01:00
Leah Rowe ff83f69154 init.sh: remove unnecessary directory check
literally the point of -p in mkdir is to, you know,
check whether the directory already exists

unclear thinking = unclear code

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 14:58:31 +01:00
Leah Rowe 0363bcaa0f fix regression in version check
it occured to me that this style of check was bad. it
only works when checking if both variables are set

my bad

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 14:55:38 +01:00
Leah Rowe 1a9b211368 xbmk: remove xbmkdir()
pointless function. literally pointless. it is literally
the most pointless function ever written in the history
of functions. literally pointless in every possible way.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 14:50:41 +01:00
Leah Rowe e9e33d4b4d lib.sh: always sanitize xbmkver before writing
this removed the need to check it in xbmk_set_version
as it calls update_xbmkver, which in turn performs
the same check.

this increases the general reliability and safety of
xbmk when recording its own version after update.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 14:33:37 +01:00
Leah Rowe 3b37a0b17d lib.sh: simplify update_xbmkver
sanitization can be done with a single sed command

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-13 14:25:09 +01:00
Leah Rowe 77b0b448e2 more cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 19:37:57 +01:00
Leah Rowe c7fb6a2bc8 get.sh: remove redundant check
we don't pull anything from supermicro's site.
we did briefly, in an earlier port for that
one supermicro board.

don't maintain dead code. dead code has one purpose:
be deleted.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 18:12:36 +01:00
Leah Rowe 2d1d7624e9 get.sh: add try_fetch_copy function
just a skeleton that calls the curl function

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 15:10:44 +01:00
Leah Rowe a32374f6cc more cleanup
this will be the last time, i promise

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 14:29:11 +01:00
Leah Rowe 897c2667af get.sh: even more cleanup (simplified fetch)
fetch_submodule now contains just the right amount
of eval, which means all of the eval.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 13:24:13 +01:00
Leah Rowe 446eca846e get.sh: further cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 12:49:12 +01:00
Leah Rowe c3e2d8c8bc get.sh: simplify xbget
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 11:19:42 +01:00
Leah Rowe b094c60a39 more variable cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 09:02:04 +01:00
Leah Rowe 798cc79399 mk: export locales much earlier
also simplify the way it works (eval and awk)

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-12 08:49:53 +01:00
Leah Rowe 6a2e9a7919 remove include/chromebook.sh import script (not needed)
i will be adding chromebooks, but not using this script,
which is why i never finished the script. i previously
had the plan to patch upstream coreboot, by importing
patches from mrchromebox, but that results in an extreme
number of patches. several hundred patches, in fact.

more efficient is to add multi-upstream support in
include/get.sh, for using different upstreams including
forks, on a given multi-tree project. i haven't done
this yet, but this is what will be done, and then
adding each chromebook will be a matter of importing
configs from mrchromebox alongside edk2 integration.

a script will still need to be written, for the initial
import, and imported chromebooks will be set release=n
until and when each target is fully tested.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 21:51:00 +01:00
Leah Rowe d0a1b40910 more cleanup
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 21:43:50 +01:00
Leah Rowe 0fd3d72998 tree.sh: remove redundant TODO
infinite loop detection was here before. i removed it
because it was bloat. we don't take general user input
here, so careful configuration is all we need.

infinite loops are harmless to the user. they are merely
annoying. they would never be introduced to the user,
because configs are always tested before release.
before commit, even.

we can save the user a few watts of electricity, or we
can Keep It Simple.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 19:49:26 +01:00
Leah Rowe 425855899f rom.sh: remove another TODO
this one is unnecessary, because we're not taking general input
from the user. we mitigate this carefully by being, you know,
careful.

implementing the TODO would have bloated the code, in ways that
might only introduce other serious bugs.

the current logic is fine, and great care will always be taken
by me to keep the code safe, while i'm in charge.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 19:46:07 +01:00
Leah Rowe f648167b9f rom.sh: remove redundant TODO
the code is correct. no TODO needed here.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 19:45:14 +01:00
Leah Rowe 36fef51e8f init.sh: universally set git commit/auth date
do it as an export. to avoid pollution elsewhere,
do it inside a subshell.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 19:42:03 +01:00
Leah Rowe b6b5f70934 init.sh: set git committer date as well
only the author date was being set before

with this change, at least on my system, i
now get the same commit ID and date each time
on the following test:

NOTE: . is lbmk (main work directory)
NOTE: here, we are copying the current clone

git clone . lbmktest
cd lbmktest
./mk version
rm -Rf .git
./mk version
git log

same output each time. we have thus eliminated
timestamps as a variable. this is but a part of
in a series of changes that will eventually lead
to libreboot being built reproducibly.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 19:32:12 +01:00
Leah Rowe 58094bd017 init.sh: portable date on git-init
don't even call the date util at all, to fix the
portability issues. now we don't need GNU date
anymore.

git itself can just take an epoch, and it will
do whatever it will do. yes.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 19:28:15 +01:00
Leah Rowe cdd399017e init.sh: don't check PATH on startup
even if i unset PATH before running lbmk, it is
reinitialised because of the shebang. if no PATH
exists, then it's either a broken system and you
have bigger problems, or you have some weird
system that uses something else.

our job is not to fix the world. there was no
scenario in which this check would even trigger
an error or fallback, so just remove it.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 19:02:20 +01:00
Leah Rowe 15204cda63 xbmk: re-introduce condensed if statements
i've been careful to makely only use it on AND operations,
not onse that use OR. a lot of blocks are not condensed,
unlike previously when this design was used.

i removed the condensed design because it made the code
allegedly easier to read, but i found it harder to read
and found the code looked dirty. this change makes it
clean again, but i've done it in a way where the shorthand
conditional statements are easy to understand for most
people. this strikes a compromise; i would go further.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 16:18:09 +01:00
Leah Rowe 8173aea83b xbmk: reintroduce setvar as newvar (init only)
use the simpler logic recently introduced, generalised
but it only sets variables to empty. this is safer than
the previous design, and brings the same reduction in
sloccount overall since i wasn't doing anything other
than emptying variables anyway, when it was used before.

i didn't like the long list of variables inside files,
so this makes everything more readable.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-11 14:24:55 +01:00
Leah Rowe aad748c5ca inject.sh: simplify xbmkcheck initialisation
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 22:49:57 +01:00
Leah Rowe 8db320799b inject.sh: re-order variables
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 22:20:05 +01:00
Leah Rowe 04c3bc53b6 mk: add error exit
not needed at the moment, since we ensure that
the functions always exit with error under fault
condition. they always return zero.

nevertheless, this might catch some unexpected
behaviour in the future.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 20:08:08 +01:00
Leah Rowe d722a02cda mk: remove redundant xrval variable
not needed.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 20:06:46 +01:00
Leah Rowe 6fe1d47fb3 mk: remove redundant set command
we exit immediately afterward, so there's
no point in putting this here.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 20:01:48 +01:00
Leah Rowe 005f1189c1 mk: major code cleanup
we don't need a main here. it's so generic that we
can just leave it really small like it is now. now
it's much clearer what it actually does.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 19:56:36 +01:00
Leah Rowe 86781a5881 mk: simplified command check
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 19:43:28 +01:00
Leah Rowe 61ab5723df xbmk: use proper shebang
env isn't that useful these days. better just
use the standard declaration.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 19:37:16 +01:00
Leah Rowe 6050cdd1db init.sh: much more thorough locale initialisation
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 19:35:17 +01:00
Leah Rowe 8c927b535d update header again
Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 19:28:27 +01:00
Leah Rowe 5f0bd5ea10 xbmk: remove setvars function
only one file used it. i've replaced its use with
a simple awk call alongside eval.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 19:25:45 +01:00
Leah Rowe 8822c56815 mk: make it completely generic
commands now fed from a file, include/common.sh
which in turn also includes other lib files

this makes mk completely generic, and means
that changes will now be completely in sync
with cbmk, ensuring a lack of merge conflicts,
though the file was already pretty small anyway.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 18:05:57 +01:00
Leah Rowe bb0221252c mk: make xbcddir usage clearer
it's always a directory, so filter it first

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 17:47:48 +01:00
Leah Rowe 1ceeb0ab55 update lbmk headers
i made several modificatinos to several files
thus for in 2026, in the main part of the build system.

i've added 2026 to the ones that i modified.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 17:45:11 +01:00
Leah Rowe bb4c038794 cleanup
actually use xbarg0

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 15:03:03 +01:00
Leah Rowe 786cf8cd9c xbmk: allow to run from PATH
now you can put lbmk somewhere on your system,
and symlink to the mk script from PATH

e.g. /usr/local/bin/lbmk -> /home/leah/lbmk/mk

lbmk will cd to itself, including from PATH,
because the string will then be passed through
readlink, which gets the real path.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 14:03:11 +01:00
Leah Rowe 189b61018f xbmk: allow running from outside of work dir
i need only now implement a check for sys dirs
e.g. /etc/lbmk.cfg and check if it defines
e.g. other location for config/ and include/

then mk is a generic dispatcher and i can one
day make mk possible to install. for example, if
you have a bsd ports system and you want to
install lbmk

i could make it check user dirs too, overriding
defaults. for example /usr/local/etc/lbmk, but
then i might have ~/.config/lbmk

you no longer need to be in the xbmk directory
to run xbmk. it'll cd to itself, with this patch

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 13:52:16 +01:00
Leah Rowe e973584123 mk: generalised dispatch loop
with this new function, i can turn commands on and
off by virtue of config. for now, behaviour is
unchanged, but this new design means i will be
able to disable certain commands in child processes

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 13:49:34 +01:00
Leah Rowe afdf8c7733 Revert "xbmk: general code cleanup"
This reverts commit 1b65e8914c.

NOTE: cleanup of xbmk_git_init was retained

this "cleanup" actually made the code harder to read.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-10 12:34:35 +01:00
Leah Rowe 123639e3db delete util/libreboot-utils (unused code)
this was an intense audit of nvmutil that somehow evolved
into writing a new, hardened implementation of mktemp.

it all works, a few memory bugs to solve on bsd, but i don't
see the point in keeping it. mktemp is fine, and nvmutil
already works.

lbutils implemented atomic writes and integrity checking,
in a manner completely overengineered for what it was
actually doing (modifying a few bytes in 8KB GbE files)

just delete it. i'll bring it back if i ever finish the
code. i don't want to leave dead/unfinished code in the tree.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-07 08:12:24 +01:00
Leah Rowe 01cb422c97 include/get.sh: 3-way merge on git am
this will make managing updates easier. which will
be soon, because i have a lot of patches.

no idea why i didn't add this before. normally, i just
copy a directory and git-fetch, then cherry-pick as
i please. this will make it trivial to just update
a revision and merge the patches. then i can just
intervene only when necessary, on a given src tree.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-09-06 10:16:00 +01:00
51 changed files with 1043 additions and 8410 deletions
@@ -21,6 +21,7 @@ CONFIG_OPTION_BACKEND_NONE=y
# CONFIG_USE_CBFS_FILE_OPTION_BACKEND is not set # CONFIG_USE_CBFS_FILE_OPTION_BACKEND is not set
CONFIG_COMPRESS_RAMSTAGE_LZMA=y CONFIG_COMPRESS_RAMSTAGE_LZMA=y
# CONFIG_COMPRESS_RAMSTAGE_LZ4 is not set # CONFIG_COMPRESS_RAMSTAGE_LZ4 is not set
# CONFIG_COMPRESS_RAMSTAGE_ZSTD is not set
CONFIG_SEPARATE_ROMSTAGE=y CONFIG_SEPARATE_ROMSTAGE=y
CONFIG_INCLUDE_CONFIG_FILE=y CONFIG_INCLUDE_CONFIG_FILE=y
CONFIG_COLLECT_TIMESTAMPS=y CONFIG_COLLECT_TIMESTAMPS=y
@@ -99,6 +100,7 @@ CONFIG_VENDOR_DELL=y
# CONFIG_VENDOR_PRODRIVE is not set # CONFIG_VENDOR_PRODRIVE is not set
# CONFIG_VENDOR_PROTECTLI is not set # CONFIG_VENDOR_PROTECTLI is not set
# CONFIG_VENDOR_PURISM is not set # CONFIG_VENDOR_PURISM is not set
# CONFIG_VENDOR_QOTOM is not set
# CONFIG_VENDOR_RAPTOR_CS is not set # CONFIG_VENDOR_RAPTOR_CS is not set
# CONFIG_VENDOR_RAZER is not set # CONFIG_VENDOR_RAZER is not set
# CONFIG_VENDOR_RODA is not set # CONFIG_VENDOR_RODA is not set
@@ -127,7 +129,7 @@ CONFIG_CBFS_SIZE=0xEEE000
CONFIG_CONSOLE_SERIAL=y CONFIG_CONSOLE_SERIAL=y
CONFIG_LINEAR_FRAMEBUFFER_MAX_HEIGHT=2160 CONFIG_LINEAR_FRAMEBUFFER_MAX_HEIGHT=2160
CONFIG_LINEAR_FRAMEBUFFER_MAX_WIDTH=3840 CONFIG_LINEAR_FRAMEBUFFER_MAX_WIDTH=3840
CONFIG_MAX_CPUS=16 CONFIG_MAX_CPUS=8
# CONFIG_ONBOARD_VGA_IS_PRIMARY is not set # CONFIG_ONBOARD_VGA_IS_PRIMARY is not set
CONFIG_POST_DEVICE=y CONFIG_POST_DEVICE=y
CONFIG_POST_IO=y CONFIG_POST_IO=y
@@ -149,19 +151,21 @@ CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt"
CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00 CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00
CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 3040 Micro" CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 3040 Micro"
# CONFIG_CONSOLE_POST is not set # CONFIG_CONSOLE_POST is not set
CONFIG_FSP_FD_PATH="3rdparty/fsp/KabylakeFspBinPkg/Fsp.fd"
CONFIG_MAX_SOCKET=1
CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default" CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default"
CONFIG_CMOS_LAYOUT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.layout" CONFIG_CMOS_LAYOUT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.layout"
CONFIG_MAX_SOCKET=1
CONFIG_BOOT_DEVICE_SPI_FLASH_BUS=0
CONFIG_USE_PM_ACPI_TIMER=y CONFIG_USE_PM_ACPI_TIMER=y
# CONFIG_BOARD_DELL_LATITUDE_E7240 is not set CONFIG_BOOT_DEVICE_SPI_FLASH_BUS=0
# CONFIG_BOARD_DELL_E4300 is not set # CONFIG_BOARD_DELL_E4300 is not set
# CONFIG_BOARD_DELL_E6400 is not set # CONFIG_BOARD_DELL_E6400 is not set
# CONFIG_BOARD_DELL_LATITUDE_E7240 is not set
CONFIG_BOARD_DELL_OPTIPLEX_3040=y CONFIG_BOARD_DELL_OPTIPLEX_3040=y
# CONFIG_BOARD_DELL_OPTIPLEX_780_MT is not set # CONFIG_BOARD_DELL_OPTIPLEX_780_MT is not set
# CONFIG_BOARD_DELL_OPTIPLEX_780_USFF is not set # CONFIG_BOARD_DELL_OPTIPLEX_780_USFF is not set
# CONFIG_BOARD_DELL_OPTIPLEX_9020_SFF is not set # CONFIG_BOARD_DELL_OPTIPLEX_9020_SFF is not set
# CONFIG_BOARD_DELL_OPTIPLEX_9020_MT is not set # CONFIG_BOARD_DELL_OPTIPLEX_9020_MT is not set
# CONFIG_BOARD_DELL_OPTIPLEX_3050 is not set
# CONFIG_BOARD_DELL_LATITUDE_E5420 is not set # CONFIG_BOARD_DELL_LATITUDE_E5420 is not set
# CONFIG_BOARD_DELL_LATITUDE_E5520 is not set # CONFIG_BOARD_DELL_LATITUDE_E5520 is not set
# CONFIG_BOARD_DELL_LATITUDE_E6220 is not set # CONFIG_BOARD_DELL_LATITUDE_E6220 is not set
@@ -205,7 +209,8 @@ CONFIG_GFX_GMA_PANEL_1_ON_EDP=y
CONFIG_DRIVERS_UART_8250IO=y CONFIG_DRIVERS_UART_8250IO=y
CONFIG_PC_CMOS_BASE_PORT_BANK1=0x72 CONFIG_PC_CMOS_BASE_PORT_BANK1=0x72
CONFIG_HEAP_SIZE=0x100000 CONFIG_HEAP_SIZE=0x100000
CONFIG_EC_GPE_SCI=0x50 # CONFIG_BOOTMEDIA_SMM_BWP is not set
# CONFIG_DRIVERS_EFI_FW_INFO is not set
CONFIG_BOARD_ROMSIZE_KB_16384=y CONFIG_BOARD_ROMSIZE_KB_16384=y
# CONFIG_COREBOOT_ROMSIZE_KB_256 is not set # CONFIG_COREBOOT_ROMSIZE_KB_256 is not set
# CONFIG_COREBOOT_ROMSIZE_KB_512 is not set # CONFIG_COREBOOT_ROMSIZE_KB_512 is not set
@@ -249,6 +254,7 @@ CONFIG_SMM_RESERVED_SIZE=0x200000
CONFIG_SMM_MODULE_STACK_SIZE=0x800 CONFIG_SMM_MODULE_STACK_SIZE=0x800
CONFIG_ACPI_BERT_SIZE=0x0 CONFIG_ACPI_BERT_SIZE=0x0
CONFIG_DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ=120 CONFIG_DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ=120
CONFIG_CPU_PT_ROM_MAP_GB=512
CONFIG_PRERAM_CBFS_CACHE_SIZE=0x4000 CONFIG_PRERAM_CBFS_CACHE_SIZE=0x4000
CONFIG_DOMAIN_RESOURCE_32BIT_LIMIT=0xe0000000 CONFIG_DOMAIN_RESOURCE_32BIT_LIMIT=0xe0000000
CONFIG_ACPI_CPU_STRING="CP%02X" CONFIG_ACPI_CPU_STRING="CP%02X"
@@ -266,7 +272,6 @@ CONFIG_SOC_INTEL_I2C_DEV_MAX=6
CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL=0x30 CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL=0x30
CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL=0xc35 CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL=0xc35
CONFIG_FSP_HEADER_PATH="3rdparty/fsp/KabylakeFspBinPkg/Include/" CONFIG_FSP_HEADER_PATH="3rdparty/fsp/KabylakeFspBinPkg/Include/"
CONFIG_FSP_FD_PATH="3rdparty/fsp/KabylakeFspBinPkg/Fsp.fd"
CONFIG_SOC_INTEL_COMMON_DEBUG_CONSENT=0 CONFIG_SOC_INTEL_COMMON_DEBUG_CONSENT=0
CONFIG_INTEL_GMA_BCLV_OFFSET=0xc8254 CONFIG_INTEL_GMA_BCLV_OFFSET=0xc8254
CONFIG_INTEL_GMA_BCLV_WIDTH=16 CONFIG_INTEL_GMA_BCLV_WIDTH=16
@@ -284,6 +289,8 @@ CONFIG_SOC_INTEL_GFX_FRAMEBUFFER_OFFSET=0x0
CONFIG_PCIE_LTR_MAX_SNOOP_LATENCY=0x1003 CONFIG_PCIE_LTR_MAX_SNOOP_LATENCY=0x1003
CONFIG_PCIE_LTR_MAX_NO_SNOOP_LATENCY=0x1003 CONFIG_PCIE_LTR_MAX_NO_SNOOP_LATENCY=0x1003
CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH=0 CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH=0
CONFIG_RAMSTAGE_CBFS_CACHE_SIZE=0x4000
CONFIG_CBFS_CACHE_ALIGN=8
CONFIG_SOC_INTEL_COMMON_SKYLAKE_BASE=y CONFIG_SOC_INTEL_COMMON_SKYLAKE_BASE=y
CONFIG_SOC_INTEL_KABYLAKE=y CONFIG_SOC_INTEL_KABYLAKE=y
CONFIG_SKYLAKE_SOC_PCH_H=y CONFIG_SKYLAKE_SOC_PCH_H=y
@@ -293,7 +300,7 @@ CONFIG_SKYLAKE_SOC_PCH_H=y
CONFIG_FSP_T_LOCATION=0xfffe0000 CONFIG_FSP_T_LOCATION=0xfffe0000
CONFIG_SOC_INTEL_COMMON_BLOCK_P2SB=y CONFIG_SOC_INTEL_COMMON_BLOCK_P2SB=y
CONFIG_FIXED_SMBUS_IO_BASE=0xefa0 CONFIG_FIXED_SMBUS_IO_BASE=0xefa0
CONFIG_CBFS_CACHE_ALIGN=8 CONFIG_UART_BITBANG_TX_DELAY_MS=5
CONFIG_SOC_INTEL_COMMON=y CONFIG_SOC_INTEL_COMMON=y
# #
@@ -431,7 +438,6 @@ CONFIG_UDELAY_TSC=y
CONFIG_TSC_MONOTONIC_TIMER=y CONFIG_TSC_MONOTONIC_TIMER=y
CONFIG_TSC_SYNC_MFENCE=y CONFIG_TSC_SYNC_MFENCE=y
CONFIG_HAVE_SMI_HANDLER=y CONFIG_HAVE_SMI_HANDLER=y
CONFIG_CPU_PT_ROM_MAP_GB=512
CONFIG_SMM_TSEG=y CONFIG_SMM_TSEG=y
CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS=8 CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS=8
CONFIG_AP_STACK_SIZE=0x800 CONFIG_AP_STACK_SIZE=0x800
@@ -500,7 +506,6 @@ CONFIG_ARCH_ALL_STAGES_X86_32=y
CONFIG_RESERVED_PHYSICAL_ADDRESS_BITS_SUPPORT=y CONFIG_RESERVED_PHYSICAL_ADDRESS_BITS_SUPPORT=y
CONFIG_X86_TOP4G_BOOTMEDIA_MAP=y CONFIG_X86_TOP4G_BOOTMEDIA_MAP=y
CONFIG_POSTRAM_CBFS_CACHE_IN_BSS=y CONFIG_POSTRAM_CBFS_CACHE_IN_BSS=y
CONFIG_RAMSTAGE_CBFS_CACHE_SIZE=0x4000
CONFIG_PC80_SYSTEM=y CONFIG_PC80_SYSTEM=y
CONFIG_HAVE_CMOS_DEFAULT=y CONFIG_HAVE_CMOS_DEFAULT=y
CONFIG_POSTCAR_STAGE=y CONFIG_POSTCAR_STAGE=y
@@ -564,6 +569,8 @@ CONFIG_INTEL_GMA_ADD_VBT=y
# CONFIG_SOFTWARE_I2C is not set # CONFIG_SOFTWARE_I2C is not set
CONFIG_I2C_TRANSFER_TIMEOUT_US=500000 CONFIG_I2C_TRANSFER_TIMEOUT_US=500000
CONFIG_RESOURCE_ALLOCATION_TOP_DOWN=y CONFIG_RESOURCE_ALLOCATION_TOP_DOWN=y
CONFIG_DRAM_SUPPORT_DDR4=y
CONFIG_DRAM_SUPPORT_DDR3=y
# end of Devices # end of Devices
# #
@@ -571,8 +578,8 @@ CONFIG_RESOURCE_ALLOCATION_TOP_DOWN=y
# #
CONFIG_CRB_TPM_BASE_ADDRESS=0xfed40000 CONFIG_CRB_TPM_BASE_ADDRESS=0xfed40000
# CONFIG_DRIVERS_EFI_VARIABLE_STORE is not set # CONFIG_DRIVERS_EFI_VARIABLE_STORE is not set
# CONFIG_DRIVERS_EFI_FW_INFO is not set
# CONFIG_ELOG is not set # CONFIG_ELOG is not set
# CONFIG_DRIVERS_HWID_DMI is not set
CONFIG_CACHE_MRC_SETTINGS=y CONFIG_CACHE_MRC_SETTINGS=y
CONFIG_MRC_SETTINGS_PROTECT=y CONFIG_MRC_SETTINGS_PROTECT=y
# CONFIG_DRIVERS_OPTION_CFR is not set # CONFIG_DRIVERS_OPTION_CFR is not set
@@ -610,6 +617,7 @@ CONFIG_USE_FSP_NOTIFY_PHASE_READY_TO_BOOT=y
CONFIG_USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE=y CONFIG_USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE=y
# CONFIG_DISPLAY_FSP_TIMESTAMPS is not set # CONFIG_DISPLAY_FSP_TIMESTAMPS is not set
# CONFIG_BUILDING_WITH_DEBUG_FSP is not set # CONFIG_BUILDING_WITH_DEBUG_FSP is not set
CONFIG_FSP_VGA_MODE12_BPP=0x0
CONFIG_INTEL_GMA_ACPI=y CONFIG_INTEL_GMA_ACPI=y
CONFIG_VBT_CBFS_COMPRESSION_LZMA=y CONFIG_VBT_CBFS_COMPRESSION_LZMA=y
# CONFIG_VBT_CBFS_COMPRESSION_LZ4 is not set # CONFIG_VBT_CBFS_COMPRESSION_LZ4 is not set
@@ -670,7 +678,6 @@ CONFIG_PLATFORM_HAS_DRAM_CLEAR=y
CONFIG_BOOTMEDIA_LOCK_NONE=y CONFIG_BOOTMEDIA_LOCK_NONE=y
# CONFIG_BOOTMEDIA_LOCK_CONTROLLER is not set # CONFIG_BOOTMEDIA_LOCK_CONTROLLER is not set
# CONFIG_BOOTMEDIA_LOCK_CHIP is not set # CONFIG_BOOTMEDIA_LOCK_CHIP is not set
# CONFIG_BOOTMEDIA_SMM_BWP is not set
# end of Security # end of Security
CONFIG_ACPI_HAVE_PCAT_8259=y CONFIG_ACPI_HAVE_PCAT_8259=y
@@ -811,6 +818,9 @@ CONFIG_DECOMPRESS_OFAST=y
# Boot Logo Configuration # Boot Logo Configuration
# #
# CONFIG_BMP_LOGO is not set # CONFIG_BMP_LOGO is not set
CONFIG_PLATFORM_POST_RENDER_DELAY_SEC=5
CONFIG_PLATFORM_OFF_MODE_CHARGING_INDICATOR_LOGO_PATH="3rdparty/blobs/mainboard/$(MAINBOARDDIR)/off_mode_charging.bmp"
# CONFIG_FRAMEBUFFER_SPLASH_TEXT is not set
# end of Boot Logo Configuration # end of Boot Logo Configuration
CONFIG_WARNINGS_ARE_ERRORS=y CONFIG_WARNINGS_ARE_ERRORS=y
@@ -21,6 +21,7 @@ CONFIG_OPTION_BACKEND_NONE=y
# CONFIG_USE_CBFS_FILE_OPTION_BACKEND is not set # CONFIG_USE_CBFS_FILE_OPTION_BACKEND is not set
CONFIG_COMPRESS_RAMSTAGE_LZMA=y CONFIG_COMPRESS_RAMSTAGE_LZMA=y
# CONFIG_COMPRESS_RAMSTAGE_LZ4 is not set # CONFIG_COMPRESS_RAMSTAGE_LZ4 is not set
# CONFIG_COMPRESS_RAMSTAGE_ZSTD is not set
CONFIG_SEPARATE_ROMSTAGE=y CONFIG_SEPARATE_ROMSTAGE=y
CONFIG_INCLUDE_CONFIG_FILE=y CONFIG_INCLUDE_CONFIG_FILE=y
CONFIG_COLLECT_TIMESTAMPS=y CONFIG_COLLECT_TIMESTAMPS=y
@@ -99,6 +100,7 @@ CONFIG_VENDOR_DELL=y
# CONFIG_VENDOR_PRODRIVE is not set # CONFIG_VENDOR_PRODRIVE is not set
# CONFIG_VENDOR_PROTECTLI is not set # CONFIG_VENDOR_PROTECTLI is not set
# CONFIG_VENDOR_PURISM is not set # CONFIG_VENDOR_PURISM is not set
# CONFIG_VENDOR_QOTOM is not set
# CONFIG_VENDOR_RAPTOR_CS is not set # CONFIG_VENDOR_RAPTOR_CS is not set
# CONFIG_VENDOR_RAZER is not set # CONFIG_VENDOR_RAZER is not set
# CONFIG_VENDOR_RODA is not set # CONFIG_VENDOR_RODA is not set
@@ -125,7 +127,7 @@ CONFIG_FMDFILE=""
CONFIG_MAINBOARD_VENDOR="Dell Inc." CONFIG_MAINBOARD_VENDOR="Dell Inc."
CONFIG_CBFS_SIZE=0xEEE000 CONFIG_CBFS_SIZE=0xEEE000
CONFIG_CONSOLE_SERIAL=y CONFIG_CONSOLE_SERIAL=y
CONFIG_MAX_CPUS=16 CONFIG_MAX_CPUS=8
# CONFIG_ONBOARD_VGA_IS_PRIMARY is not set # CONFIG_ONBOARD_VGA_IS_PRIMARY is not set
CONFIG_POST_DEVICE=y CONFIG_POST_DEVICE=y
CONFIG_POST_IO=y CONFIG_POST_IO=y
@@ -147,19 +149,21 @@ CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt"
CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00 CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00
CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 3040 Micro" CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 3040 Micro"
# CONFIG_CONSOLE_POST is not set # CONFIG_CONSOLE_POST is not set
CONFIG_FSP_FD_PATH="3rdparty/fsp/KabylakeFspBinPkg/Fsp.fd"
CONFIG_MAX_SOCKET=1
CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default" CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default"
CONFIG_CMOS_LAYOUT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.layout" CONFIG_CMOS_LAYOUT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.layout"
CONFIG_MAX_SOCKET=1
CONFIG_BOOT_DEVICE_SPI_FLASH_BUS=0
CONFIG_USE_PM_ACPI_TIMER=y CONFIG_USE_PM_ACPI_TIMER=y
# CONFIG_BOARD_DELL_LATITUDE_E7240 is not set CONFIG_BOOT_DEVICE_SPI_FLASH_BUS=0
# CONFIG_BOARD_DELL_E4300 is not set # CONFIG_BOARD_DELL_E4300 is not set
# CONFIG_BOARD_DELL_E6400 is not set # CONFIG_BOARD_DELL_E6400 is not set
# CONFIG_BOARD_DELL_LATITUDE_E7240 is not set
CONFIG_BOARD_DELL_OPTIPLEX_3040=y CONFIG_BOARD_DELL_OPTIPLEX_3040=y
# CONFIG_BOARD_DELL_OPTIPLEX_780_MT is not set # CONFIG_BOARD_DELL_OPTIPLEX_780_MT is not set
# CONFIG_BOARD_DELL_OPTIPLEX_780_USFF is not set # CONFIG_BOARD_DELL_OPTIPLEX_780_USFF is not set
# CONFIG_BOARD_DELL_OPTIPLEX_9020_SFF is not set # CONFIG_BOARD_DELL_OPTIPLEX_9020_SFF is not set
# CONFIG_BOARD_DELL_OPTIPLEX_9020_MT is not set # CONFIG_BOARD_DELL_OPTIPLEX_9020_MT is not set
# CONFIG_BOARD_DELL_OPTIPLEX_3050 is not set
# CONFIG_BOARD_DELL_LATITUDE_E5420 is not set # CONFIG_BOARD_DELL_LATITUDE_E5420 is not set
# CONFIG_BOARD_DELL_LATITUDE_E5520 is not set # CONFIG_BOARD_DELL_LATITUDE_E5520 is not set
# CONFIG_BOARD_DELL_LATITUDE_E6220 is not set # CONFIG_BOARD_DELL_LATITUDE_E6220 is not set
@@ -203,7 +207,8 @@ CONFIG_GFX_GMA_PANEL_1_ON_EDP=y
CONFIG_DRIVERS_UART_8250IO=y CONFIG_DRIVERS_UART_8250IO=y
CONFIG_PC_CMOS_BASE_PORT_BANK1=0x72 CONFIG_PC_CMOS_BASE_PORT_BANK1=0x72
CONFIG_HEAP_SIZE=0x100000 CONFIG_HEAP_SIZE=0x100000
CONFIG_EC_GPE_SCI=0x50 # CONFIG_BOOTMEDIA_SMM_BWP is not set
# CONFIG_DRIVERS_EFI_FW_INFO is not set
CONFIG_BOARD_ROMSIZE_KB_16384=y CONFIG_BOARD_ROMSIZE_KB_16384=y
# CONFIG_COREBOOT_ROMSIZE_KB_256 is not set # CONFIG_COREBOOT_ROMSIZE_KB_256 is not set
# CONFIG_COREBOOT_ROMSIZE_KB_512 is not set # CONFIG_COREBOOT_ROMSIZE_KB_512 is not set
@@ -247,6 +252,7 @@ CONFIG_SMM_RESERVED_SIZE=0x200000
CONFIG_SMM_MODULE_STACK_SIZE=0x800 CONFIG_SMM_MODULE_STACK_SIZE=0x800
CONFIG_ACPI_BERT_SIZE=0x0 CONFIG_ACPI_BERT_SIZE=0x0
CONFIG_DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ=120 CONFIG_DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ=120
CONFIG_CPU_PT_ROM_MAP_GB=512
CONFIG_PRERAM_CBFS_CACHE_SIZE=0x4000 CONFIG_PRERAM_CBFS_CACHE_SIZE=0x4000
CONFIG_DOMAIN_RESOURCE_32BIT_LIMIT=0xe0000000 CONFIG_DOMAIN_RESOURCE_32BIT_LIMIT=0xe0000000
CONFIG_ACPI_CPU_STRING="CP%02X" CONFIG_ACPI_CPU_STRING="CP%02X"
@@ -264,7 +270,6 @@ CONFIG_SOC_INTEL_I2C_DEV_MAX=6
CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL=0x30 CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL=0x30
CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL=0xc35 CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL=0xc35
CONFIG_FSP_HEADER_PATH="3rdparty/fsp/KabylakeFspBinPkg/Include/" CONFIG_FSP_HEADER_PATH="3rdparty/fsp/KabylakeFspBinPkg/Include/"
CONFIG_FSP_FD_PATH="3rdparty/fsp/KabylakeFspBinPkg/Fsp.fd"
CONFIG_SOC_INTEL_COMMON_DEBUG_CONSENT=0 CONFIG_SOC_INTEL_COMMON_DEBUG_CONSENT=0
CONFIG_INTEL_GMA_BCLV_OFFSET=0xc8254 CONFIG_INTEL_GMA_BCLV_OFFSET=0xc8254
CONFIG_INTEL_GMA_BCLV_WIDTH=16 CONFIG_INTEL_GMA_BCLV_WIDTH=16
@@ -282,6 +287,8 @@ CONFIG_SOC_INTEL_GFX_FRAMEBUFFER_OFFSET=0x0
CONFIG_PCIE_LTR_MAX_SNOOP_LATENCY=0x1003 CONFIG_PCIE_LTR_MAX_SNOOP_LATENCY=0x1003
CONFIG_PCIE_LTR_MAX_NO_SNOOP_LATENCY=0x1003 CONFIG_PCIE_LTR_MAX_NO_SNOOP_LATENCY=0x1003
CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH=0 CONFIG_SOC_PHYSICAL_ADDRESS_WIDTH=0
CONFIG_RAMSTAGE_CBFS_CACHE_SIZE=0x4000
CONFIG_CBFS_CACHE_ALIGN=8
CONFIG_SOC_INTEL_COMMON_SKYLAKE_BASE=y CONFIG_SOC_INTEL_COMMON_SKYLAKE_BASE=y
CONFIG_SOC_INTEL_KABYLAKE=y CONFIG_SOC_INTEL_KABYLAKE=y
CONFIG_SKYLAKE_SOC_PCH_H=y CONFIG_SKYLAKE_SOC_PCH_H=y
@@ -291,7 +298,7 @@ CONFIG_SKYLAKE_SOC_PCH_H=y
CONFIG_FSP_T_LOCATION=0xfffe0000 CONFIG_FSP_T_LOCATION=0xfffe0000
CONFIG_SOC_INTEL_COMMON_BLOCK_P2SB=y CONFIG_SOC_INTEL_COMMON_BLOCK_P2SB=y
CONFIG_FIXED_SMBUS_IO_BASE=0xefa0 CONFIG_FIXED_SMBUS_IO_BASE=0xefa0
CONFIG_CBFS_CACHE_ALIGN=8 CONFIG_UART_BITBANG_TX_DELAY_MS=5
CONFIG_SOC_INTEL_COMMON=y CONFIG_SOC_INTEL_COMMON=y
# #
@@ -429,7 +436,6 @@ CONFIG_UDELAY_TSC=y
CONFIG_TSC_MONOTONIC_TIMER=y CONFIG_TSC_MONOTONIC_TIMER=y
CONFIG_TSC_SYNC_MFENCE=y CONFIG_TSC_SYNC_MFENCE=y
CONFIG_HAVE_SMI_HANDLER=y CONFIG_HAVE_SMI_HANDLER=y
CONFIG_CPU_PT_ROM_MAP_GB=512
CONFIG_SMM_TSEG=y CONFIG_SMM_TSEG=y
CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS=8 CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS=8
CONFIG_AP_STACK_SIZE=0x800 CONFIG_AP_STACK_SIZE=0x800
@@ -498,7 +504,6 @@ CONFIG_ARCH_ALL_STAGES_X86_32=y
CONFIG_RESERVED_PHYSICAL_ADDRESS_BITS_SUPPORT=y CONFIG_RESERVED_PHYSICAL_ADDRESS_BITS_SUPPORT=y
CONFIG_X86_TOP4G_BOOTMEDIA_MAP=y CONFIG_X86_TOP4G_BOOTMEDIA_MAP=y
CONFIG_POSTRAM_CBFS_CACHE_IN_BSS=y CONFIG_POSTRAM_CBFS_CACHE_IN_BSS=y
CONFIG_RAMSTAGE_CBFS_CACHE_SIZE=0x4000
CONFIG_PC80_SYSTEM=y CONFIG_PC80_SYSTEM=y
CONFIG_HAVE_CMOS_DEFAULT=y CONFIG_HAVE_CMOS_DEFAULT=y
CONFIG_POSTCAR_STAGE=y CONFIG_POSTCAR_STAGE=y
@@ -556,6 +561,8 @@ CONFIG_INTEL_GMA_ADD_VBT=y
# CONFIG_SOFTWARE_I2C is not set # CONFIG_SOFTWARE_I2C is not set
CONFIG_I2C_TRANSFER_TIMEOUT_US=500000 CONFIG_I2C_TRANSFER_TIMEOUT_US=500000
CONFIG_RESOURCE_ALLOCATION_TOP_DOWN=y CONFIG_RESOURCE_ALLOCATION_TOP_DOWN=y
CONFIG_DRAM_SUPPORT_DDR4=y
CONFIG_DRAM_SUPPORT_DDR3=y
# end of Devices # end of Devices
# #
@@ -563,8 +570,8 @@ CONFIG_RESOURCE_ALLOCATION_TOP_DOWN=y
# #
CONFIG_CRB_TPM_BASE_ADDRESS=0xfed40000 CONFIG_CRB_TPM_BASE_ADDRESS=0xfed40000
# CONFIG_DRIVERS_EFI_VARIABLE_STORE is not set # CONFIG_DRIVERS_EFI_VARIABLE_STORE is not set
# CONFIG_DRIVERS_EFI_FW_INFO is not set
# CONFIG_ELOG is not set # CONFIG_ELOG is not set
# CONFIG_DRIVERS_HWID_DMI is not set
CONFIG_CACHE_MRC_SETTINGS=y CONFIG_CACHE_MRC_SETTINGS=y
CONFIG_MRC_SETTINGS_PROTECT=y CONFIG_MRC_SETTINGS_PROTECT=y
# CONFIG_DRIVERS_OPTION_CFR is not set # CONFIG_DRIVERS_OPTION_CFR is not set
@@ -602,6 +609,7 @@ CONFIG_USE_FSP_NOTIFY_PHASE_READY_TO_BOOT=y
CONFIG_USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE=y CONFIG_USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE=y
# CONFIG_DISPLAY_FSP_TIMESTAMPS is not set # CONFIG_DISPLAY_FSP_TIMESTAMPS is not set
# CONFIG_BUILDING_WITH_DEBUG_FSP is not set # CONFIG_BUILDING_WITH_DEBUG_FSP is not set
CONFIG_FSP_VGA_MODE12_BPP=0x0
CONFIG_INTEL_GMA_ACPI=y CONFIG_INTEL_GMA_ACPI=y
CONFIG_VBT_CBFS_COMPRESSION_LZMA=y CONFIG_VBT_CBFS_COMPRESSION_LZMA=y
# CONFIG_VBT_CBFS_COMPRESSION_LZ4 is not set # CONFIG_VBT_CBFS_COMPRESSION_LZ4 is not set
@@ -663,7 +671,6 @@ CONFIG_PLATFORM_HAS_DRAM_CLEAR=y
CONFIG_BOOTMEDIA_LOCK_NONE=y CONFIG_BOOTMEDIA_LOCK_NONE=y
# CONFIG_BOOTMEDIA_LOCK_CONTROLLER is not set # CONFIG_BOOTMEDIA_LOCK_CONTROLLER is not set
# CONFIG_BOOTMEDIA_LOCK_CHIP is not set # CONFIG_BOOTMEDIA_LOCK_CHIP is not set
# CONFIG_BOOTMEDIA_SMM_BWP is not set
# end of Security # end of Security
CONFIG_ACPI_HAVE_PCAT_8259=y CONFIG_ACPI_HAVE_PCAT_8259=y
@@ -804,6 +811,9 @@ CONFIG_DECOMPRESS_OFAST=y
# Boot Logo Configuration # Boot Logo Configuration
# #
# CONFIG_BMP_LOGO is not set # CONFIG_BMP_LOGO is not set
CONFIG_PLATFORM_POST_RENDER_DELAY_SEC=5
CONFIG_PLATFORM_OFF_MODE_CHARGING_INDICATOR_LOGO_PATH="3rdparty/blobs/mainboard/$(MAINBOARDDIR)/off_mode_charging.bmp"
# CONFIG_FRAMEBUFFER_SPLASH_TEXT is not set
# end of Boot Logo Configuration # end of Boot Logo Configuration
CONFIG_WARNINGS_ARE_ERRORS=y CONFIG_WARNINGS_ARE_ERRORS=y
@@ -150,7 +150,7 @@ CONFIG_MEMLAYOUT_LD_FILE="src/arch/x86/memlayout.ld"
# CONFIG_FATAL_ASSERTS is not set # CONFIG_FATAL_ASSERTS is not set
CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt" CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt"
CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00 CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00
CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 7020/9020 SFF" CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="Precision T1700 MT"
# CONFIG_CONSOLE_POST is not set # CONFIG_CONSOLE_POST is not set
CONFIG_MAX_SOCKET=1 CONFIG_MAX_SOCKET=1
CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default" CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default"
@@ -148,7 +148,7 @@ CONFIG_MEMLAYOUT_LD_FILE="src/arch/x86/memlayout.ld"
# CONFIG_FATAL_ASSERTS is not set # CONFIG_FATAL_ASSERTS is not set
CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt" CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt"
CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00 CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00
CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 7020/9020 SFF" CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="Precision T1700 MT"
# CONFIG_CONSOLE_POST is not set # CONFIG_CONSOLE_POST is not set
CONFIG_MAX_SOCKET=1 CONFIG_MAX_SOCKET=1
CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default" CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default"
@@ -150,7 +150,7 @@ CONFIG_MEMLAYOUT_LD_FILE="src/arch/x86/memlayout.ld"
# CONFIG_FATAL_ASSERTS is not set # CONFIG_FATAL_ASSERTS is not set
CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt" CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt"
CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00 CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00
CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 7020/9020 SFF" CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="Precision T1700 SFF"
# CONFIG_CONSOLE_POST is not set # CONFIG_CONSOLE_POST is not set
CONFIG_MAX_SOCKET=1 CONFIG_MAX_SOCKET=1
CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default" CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default"
@@ -148,7 +148,7 @@ CONFIG_MEMLAYOUT_LD_FILE="src/arch/x86/memlayout.ld"
# CONFIG_FATAL_ASSERTS is not set # CONFIG_FATAL_ASSERTS is not set
CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt" CONFIG_INTEL_GMA_VBT_FILE="src/mainboard/$(MAINBOARDDIR)/data.vbt"
CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00 CONFIG_PRERAM_CBMEM_CONSOLE_SIZE=0xc00
CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="OptiPlex 7020/9020 SFF" CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="Precision T1700 SFF"
# CONFIG_CONSOLE_POST is not set # CONFIG_CONSOLE_POST is not set
CONFIG_MAX_SOCKET=1 CONFIG_MAX_SOCKET=1
CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default" CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default"
+2 -2
View File
@@ -24,5 +24,5 @@ payload_uboot=""
cbfscfg="" cbfscfg=""
premake="corebootpremake" premake="corebootpremake"
mkhelper="coreboot_pad_one_byte" mkhelper="$if_not_dry_build coreboot_pad_one_byte"
postmake="mkcorebootbin" postmake="$if_not_dry_build mkcorebootbin"
+2 -2
View File
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
bootstrapargs="--gnulib-srcdir=gnulib/ --no-git" bootstrapargs="--gnulib-srcdir=gnulib/ --no-git"
autoconfargs="--with-platform=coreboot --disable-werror" configureargs="--with-platform=coreboot --disable-werror"
makeargs="FS_PAYLOAD_MODULES=\"\"" makeargs="FS_PAYLOAD_MODULES=\"\""
buildtype="autohell" buildtype="autohell"
mkhelper="mkpayload_grub" mkhelper="$if_not_dry_build mkpayload_grub"
+2 -1
View File
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
postmake="copyps1bios" mkhelper="$if_not_dry_build copyps1bios"
postmake="$if_not_dry_build copyps1bios"
+1 -1
View File
@@ -6,7 +6,7 @@ acpica arm-none-eabi-binutils arm-none-eabi-gcc arm-none-eabi-newlib \
autogen base-devel bison cdrtools cmake curl device-mapper doxygen \ autogen base-devel bison cdrtools cmake curl device-mapper doxygen \
dtc e2fsprogs flex freetype2 fuse2 gawk gcc-ada gdb gettext git \ dtc e2fsprogs flex freetype2 fuse2 gawk gcc-ada gdb gettext git \
help2man innoextract libftdi libgpiod libjaylink libpciaccess libusb nasm \ help2man innoextract libftdi libgpiod libjaylink libpciaccess libusb nasm \
ncurses openssl 7zip ccache less libx86 \ ncurses openssl 7zip less libx86 \
pandoc parted pciutils perl perl-libwww python python-setuptools rsync \ pandoc parted pciutils perl perl-libwww python python-setuptools rsync \
sharutils subversion swig texinfo ttf-dejavu unarchiver unzip wget xz zlib mtools \ sharutils subversion swig texinfo ttf-dejavu unarchiver unzip wget xz zlib mtools \
" "
+1 -1
View File
@@ -13,6 +13,6 @@ libsdl2-dev libselinux1-dev libssl-dev libtool libusb-1.0-0 libusb-1.0-0-dev \
libusb-dev lz4 lzma lzma-alone m4 nasm openssl 7zip parted pciutils \ libusb-dev lz4 lzma lzma-alone m4 nasm openssl 7zip parted pciutils \
perl pkg-config python3 python3-distutils-extra python3-pkg-resources python3-pycryptodome \ perl pkg-config python3 python3-distutils-extra python3-pkg-resources python3-pycryptodome \
python3-pyelftools python3-setuptools python-is-python3 sharutils swig unar \ python3-pyelftools python3-setuptools python-is-python3 sharutils swig unar \
unifont unifont-bin unzip uuid-dev wget xfonts-unifont zlib1g-dev ccache \ unifont unifont-bin unzip uuid-dev wget xfonts-unifont zlib1g-dev \
g++-mipsel-linux-gnu make genisoimage mtools libx86-1 libx86-dev libstdc++-arm-none-eabi-newlib autoconf-archive \ g++-mipsel-linux-gnu make genisoimage mtools libx86-1 libx86-dev libstdc++-arm-none-eabi-newlib autoconf-archive \
" "
+1 -1
View File
@@ -10,5 +10,5 @@ innoextract intltool libftdi-devel libselinux-devel libusb1 libusb1-devel \
nasm ncurses-devel openssl-devel p7zip p7zip-plugins pandoc parted \ nasm ncurses-devel openssl-devel p7zip p7zip-plugins pandoc parted \
pciutils-devel perl perl-libwww-perl python-unversioned-command python3 \ pciutils-devel perl perl-libwww-perl python-unversioned-command python3 \
python3-setuptools rsync sharutils subversion texinfo unar unifont \ python3-setuptools rsync sharutils subversion texinfo unar unifont \
unifont-fonts unifont-ttf-fonts unzip wget xz zlib-devel ccache swig \ unifont-fonts unifont-ttf-fonts unzip wget xz zlib-devel swig \
" "
+1 -1
View File
@@ -11,5 +11,5 @@ libselinux-devel libusb1 libusb1-devel nasm ncurses-devel openssl-devel \
p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \ p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \
python-unversioned-command python3 python3-setuptools rsync sharutils \ python-unversioned-command python3 python3-setuptools rsync sharutils \
subversion systemd-devel texinfo unar unifont unifont-fonts \ subversion systemd-devel texinfo unar unifont unifont-fonts \
unifont-ttf-fonts unzip wget xz zlib-devel ccache swig python3-devel \ unifont-ttf-fonts unzip wget xz zlib-devel swig python3-devel \
" "
+1 -1
View File
@@ -11,6 +11,6 @@ libselinux-devel libusb1 libusb1-devel nasm ncurses-devel openssl-devel openssl-
p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \ p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \
python-unversioned-command python3 python3-setuptools rsync sharutils \ python-unversioned-command python3 python3-setuptools rsync sharutils \
subversion systemd-devel texinfo unar unifont unifont-fonts uuid-devel \ subversion systemd-devel texinfo unar unifont unifont-fonts uuid-devel \
unifont-ttf-fonts unzip wget xz zlib-devel ccache swig python3-devel \ unifont-ttf-fonts unzip wget xz zlib-devel swig python3-devel \
libuuid-devel gnutls-devel \ libuuid-devel gnutls-devel \
" "
+1 -1
View File
@@ -11,6 +11,6 @@ libselinux-devel libusb1 libusb1-devel nasm ncurses-devel openssl-devel openssl-
p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \ p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \
python-unversioned-command python3 python3-setuptools rsync sharutils \ python-unversioned-command python3 python3-setuptools rsync sharutils \
subversion systemd-devel texinfo unifont unifont-fonts uuid-devel \ subversion systemd-devel texinfo unifont unifont-fonts uuid-devel \
unifont-ttf-fonts unzip wget xz zlib-devel ccache swig python3-devel \ unifont-ttf-fonts unzip wget xz zlib-devel swig python3-devel \
libuuid-devel gnutls-devel tar unar libtool \ libuuid-devel gnutls-devel tar unar libtool \
" "
+1 -1
View File
@@ -11,6 +11,6 @@ libselinux-devel libusb1 libusb1-devel nasm ncurses-devel openssl-devel openssl-
p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \ p7zip p7zip-plugins pandoc parted pciutils-devel perl perl-libwww-perl \
python-unversioned-command python3 python3-setuptools rsync sharutils \ python-unversioned-command python3 python3-setuptools rsync sharutils \
subversion systemd-devel texinfo unifont unifont-fonts uuid-devel \ subversion systemd-devel texinfo unifont unifont-fonts uuid-devel \
unifont-ttf-fonts unzip wget xz zlib-devel ccache swig python3-devel \ unifont-ttf-fonts unzip wget xz zlib-devel swig python3-devel \
libuuid-devel gnutls-devel tar unar libtool \ libuuid-devel gnutls-devel tar unar libtool \
" "
+1 -1
View File
@@ -11,7 +11,7 @@ dev-libs/libgpiod app-arch/sharutils dev-libs/libtomcrypt sys-devel/autogen \
media-libs/freetype sys-fs/e2fsprogs sys-fs/lvm2 dev-libs/libusb \ media-libs/freetype sys-fs/e2fsprogs sys-fs/lvm2 dev-libs/libusb \
sys-block/parted sys-fs/mtools app-arch/lz4 dev-libs/leancrypto sys-fs/fuse \ sys-block/parted sys-fs/mtools app-arch/lz4 dev-libs/leancrypto sys-fs/fuse \
sys-apps/dtc net-libs/gnutls net-misc/curl dev-build/cmake dev-vcs/git \ sys-apps/dtc net-libs/gnutls net-misc/curl dev-build/cmake dev-vcs/git \
dev-util/ccache dev-embedded/libftdi app-arch/innoextract sys-devel/gcc \ dev-embedded/libftdi app-arch/innoextract sys-devel/gcc \
sys-apps/pciutils app-crypt/efitools gnustep-base/gnustep-make gnustep-base/gnustep-base \ sys-apps/pciutils app-crypt/efitools gnustep-base/gnustep-make gnustep-base/gnustep-base \
app-arch/unar app-arch/7zip dev-lang/python dev-python/setuptools dev-python/ply \ app-arch/unar app-arch/7zip dev-lang/python dev-python/setuptools dev-python/ply \
sys-libs/libselinux dev-python/pyelftools dev-python/pycparser dev-python/cffi \ sys-libs/libselinux dev-python/pyelftools dev-python/pycparser dev-python/cffi \
+1 -1
View File
@@ -12,6 +12,6 @@ libpython3-dev libsdl2-dev libselinux1-dev libssl-dev libtool libusb-1.0-0 \
libusb-1.0-0-dev lz4 lzma lzma-alone m4 nasm openssl p7zip p7zip-full parted \ libusb-1.0-0-dev lz4 lzma lzma-alone m4 nasm openssl p7zip p7zip-full parted \
pciutils perl pkg-config python3 python3-pkg-resources python3-pycryptodome \ pciutils perl pkg-config python3 python3-pkg-resources python3-pycryptodome \
python3-pyelftools python3-setuptools python-is-python3 sharutils swig \ python3-pyelftools python3-setuptools python-is-python3 sharutils swig \
fonts-unifont unar unifont unzip uuid-dev wget zlib1g-dev ccache \ fonts-unifont unar unifont unzip uuid-dev wget zlib1g-dev \
g++-mipsel-linux-gnu make genisoimage mtools \ g++-mipsel-linux-gnu make genisoimage mtools \
" "
+1 -1
View File
@@ -8,5 +8,5 @@ freetype freetype-devel fuse gawk gcc-ada gdb gettext gettext-devel git \
gnutls-devel help2man innoextract libftdi1 libpciaccess libusb libuuid-devel \ gnutls-devel help2man innoextract libftdi1 libpciaccess libusb libuuid-devel \
nasm ncurses ncurses-devel openssl openssl-devel 7zip parted pciutils perl \ nasm ncurses ncurses-devel openssl openssl-devel 7zip parted pciutils perl \
perl-LWP python python3 python3-devel python3-setuptools rsync sharutils \ perl-LWP python python3 python3-devel python3-setuptools rsync sharutils \
subversion swig texinfo unar unzip wget xz zlib ccache \ subversion swig texinfo unar unzip wget xz zlib \
" "
-1
View File
@@ -2,4 +2,3 @@
makeargs="-f lbmkbofhmakefile" makeargs="-f lbmkbofhmakefile"
cleanargs="-f lbmkbofhmakefile" cleanargs="-f lbmkbofhmakefile"
mkhelper="copyps1bios"
-138
View File
@@ -1,138 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (c) 2025 Leah Rowe <leah@libreboot.org>
# Import MrChromebox project into xbmk
# NOTE: variable naming scheme:
# mr_ for variables/functions dealing with MrChromebox
# mx_ for variables/functions pertaining to Libreboot setup
# because i am a non-binary blob
spdx="# SPDX-License-Identifier: GPL-3.0-or-later"
# temporary work variables
mr_tmpdir="" # dir to clone tmp repos in
# NOTE: upstream for our purposes: https://review.coreboot.org/coreboot
mr_cbrepo="https://github.com/mrchromebox/coreboot"
mr_cbbranch="MrChromebox-2503" # branch in mrchromebox
mr_cbrev="ecd9fa6a177e00132ec214252a2b9cebbb01e25f" # relative to base
mr_cbrevbase="38f5f7c48024d9fca4b6bbd88914423c34da709c" # 25.03 upstream base
mr_cbtree="chromebook" # tree name in xbmk
# NOTE: upstream for our purposes: https://github.com/tianocore/edk2.git
mr_edk2repo="https://github.com/mrchromebox/edk2"
mr_edk2branch="uefipayload_2502" # branch in mrchromebox
mr_edk2rev="feaf6b976b7cc72a18ed364f273751c943a9e7d0" # relative to base
mr_edk2revbase="fbe0805b2091393406952e84724188f8c1941837" # 2025.02 upstream
mr_edk2tree="chromebook" # tree name in xbmk
# mxlibreboot was here
prep_mr_import()
{
if [ -f "$xbmkpwd/CHANGELOG" ]; then
err "Project import disabled on releases" "prep_mr_import" "$@"
fi
mr_tmpdir="`mktemp -d || err "can't make mrtmpdir"`" || \
err "can't make mrtmpdir" "prep_mr_coreboot" "$@"
x_ remkdir "$mr_tmpdir"
x_ prep_mx_edk2conf
x_ prep_mr_projects
x_ rm -Rf "$mr_tmpdir"
}
# create config/git/edk2/pkg.cfg
prep_mx_edk2conf()
{
x_ remkdir "config/git/edk2"
x_ prep_mr_file "config/git/edk2/pkg.cfg" \
"$spdx" \
"" \
"rev=\"HEAD\"" \
"url=\"https://codeberg.org/libreboot/edk2\"" \
"bkup_url=\"https://git.disroot.org/libreboot/edk2\""
}
# prep config/PROJECT/TREE/ for various projects
prep_mr_projects()
{
x_ prep_mr "coreboot" "$mr_cbrepo" "$mr_cbbranch" "$mr_cbrev" \
"$mr_cbrevbase" "$mr_cbtree"
x_ prep_mr "edk2" "$mr_edk2repo" "$mr_edk2branch" "$mr_edk2rev" \
"$mr_edk2revbase" "$mr_edk2tree"
}
# create config/PROJECT/TREE/target.cfg
# and config/PROJECT/TREE/patches/
prep_mr()
{
mr_projectname="$1"
mr_repo="$2"
mr_branch="$3"
mr_rev="$4"
mr_revbase="$5"
mr_tree="$6"
x_ prep_mr_clone "$@"
x_ prep_mr_patch "$@"
x_ prep_mr_file "config/$1/$6/target.cfg" \
"$spdx" \
"" \
"tree=\"$6\"" \
"rev=\"$5\""
}
prep_mr_clone()
{
mr_tmpclone="$mr_tmpdir/$1"
x_ git clone "$2" "$mr_tmpclone"
x_ git -C "$mr_tmpclone" checkout "$3"
# we don't reset, because we format-patch between revbase..rev
}
prep_mr_patch()
{
mr_tmpclone="$mr_tmpdir/$1"
mx_patchdir="config/$1/$6/patches"
x_ remkdir "$mx_patchdir"
if [ "$4" != "$5" ]; then
x_ git -C "$mr_tmpclone" format-patch $5..$4
x_ mv "$mr_tmpclone"/*.patch "$mx_patchdir"
fi
# if no patches were created, rmdir will succeed
rmdir "$mx_patchdir" 1>/dev/null 2>/dev/null || :
}
prep_mr_file()
{
mr_filename="$1"
shift 1
x_ rm -f "$mr_filename"
while [ $# -gt 0 ]; do
printf "%s\n" "$1" >> "$mr_filename" || \
err "Can't write '$1' to '$mr_filename'" prep_mr_file "$@"
shift 1
done
printf "Created '%s'\n" "$mr_filename"
}
+67 -245
View File
@@ -1,77 +1,51 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (c) 2020-2021,2023-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2020-2021,2023-2026 Leah Rowe <leah@libreboot.org>
# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com>
url="" eval "`newvar url bkup_url depend loc subcurl subcurl_bkup subgit subgit_bkup \
bkup_url="" subhash`"
depend=""
loc=""
subcurl=""
subcurl_bkup=""
subgit=""
subgit_bkup=""
subhash=""
tmpgit="$xbtmp/gitclone" tmpgit="$xbtmp/gitclone"
tmpgitcache="$xbtmp/tmpgit" tmpgitcache="$xbtmp/tmpgit"
fetch_targets() multi_tree_fetch()
{ {
if [ -d "src/$project/$tree" ]; then [ -d "src/$project/$tree" ] && return 0
return 0
fi
git_prep "$url" "$bkup_url" "$xbmkpwd/$configdir/$tree/patches" \ git_prep "$url" "$bkup_url" "$xbmkpwd/$configdir/$tree/patches" \
"src/$project/$tree" "submod" "src/$project/$tree" "submod"
} }
fetch_project() single_tree_fetch()
{ {
xgcctree="" xgcctree=""
. "config/git/$project/pkg.cfg" || \ . "config/git/$project/pkg.cfg" || \
err "Can't read config 'config/git/$project/pkg.cfg'" \ err "Can't read config 'config/git/$project/pkg.cfg'" \
"fetch_project" "@" "single_tree_fetch" "@"
if [ -z "$url" ] || \
[ -z "$bkup_url" ]; then
if [ -z "$url" ] || [ -z "$bkup_url" ]; then
err "url/bkup_url not both set 'config/git/$project/pkg.cfg'" \ err "url/bkup_url not both set 'config/git/$project/pkg.cfg'" \
"fetch_project" "$@" "single_tree_fetch" "$@"
fi fi
if [ -n "$xgcctree" ]; then [ -n "$xgcctree" ] && \
x_ "$mk" -f coreboot "$xgcctree"
x_ ./mk -f coreboot "$xgcctree"
fi
if [ -n "$depend" ]; then
[ -n "$depend" ] && \
for d in $depend ; do for d in $depend ; do
x_ "$mk" -f $d
x_ ./mk -f $d
done done
fi
clone_project $if_single_tree \
clone_project; :
} }
clone_project() clone_project()
{ {
if ! singletree "$project"; then
return 0
fi
loc="src/$project" loc="src/$project"
[ -d "$loc" ] && return 0
if [ -d "$loc" ]; then
return 0
fi
remkdir "${tmpgit%/*}" remkdir "${tmpgit%/*}"
git_prep "$url" "$bkup_url" "$xbmkpwd/config/$project/patches" "$loc" git_prep "$url" "$bkup_url" "$xbmkpwd/config/$project/patches" "$loc"
@@ -84,23 +58,16 @@ git_prep()
_patchdir="$3" _patchdir="$3"
_loc="$4" # $1 and $2 are gitrepo and gitrepo_backup _loc="$4" # $1 and $2 are gitrepo and gitrepo_backup
if [ -z "$rev" ]; then [ -z "$rev" ] && \
err "$project/$tree: rev not set" "git_prep" "$@" err "$project/$tree: rev not set" "git_prep" "$@"
fi
xbget git "$1" "$2" "$tmpgit" "$rev" "$_patchdir" xbget git "$1" "$2" "$tmpgit" "$rev" "$_patchdir"
if singletree "$project" || [ $# -gt 4 ]; then
if singletree "$project" || \
[ $# -gt 4 ]; then
dx_ fetch_submodule "$mdir/module.list" dx_ fetch_submodule "$mdir/module.list"
fi fi
if [ "$_loc" != "${_loc%/*}" ]; then [ "$_loc" != "${_loc%/*}" ] && \
x_ mkdir -p "${_loc%/*}"
x_ xbmkdir "${_loc%/*}"
fi
x_ mv "$tmpgit" "$_loc" x_ mv "$tmpgit" "$_loc"
} }
@@ -108,73 +75,28 @@ git_prep()
fetch_submodule() fetch_submodule()
{ {
mcfgdir="$mdir/${1##*/}" mcfgdir="$mdir/${1##*/}"
eval "`newvar st subcurl subcurl_bkup subgit subgit_bkup subhash`"
st="" e "$mcfgdir/module.cfg" f missing && return 0
subcurl=""
subcurl_bkup=""
subgit=""
subgit_bkup=""
subhash=""
if e "$mcfgdir/module.cfg" f missing; then
return 0
fi
. "$mcfgdir/module.cfg" || \ . "$mcfgdir/module.cfg" || \
err "Can't read '$mcfgdir/module.cfg'" "fetch_submodules" "$@" err "Can't read '$mcfgdir/module.cfg'" "fetch_submodules" "$@"
if [ -n "$subgit" ] || \ [ -n "$subgit" ] && [ -n "$subgit_bkup" ] && \
[ -n "$subgit_bkup" ]; then st="git"
[ -n "$subcurl" ] && [ -n "$subcurl_bkup" ] && \
st="$st git" st="curl$st"
fi [ "$st" = "curlgit" ] && \
if [ -n "$subcurl" ] || \
[ -n "$subcurl_bkup" ]; then
st="$st curl"
fi
st="${st# }"
if [ "$st" = "git curl" ]; then
err "$mdir: git+curl defined" "fetch_submodule" "$@" err "$mdir: git+curl defined" "fetch_submodule" "$@"
fi [ -z "$st" ] && \
if [ -z "$st" ]; then
return 0 return 0
fi [ -z "$subhash" ] && \
if [ "$st" = "curl" ]; then
if [ -z "$subcurl" ] || [ -z "$subcurl_bkup" ]; then
err "subcurl/subcurl_bkup not both set" \
"fetch_submodule" "$@"
fi
elif [ -z "$subgit" ] || \
[ -z "$subgit_bkup" ]; then
err "subgit/subgit_bkup not both set" "fetch_submodule" "$@"
elif [ -z "$subhash" ]; then
err "subhash not set" "fetch_submodule" "$@" err "subhash not set" "fetch_submodule" "$@"
fi
if [ "$st" = "git" ]; then
[ "$st" = "git" ] && \
x_ rm -Rf "$tmpgit/$1" x_ rm -Rf "$tmpgit/$1"
xbget "$st" "$subgit" "$subgit_bkup" "$tmpgit/$1" \ eval "xbget \"\$st\" \"\$sub$st\" \"\$sub${st}_bkup\" \"\$tmpgit/\$1\" \
"$subhash" "$mdir/${1##*/}/patches" \"\$subhash\" \"\$mdir/\${1##*/}/patches\""
else
xbget "$st" "$subcurl" "$subcurl_bkup" "$tmpgit/$1" \
"$subhash" "$mdir/${1##*/}/patches"
fi
} }
# TODO: in the following functions, argument numbers are used # TODO: in the following functions, argument numbers are used
@@ -183,151 +105,85 @@ fetch_submodule()
xbget() xbget()
{ {
if [ "$1" != "curl" ] && \ [ "$1" != "curl" ] && [ "$1" != "copy" ] && [ "$1" != "git" ] && \
[ "$1" != "copy" ] && \
[ "$1" != "git" ]; then
err "Bad dlop (arg 1)" "xbget" "$@" err "Bad dlop (arg 1)" "xbget" "$@"
fi
for url in "$2" "$3"; do for url in "$2" "$3"; do
[ -z "$url" ] && \
if [ -z "$url" ]; then
err "empty URL given in" "xbget" "$@" err "empty URL given in" "xbget" "$@"
try_fetch_$1 "$url" "$@" || \
elif ! try_fetch "$url" "$@"; then
continue continue
fi [ -e "$4" ] && return 0; : # successful download/copy
case "$1" in
git)
if [ ! -d "$4" ]; then
continue
fi
;;
*)
if [ ! -f "$4" ]; then
continue
fi
;;
esac
return 0 # successful download/copy
done done
err "failed to download file/repository" "xbget" "$@"; : err "failed to download file/repository" "xbget" "$@"; :
} }
try_fetch()
{
if [ "$2" = "git" ]; then
if ! try_fetch_git "$@"; then
return 1
fi
else
if ! try_fetch_file "$@"; then
return 1
fi
fi
}
try_fetch_git() try_fetch_git()
{ {
# 1st argument $1 is the current git remote being tried, # 1st argument $1 is the current git remote being tried,
# let's say it was https://foo.example.com/repo, then cached # let's say it was https://foo.example.com/repo, then cached
# directories becomes cache/mirror/foo.example.com/repo # directories becomes cache/mirror/foo.example.com/repo
if [ "$XBMK_CACHE_MIRROR" = "y" ]; then cached="clone"
[ "$XBMK_CACHE_MIRROR" = "y" ] && \
cached="mirror" cached="mirror"
else
cached="clone"
fi
cached="$cached/${1#*://}" cached="$cached/${1#*://}"
cached="$XBMK_CACHE/$cached" cached="$XBMK_CACHE/$cached"
x_ xbmkdir "${5%/*}" "${cached%/*}" x_ mkdir -p "${5%/*}" "${cached%/*}"
if ! try_$2 "$cached" "$@"; then
try_$2 "$cached" "$@" || \
return 1 return 1
elif [ ! -d "$cached" ]; then [ ! -d "$cached" ] && \
return 1 return 1
fi
if [ ! -d "$5" ]; then if [ ! -d "$5" ]; then
tmpclone "$cached" "$5" "$6" "$7" || \ tmpclone "$cached" "$5" "$6" "$7" || \
err "Can't clone final repo" "try_fetch" "$@"; : err "Can't clone final repo" "try_fetch" "$@"; :
fi fi
if [ ! -d "$5" ]; then [ ! -d "$5" ] && \
return 1; :
return 1
fi
} }
try_fetch_file() try_fetch_copy()
{
try_fetch_curl "$@" || return 1; :
}
try_fetch_curl()
{ {
cached="file/$6" cached="file/$6"
cached="$XBMK_CACHE/$cached" cached="$XBMK_CACHE/$cached"
x_ xbmkdir "${5%/*}" "${cached%/*}" x_ mkdir -p "${5%/*}" "${cached%/*}"
if bad_checksum "$6" "$cached" 2>/dev/null; then if bad_checksum "$6" "$cached" 2>/dev/null; then
x_ rm -f "$cached" x_ rm -f "$cached"
fi fi
if [ ! -f "$cached" ]; then [ -f "$cached" ] || \
try_$2 "$cached" "$@" || \
if ! try_$2 "$cached" "$@"; then
return 1 return 1
fi
fi
if [ -f "$5" ]; then [ -f "$5" ] && bad_checksum "$6" "$5" 2>/dev/null && \
if bad_checksum "$6" "$5" 2>/dev/null; then x_ cp "$cached" "$5"
x_ cp "$cached" "$5"
fi
fi
if [ ! -f "$cached" ]; then if [ ! -f "$cached" ]; then
return 1 return 1
elif bad_checksum "$6" "$cached"; then elif bad_checksum "$6" "$cached"; then
x_ rm -f "$cached" x_ rm -f "$cached"
return 1 return 1
fi fi
if [ "$cached" != "$5" ]; then [ "$cached" != "$5" ] && \
x_ cp "$cached" "$5" x_ cp "$cached" "$5"
fi
if bad_checksum "$6" "$5"; then if bad_checksum "$6" "$5"; then
x_ rm -f "$5" x_ rm -f "$5"
return 1 return 1
elif [ ! -f "$5" ]; then elif [ ! -f "$5" ]; then
return 1 return 1
fi fi
} }
@@ -336,22 +192,8 @@ try_curl()
{ {
ua="Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0" ua="Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"
case "$2" in
https://www.supermicro.com/*)
ua="curl/8.6.0"
;;
*)
:
;;
esac
( x_ curl --location --retry 3 -A "$ua" "$2" -o "$1" ) \ ( x_ curl --location --retry 3 -A "$ua" "$2" -o "$1" ) \
|| ( x_ wget --tries 3 -U "$ua" "$2" -O "$1" ) \ || ( x_ wget --tries 3 -U "$ua" "$2" -O "$1" ) || return 1; :
|| return 1; :
} }
try_copy() try_copy()
@@ -367,62 +209,43 @@ try_git()
x_ rm -Rf "$tmpgitcache" x_ rm -Rf "$tmpgitcache"
if [ ! -d "$gitdest" ]; then if [ ! -d "$gitdest" ]; then
if [ "$XBMK_CACHE_MIRROR" = "y" ]; then if [ "$XBMK_CACHE_MIRROR" = "y" ]; then
( x_ git clone --mirror "$2" "$tmpgitcache" ) || \ ( x_ git clone --mirror "$2" "$tmpgitcache" ) || \
return 1 return 1
else else
( x_ git clone "$2" "$tmpgitcache" ) || return 1 ( x_ git clone "$2" "$tmpgitcache" ) || return 1
fi fi
x_ xbmkdir "${gitdest%/*}" x_ mkdir -p "${gitdest%/*}"
x_ mv "$tmpgitcache" "$gitdest" x_ mv "$tmpgitcache" "$gitdest"
fi fi
if git -C "$gitdest" show "$7" 1>/dev/null 2>/dev/null && \ git -C "$gitdest" show "$7" 1>/dev/null 2>/dev/null && \
[ "$forcepull" != "y" ]; then [ "$forcepull" != "y" ] && \
return 0 # don't pull changes if target rev exists locally
# don't try to pull the latest changes if the given target
# revision already exists locally. this saves a lot of time
# during release builds, and reduces the chance that we will
# interact with grub.git or gnulib.git overall during runtime
return 0
fi
if [ "$XBMK_CACHE_MIRROR" = "y" ]; then if [ "$XBMK_CACHE_MIRROR" = "y" ]; then
( x_ git -C "$gitdest" fetch ) || :; : ( x_ git -C "$gitdest" fetch ) || :; :
( x_ git -C "$gitdest" update-server-info ) || :; : ( x_ git -C "$gitdest" update-server-info ) || :; :
else else
( x_ git -C "$gitdest" pull --all ) || :; : ( x_ git -C "$gitdest" pull --all ) || :; :
fi fi
} }
bad_checksum() bad_checksum()
{ {
if e "$2" f missing; then e "$2" f missing && \
return 0 return 0
fi
build_sbase
eval "$build_sbase"
csum="$(x_ "$sha512sum" "$2" | awk '{print $1}')" || \ csum="$(x_ "$sha512sum" "$2" | awk '{print $1}')" || \
err "!sha512 '$2' $1" bad_checksum "$@" err "!sha512 '$2' $1" bad_checksum "$@"
if [ "$csum" = "$1" ]; then [ "$csum" = "$1" ] && \
return 1 return 1
else
x_ rm -f "$2" x_ rm -f "$2"
printf "BAD SHA512 %s, '%s'; need %s\n" "$csum" "$2" "$1" 1>&2
printf "BAD SHA512 %s, '%s'; need %s\n" "$csum" "$2" "$1" 1>&2
fi
} }
tmpclone() tmpclone()
@@ -430,9 +253,8 @@ tmpclone()
( x_ git clone "$1" "$2" ) || return 1 ( x_ git clone "$1" "$2" ) || return 1
( x_ git -C "$2" reset --hard "$3" ) || return 1 ( x_ git -C "$2" reset --hard "$3" ) || return 1
if [ ! -d "$4" ]; then [ ! -d "$4" ] && \
return 0 return 0
fi
tmpclone_patchlist="`mktemp || err "Can't create tmp patch list"`" || \ tmpclone_patchlist="`mktemp || err "Can't create tmp patch list"`" || \
err "Can't create tmp patch list" "tmpclone" "$@" err "Can't create tmp patch list" "tmpclone" "$@"
@@ -443,7 +265,7 @@ tmpclone()
while read -r tmpclone_patch; do while read -r tmpclone_patch; do
( x_ git -C "$2" am --keep-cr "$tmpclone_patch" ) || \ ( x_ git -C "$2" am -3 --keep-cr "$tmpclone_patch" ) || \
err "Can't apply '$tmpclone_patch'" "tmpclone" "$@"; : err "Can't apply '$tmpclone_patch'" "tmpclone" "$@"; :
done < "$tmpclone_patchlist" || \ done < "$tmpclone_patchlist" || \
+97 -320
View File
@@ -2,52 +2,23 @@
# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com>
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
# Copyright (c) 2020-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2020-2026 Leah Rowe <leah@libreboot.org>
# Copyright (c) 2025 Alper Nebi Yasak <alpernebiyasak@gmail.com> # Copyright (c) 2025 Alper Nebi Yasak <alpernebiyasak@gmail.com>
export LANG=C.UTF-8
export LC_COLLATE=C.UTF-8
export LC_ALL=C.UTF-8
projectname="libreboot" projectname="libreboot"
projectsite="https://libreboot.org/" projectsite="https://libreboot.org/"
# TODO: consider just erroring here instead of hardcoding a default eval "`newvar aur_notice basetmp board checkvarschk checkvarsxbmk configdir \
if [ -z "${PATH+x}" ]; then datadir is_child python pyver reinstall relname version versiondate \
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" xbmklock xbmkpath xbtmp sha512sum`"
fi
sha512sum="util/sbase/sha512sum"
aur_notice=""
basetmp=""
board=""
checkvarschk=""
checkvarsxbmk=""
configdir=""
datadir=""
is_child=""
python=""
pyver=""
reinstall=""
relname=""
version=""
versiondate=""
xbmklock=""
xbmkpath=""
xbmkpwd=""
xbmkpwd=""
xbtmp=""
xbmk_init() xbmk_init()
{ {
xbmkpwd="`pwd || err "Cannot generate PWD"`" || err "!" xbmk_init "$@"
xbmklock="$xbmkpwd/lock" xbmklock="$xbmkpwd/lock"
basetmp="$xbmkpwd/xbmkwd" basetmp="$xbmkpwd/xbmkwd"
sha512sum="$xbmkpwd/util/sbase/sha512sum" sha512sum="$xbmkpwd/util/sbase/sha512sum"
if [ $# -gt 0 ] && [ "$1" = "dependencies" ]; then if [ $# -gt 0 ] && [ "$1" = "dependencies" ]; then
x_ xbmkpkg "$@" x_ xbmkpkg "$@"
exit 0 exit 0
fi fi
@@ -55,193 +26,115 @@ xbmk_init()
id -u 1>/dev/null 2>/dev/null || \ id -u 1>/dev/null 2>/dev/null || \
err "suid check failed" "xbmk_init" "$@" err "suid check failed" "xbmk_init" "$@"
if [ "$(id -u)" = "0" ]; then [ "$(id -u)" = "0" ] && \
err "this command as root is not permitted" "xbmk_init" "$@" err "this command as root is not permitted" "xbmk_init" "$@"
fi
export PWD="$xbmkpwd" export PWD="$xbmkpwd"
x_ xbmkdir "$basetmp" x_ mkdir -p "$basetmp" "cache"
if [ ! -e "cache" ]; then eval "$(printf "get_ver set_env set_threads git_init xchild\n" | awk \
'{ for (i=1; i<=NF; i++) $i = $i " \"$@\" || return 0;"; print }')"
x_ xbmkdir "cache"
fi
for init_cmd in get_version set_env set_threads git_init child_exec; do
if ! xbmk_$init_cmd "$@"; then
break
fi
done
} }
xbmkpkg() xbmkpkg()
{ {
xchk xbmkpkg "$@" xchk xbmkpkg "$@"
if [ $# -gt 2 ]; then [ $# -gt 2 ] && \
reinstall="$3" reinstall="$3"
fi
. "config/dependencies/$2" || \ . "config/dependencies/$2" || \
err "Can't read 'config/dependencies/$2'" "xbmkpkg" "$@" err "Can't read 'config/dependencies/$2'" "xbmkpkg" "$@"
if [ -z "$pkg_add" ] || \ if [ -z "$pkg_add" ] || [ -z "$pkglist" ]; then
[ -z "$pkglist" ]; then
err "pkg_add/pkglist not both set" "xbmkpkg" "$@" err "pkg_add/pkglist not both set" "xbmkpkg" "$@"
fi fi
if [ "$2" == "gentoo" ]; then if [ "$2" == "gentoo" ]; then
if [ -z "$pkg_use" ] || \ if [ -z "$pkg_use" ] || [ -z "$pkg_use_file" ]; then
[ -z "$pkg_use_file" ]; then
err "pkg_use/pkg_use_file not both set" "xbmkpkg" "$@" err "pkg_use/pkg_use_file not both set" "xbmkpkg" "$@"
fi fi
printf "Updating package use...\n" printf "Updating package use...\n"
printf "Writing into %s" "$pkg_use_file..." printf "Writing into %s" "$pkg_use_file..."
if [ ! -d "`dirname $pkg_use_file`" ]; then x_ mkdir -p "`dirname $pkg_use_file`"
x_ mkdir -p "`dirname $pkg_use_file`"
fi
printf "%s\n" "$pkg_use" >> "$pkg_use_file" printf "%s\n" "$pkg_use" >> "$pkg_use_file"
fi fi
x_ $pkg_add $pkglist x_ $pkg_add $pkglist
if [ -n "$aur_notice" ]; then [ -n "$aur_notice" ] && \
printf "You need AUR packages: %s\n" "$aur_notice" 1>&2; :
printf "You need AUR packages: %s\n" "$aur_notice" 1>&2
fi
} }
xbmk_get_version() get_ver()
{ {
if [ -f ".version" ]; then [ ! -f ".version" ] || \
read -r version < ".version" || \ read -r version < ".version" || \
err "can't read version file" "xbmk_get_version" "$@" err "can't read version file" "get_ver" "$@"
fi [ ! -f ".versiondate" ] || \
if [ -f ".versiondate" ]; then
read -r versiondate < ".versiondate" || \ read -r versiondate < ".versiondate" || \
err "can't read versiondate" xbmk_get_version "$@" err "can't read versiondate" get_ver "$@"
fi
if [ -f ".version" ] && \ [ -f ".version" ] && [ -z "$version" ] && \
[ -z "$version" ]; then err "version not set" "get_ver" "$@"
[ -f ".versiondate" ] && [ -z "$versiondate" ] && \
err "version not set" "xbmk_get_version" "$@" err "versiondate not set" "get_ver" "$@"
fi
if [ -f ".versiondate" ] && \
[ -z "$versiondate" ]; then
err "versiondate not set" "xbmk_get_version" "$@"
fi
if [ ! -e ".git" ] && \
[ ! -f ".version" ]; then
[ ! -e ".git" ] && [ ! -f ".version" ] && \
version="unknown" version="unknown"
fi [ ! -e ".git" ] && [ ! -f ".versiondate" ] && \
if [ ! -e ".git" ] && \
[ ! -f ".versiondate" ]; then
versiondate="1716415872" versiondate="1716415872"
fi
xbmk_sanitize_version xbmk_sanitize_version
if [ -n "$version" ]; then [ -n "$version" ] && \
relname="$projectname-$version"; :
relname="$projectname-$version"
fi
} }
# a parent instance will cause this function to return 0. # a parent instance will cause this function to return 0.
# a child instance will return 1, skipping further initialisation # a child instance will return 1, skipping further initialisation
# after this function is called. # after this function is called.
xbmk_set_env() set_env()
{ {
is_child="n" is_child="n"
xbmkpath="$PATH" xbmkpath="$PATH"
# unify all temporary files/directories in a single TMPDIR # unify all temporary files/directories in a single TMPDIR
[ -n "${TMPDIR+x}" ] && [ "${TMPDIR%_*}" != "$basetmp/xbmk" ] && \
if [ -n "${TMPDIR+x}" ] && \
[ "${TMPDIR%_*}" != "$basetmp/xbmk" ]; then
unset TMPDIR unset TMPDIR
fi
if [ -n "${TMPDIR+x}" ]; then if [ -n "${TMPDIR+x}" ]; then
export TMPDIR="$TMPDIR" export TMPDIR="$TMPDIR"
xbtmp="$TMPDIR" xbtmp="$TMPDIR"
fi fi
[ -n "${TMPDIR+x}" ] && \
if [ -n "${TMPDIR+x}" ]; then
is_child="y" is_child="y"
fi
if [ "$is_child" = "y" ]; then if [ "$is_child" = "y" ]; then
# child instance of xbmk, so we stop init after this point
# and execute the given user command upon return:
xbmk_child_set_env xbmk_child_set_env
return 1 # child instance. discontinue initialisation.
return 1
else
# parent instance of xbmk, so we continue initialising.
# a parent instance of xbmk never processes its own
# command directly; instead, it calls a child instance
# of xbmk, and exits with the corresponding return status.
xbmk_parent_set_env
return 0
fi fi
xbmk_parent_set_env
} }
xbmk_child_set_env() xbmk_child_set_env()
{ {
xbmk_child_set_tmp xbmk_child_set_tmp
if [ -z "${XBMK_CACHE+x}" ]; then [ -z "${XBMK_CACHE+x}" ] && \
err "XBMK_CACHE unset on child" "set_env" "$@"
err "XBMK_CACHE unset on child" "xbmk_set_env" "$@" [ -z "${XBMK_THREADS+x}" ] && \
fi set_threads
[ -z "${XBMK_CACHE_MIRROR+x}" ] && \
if [ -z "${XBMK_THREADS+x}" ]; then xbmk_set_mirror; :
xbmk_set_threads; :
fi
if [ -z "${XBMK_CACHE_MIRROR+x}" ]; then
xbmk_set_mirror
fi
} }
xbmk_child_set_tmp() xbmk_child_set_tmp()
{ {
badtmp="" eval "`newvar badtmp locktmp xbtmpchk`"
locktmp=""
xbtmpchk=""
xbtmpchk="`findpath "$TMPDIR" || err "!findpath $TMPDIR"`" || \ xbtmpchk="`findpath "$TMPDIR" || err "!findpath $TMPDIR"`" || \
err "!findpath '$TMPDIR'" "xbmk_child_set_tmp" "$@" err "!findpath '$TMPDIR'" "xbmk_child_set_tmp" "$@"
@@ -250,15 +143,12 @@ xbmk_child_set_tmp()
err "can't read '$xbmklock'" "xbmk_child_set_tmp" "$@" err "can't read '$xbmklock'" "xbmk_child_set_tmp" "$@"
if [ "$locktmp" != "$xbtmpchk" ]; then if [ "$locktmp" != "$xbtmpchk" ]; then
badtmp="TMPDIR '$xbtmpchk' changed; was '$locktmp'" badtmp="TMPDIR '$xbtmpchk' changed; was '$locktmp'"
printf "bad TMPDIR init, '%s': %s\n" "$TMPDIR" "$badtmp" 1>&2 printf "bad TMPDIR init, '%s': %s\n" "$TMPDIR" "$badtmp" 1>&2
err "'$xbmklock' present with bad tmpdir. is a build running?" err "'$xbmklock' present with bad tmpdir. is a build running?"
fi fi
xbtmp="$xbtmpchk" xbtmp="$xbtmpchk"
export TMPDIR="$xbtmpchk" export TMPDIR="$xbtmpchk"
} }
@@ -267,7 +157,7 @@ xbmk_parent_set_env()
xbmk_parent_check_tmp xbmk_parent_check_tmp
printf "%s\n" "$xbtmp" > "$xbmklock" || \ printf "%s\n" "$xbtmp" > "$xbmklock" || \
err "cannot create '$xbmklock'" xbmk_set_env "$@"; : err "cannot create '$xbmklock'" set_env "$@"; :
# not really critical for security, but it's a barrier # not really critical for security, but it's a barrier
# against the user to make them think twice before deleting it # against the user to make them think twice before deleting it
@@ -275,15 +165,11 @@ xbmk_parent_set_env()
x_ chmod -w "$xbmklock" x_ chmod -w "$xbmklock"
xbmk_parent_set_export forx 'xbmk_%s' parent_set_export set_version
xbmk_set_version remkdir "$xbtmp" "$xbtmp/xbmkpath"
remkdir "$xbtmp" "$xbtmp/gnupath" "$xbtmp/xbmkpath" forx 'xbmk_set_%s' pyver mirror
xbmk_set_pyver
xbmk_set_mirror
} }
xbmk_parent_check_tmp() xbmk_parent_check_tmp()
@@ -297,29 +183,20 @@ xbmk_parent_check_tmp()
x_ touch "$xbmklist" x_ touch "$xbmklist"
for xtmpdir in "$basetmp"/xbmk_*; do for xtmpdir in "$basetmp"/xbmk_*; do
[ ! -e "$xtmpdir" ] || \
if [ -e "$xtmpdir" ]; then
printf "%s\n" "$xtmpdir" >> "$xbmklist" || \ printf "%s\n" "$xtmpdir" >> "$xbmklist" || \
err "can't write '$xtmpdir' to '$xbmklist'" \ err "can't write '$xtmpdir' to '$xbmklist'" \
"xbmk_parent_check_tmp" "$@"; : "xbmk_parent_check_tmp" "$@"; :
fi
done done
# set up a unified temporary directory, for common deletion later: # set up a unified temporary directory, for common deletion later:
export TMPDIR="`x_ mktemp -d -t xbmk_XXXXXXXX`" || \ export TMPDIR="`x_ mktemp -d -t xbmk_XXXXXXXX`" || \
err "can't export TMPDIR" "xbmk_parent_check_tmp" "$@" err "can't export TMPDIR" "xbmk_parent_check_tmp" "$@"
xbtmp="$TMPDIR" xbtmp="$TMPDIR"
while read -r xtmpdir; do while read -r xtmpdir; do
[ "$xtmpdir" = "$xbtmp" ] && \
if [ "$xtmpdir" = "$xbtmp" ]; then err "pre-existing $xbtmp" xbmk_parent_check_tmp "$@"; :
err "pre-existing '$xbtmp'" "xbmk_parent_check_tmp" "$@"
fi
done < "$xbmklist" || \ done < "$xbmklist" || \
err "Can't read xbmklist: '$xbmklist'" "xbmk_parent_check_tmp" "$@" err "Can't read xbmklist: '$xbmklist'" "xbmk_parent_check_tmp" "$@"
@@ -330,133 +207,84 @@ xbmk_parent_set_export()
{ {
export XBMK_CACHE="$xbmkpwd/cache" export XBMK_CACHE="$xbmkpwd/cache"
if [ -e "$XBMK_CACHE" ] && \ [ -e "$XBMK_CACHE" ] && [ ! -d "$XBMK_CACHE" ] && \
[ ! -d "$XBMK_CACHE" ]; then
err "cachedir '$XBMK_CACHE' is a file" \ err "cachedir '$XBMK_CACHE' is a file" \
"xbmk_parent_set_export" "$@" "xbmk_parent_set_export" "$@"
fi
export PATH="$xbtmp/xbmkpath:$xbtmp/gnupath:$PATH" export PATH="$xbtmp/xbmkpath:$PATH"
xbmkpath="$PATH" xbmkpath="$PATH"
# if "y": a coreboot target won't be built if target.cfg says release=n # if "y": a coreboot target won't be built if target.cfg says release=n
# (this is used to exclude certain build targets from releases) # (this is used to exclude certain build targets from releases)
if [ -z "${XBMK_RELEASE+x}" ]; then [ -z "${XBMK_RELEASE+x}" ] && \
export XBMK_RELEASE="n" export XBMK_RELEASE="n"
fi [ "$XBMK_RELEASE" = "Y" ] && \
if [ "$XBMK_RELEASE" = "Y" ]; then
export XBMK_RELEASE="y" export XBMK_RELEASE="y"
fi [ "$XBMK_RELEASE" != "y" ] && \
export XBMK_RELEASE="n"; :
if [ "$XBMK_RELEASE" != "y" ]; then
export XBMK_RELEASE="n"
fi
} }
xbmk_set_threads() set_threads()
{ {
if [ -z "${XBMK_THREADS+x}" ]; then [ -z "${XBMK_THREADS+x}" ] && \
export XBMK_THREADS=1 export XBMK_THREADS=1
fi expr "X$XBMK_THREADS" : "X-\{0,1\}[0123456789][0123456789]*$" \
1>/dev/null 2>/dev/null || \
if ! expr "X$XBMK_THREADS" : "X-\{0,1\}[0123456789][0123456789]*$" \ export XBMK_THREADS=1; :
1>/dev/null 2>/dev/null; then
export XBMK_THREADS=1
fi
} }
xbmk_set_version() xbmk_set_version()
{ {
version_="$version" version_="$version"
[ ! -e ".git" ] || \
if [ -e ".git" ]; then
version="$(git describe --tags HEAD 2>&1)" || \ version="$(git describe --tags HEAD 2>&1)" || \
version="git-$(git rev-parse HEAD 2>&1)" || \ version="git-$(git rev-parse HEAD 2>&1)" || \
version="$version_" version="$version_"
fi
versiondate_="$versiondate" versiondate_="$versiondate"
[ ! -e ".git" ] || \
if [ -e ".git" ]; then
versiondate="$(git show --no-patch --no-notes \ versiondate="$(git show --no-patch --no-notes \
--pretty='%ct' HEAD)" || versiondate="$versiondate_" --pretty='%ct' HEAD)" || versiondate="$versiondate_"
fi
if [ -z "$version" ] || \
[ -z "$versiondate" ]; then
err "version and/or versiondate unset" "xbmk_set_version" "$@"
fi
update_xbmkver "." update_xbmkver "."
relname="$projectname-$version" relname="$projectname-$version"
export LOCALVERSION="-$projectname-${version%%-*}" export LOCALVERSION="-$projectname-${version%%-*}"
} }
xbmk_set_pyver() xbmk_set_pyver()
{ {
pyver="2"
python="python3" python="python3"
pyver="2"
pyv="import sys; print(sys.version_info[:])" pyv="import sys; print(sys.version_info[:])"
if ! pybin python3 1>/dev/null; then pybin python3 1>/dev/null || \
python="python" python="python"
fi [ "$python" = "python3" ] && \
if [ "$python" = "python3" ]; then
pyver="3" pyver="3"
fi pybin "$python" 1>/dev/null || \
if ! pybin "$python" 1>/dev/null; then
pyver="" pyver=""
fi
if [ -n "$pyver" ]; then
[ -z "$pyver" ] || \
"`x_ pybin "$python"`" -c "$pyv" 1>/dev/null \ "`x_ pybin "$python"`" -c "$pyv" 1>/dev/null \
2>/dev/null || \ 2>/dev/null || \
err "Can't detect Python version." "xbmk_set_pyver" "$@" err "Can't detect Python version." "xbmk_set_pyver" "$@"
fi
if [ -n "$pyver" ]; then if [ -n "$pyver" ]; then
pyver="$("$(pybin "$python")" -c "$pyv" | awk '{print $1}')" pyver="$("$(pybin "$python")" -c "$pyv" | awk '{print $1}')"
pyver="${pyver#(}" pyver="${pyver#(}"
pyver="${pyver%,}" pyver="${pyver%,}"
fi fi
[ "${pyver%%.*}" != "3" ] && \
if [ "${pyver%%.*}" != "3" ]; then
err "Bad python version (must by 3.x)" "xbmk_set_pyver" "$@" err "Bad python version (must by 3.x)" "xbmk_set_pyver" "$@"
fi
# set up python in PATH (environmental variable): # set up python in PATH (environmental variable):
( (
x_ cd "$xbtmp/xbmkpath" x_ cd "$xbtmp/xbmkpath"
x_ ln -s "`x_ pybin "$python"`" python || \ x_ ln -s "`x_ pybin "$python"`" python || \
err "can't make symlink" "xbmk_set_pyver" "$@" err "can't make symlink" "xbmk_set_pyver" "$@"
) || \ ) || err "Can't link Python in $xbtmp/xbmkpath" xbmk_set_pyver "$@"; :
err "Can't link Python in $xbtmp/xbmkpath" "xbmk_set_pyver" "$@"; :
} }
# Use direct path, to prevent a hang if Python is using a virtual environment, # Use direct path, to prevent a hang if Python is using a virtual environment,
@@ -467,60 +295,37 @@ pybin()
py="import sys; quit(1) if sys.prefix == sys.base_prefix else quit(0)" py="import sys; quit(1) if sys.prefix == sys.base_prefix else quit(0)"
venv=1 venv=1
command -v "$1" 1>/dev/null 2>/dev/null || \
if ! command -v "$1" 1>/dev/null 2>/dev/null; then
venv=0 venv=0
fi
if [ $venv -gt 0 ]; then
if ! "$1" -c "$py" 1>/dev/null 2>/dev/null; then
[ $venv -lt 1 ] || \
"$1" -c "$py" 1>/dev/null 2>/dev/null || \
venv=0 venv=0
fi
fi
# ideally, don't rely on PATH or hardcoded paths if python venv.
# use the *real*, direct executable linked to by the venv symlink:
if [ $venv -gt 0 ] && \
[ -L "`command -v "$1" 2>/dev/null`" ]; then
# try the direct path from PATH first. the binary specified by venv
# can be called directly, which then removes use of the venv
if [ $venv -gt 0 ] && [ -L "`command -v "$1" 2>/dev/null`" ]; then
pypath="$(findpath \ pypath="$(findpath \
"$(command -v "$1" 2>/dev/null)" 2>/dev/null || :)" "$(command -v "$1" 2>/dev/null)" 2>/dev/null || :)"
if [ -e "$pypath" ] && [ ! -d "$pypath" ] && \
if [ -e "$pypath" ] && \
[ ! -d "$pypath" ] && \
[ -x "$pypath" ]; then [ -x "$pypath" ]; then
printf "%s\n" "$pypath" printf "%s\n" "$pypath"
return 0 return 0
fi fi
fi fi
# if python venv: fall back to common PATH directories for checking: # if python venv: fall back to common PATH directories for checking:
[ $venv -gt 0 ] && for pypath in "/usr/local/bin" "/usr/bin"; do [ $venv -gt 0 ] && for pypath in "/usr/local/bin" "/usr/bin"; do
if [ -e "$pypath/$1" ] && [ ! -d "$pypath/$1" ] && \
if [ -e "$pypath/$1" ] && \
! -d "$pypath/$1" ] && \
[ -x "$pypath/$1" ]; then [ -x "$pypath/$1" ]; then
printf "%s/%s\n" "$pypath" "$1" printf "%s/%s\n" "$pypath" "$1"
return 0 return 0
fi fi
done && return 1 done && return 1
# Defer to normal command -v if not a venv: # Defer to normal command -v if not a venv
command -v "$1" 2>/dev/null || \
if ! command -v "$1" 2>/dev/null; then return 1; :
return 1
fi
} }
xbmk_set_mirror() xbmk_set_mirror()
@@ -533,79 +338,51 @@ xbmk_set_mirror()
# it's slower, and uses more disk space, and some upstreams might not # it's slower, and uses more disk space, and some upstreams might not
# appreciate it, so it should only be used for development or archival # appreciate it, so it should only be used for development or archival
if [ -z "${XBMK_CACHE_MIRROR+x}" ]; then [ -z "${XBMK_CACHE_MIRROR+x}" ] && \
export XBMK_CACHE_MIRROR="n" export XBMK_CACHE_MIRROR="n"
fi [ "$XBMK_CACHE_MIRROR" != "y" ] && \
export XBMK_CACHE_MIRROR="n"; :
if [ "$XBMK_CACHE_MIRROR" != "y" ]; then
export XBMK_CACHE_MIRROR="n"
fi
} }
xbmk_git_init() git_init()
{ {
# the git identity check is only needed for: ./mk -b coreboot [args] # the git identity check is only needed for: "$mk" -b coreboot [args]
[ "${2-}" = "-b" ] && [ "${3-}" = "coreboot" ] && \ [ "${2-}" = "-b" ] && [ "${3-}" = "coreboot" ] && \
for gitarg in "user.name" "user.email"; do for gitarg in "user.name" "user.email"; do
git config --includes $gitarg 1>/dev/null 2>/dev/null || \
gitcmd="git config --includes $gitarg"
if ! $gitcmd 1>/dev/null 2>/dev/null; then
err "Run this first: $gitcmd \"your ${gitcmd##*.}\"" \ err "Run this first: $gitcmd \"your ${gitcmd##*.}\"" \
"xbmk_git_init" "$@" "git_init" "$@"; :
fi
done done
if [ -L ".git" ]; then [ -L ".git" ] && \
err "'$xbmkpwd/.git' is a symlink" "git_init" "$@"
err "'$xbmkpwd/.git' is a symlink" "xbmk_git_init" "$@" [ -e ".git" ] && \
fi
if [ -e ".git" ]; then
return 0 return 0
fi
# GNU-specific extensions of date are used. (
# TODO: that is a bug. fix it! export GIT_COMMITTER_DATE="@$versiondate +0000"
export GIT_AUTHOR_DATE="@$versiondate +0000"
x_ date --version | grep "GNU coreutils" 1>/dev/null 2>/dev/null || \
err "Non-GNU date implementation" "xbmk_git_init" "$@"
cdate="`x_ date -Rud @$versiondate || err "can't get date"`" || \
err "can't get date" "xbmk_git_init" "$@"
x_ git init 1>/dev/null 2>/dev/null x_ git init 1>/dev/null 2>/dev/null
x_ git add -A . 1>/dev/null 2>/dev/null x_ git add -A . 1>/dev/null 2>/dev/null
x_ git -c user.name="xbmk" -c user.email="xbmk@example.com" \ x_ git -c user.name="xbmk" -c user.email="xbmk@example.com" \
commit -m "$projectname $version" --date "$cdate" \ commit -m "$projectname $version" \
--author="xbmk <xbmk@example.com>" 1>/dev/null 2>/dev/null --author="xbmk <xbmk@example.com>" 1>/dev/null 2>/dev/null
x_ git -c user.name="xbmk" -c user.email="xbmk@example.com" \ x_ git -c user.name="xbmk" -c user.email="xbmk@example.com" \
tag -a "$version" -m "$projectname $version" \ tag -a "$version" -m "$projectname $version" \
1>/dev/null 2>/dev/null; : 1>/dev/null 2>/dev/null; :
) || err "Can't initialise workdir" git_init "$@"; :
} }
xbmk_child_exec() xchild()
{ {
xbmk_rval=0 xbmk_rval=0
( x_ ./mk "$@" ) \ ( x_ "$mk" "$@" ) || xbmk_rval=1
|| xbmk_rval=1
( x_ rm -Rf "$xbtmp" ) \ ( x_ rm -Rf "$xbtmp" ) || xbmk_rval=1
|| xbmk_rval=1 ( x_ rm -f "$xbmklock" ) || xbmk_rval=1
( x_ rm -f "$xbmklock" ) \
|| xbmk_rval=1
exit $xbmk_rval exit $xbmk_rval
} }
xbmk_init "$@"
+36 -141
View File
@@ -2,200 +2,117 @@
# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com>
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
# Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2023-2026 Leah Rowe <leah@libreboot.org>
cbcfgsdir="config/coreboot" cbcfgsdir="config/coreboot"
tmpromdel="$XBMK_CACHE/DO_NOT_FLASH" tmpromdel="$XBMK_CACHE/DO_NOT_FLASH"
nvmutil="util/nvmutil/nvmutil" nvmutil="util/nvmutil/nvmutil"
ifdtool="elf/coreboot/default/ifdtool" ifdtool="elf/coreboot/default/ifdtool"
checkvars="CONFIG_GBE_BIN_PATH" checkvars="CONFIG_GBE_BIN_PATH ${checkvarsxbmk-} ${checkvarschk-}"
if [ -n "$checkvarsxbmk" ]; then eval "`newvar archive board boarddir IFD_platform ifdprefix \
new_mac nuke tmpromdir tree xchanged $checkvars`"
checkvars="$checkvars $checkvarsxbmk"
fi
if [ -n "$checkvarschk" ]; then
checkvars="$checkvars $checkvarschk"
fi
archive=""
board=""
boarddir=""
IFD_platform=""
ifdprefix=""
new_mac=""
tmpromdir=""
tree=""
xchanged=""
eval "`setvars "" $checkvars`"
inject() inject()
{ {
remkdir "$tmpromdel" remkdir "$tmpromdel"
if [ $# -lt 1 ]; then [ $# -lt 1 ] && err "No options specified" "inject" "$@"
err "No options specified" "inject" "$@"
fi
archive="$1"; archive="$1";
new_mac="xx:xx:xx:xx:xx:xx" new_mac="xx:xx:xx:xx:xx:xx"
nuke=""
xchanged=""
[ $# -gt 1 ] && case "$2" in [ $# -gt 1 ] && case "$2" in
nuke) nuke)
new_mac="" new_mac=""
nuke="nuke" nuke="nuke"
;; ;;
setmac) setmac)
if [ $# -gt 2 ]; then if [ $# -gt 2 ]; then
new_mac="$3" && \ new_mac="$3" && \
[ -z "$new_mac" ] && \
if [ -z "$new_mac" ]; then err "Empty MAC address" "inject" "$@"; :
err "Empty MAC address specified" "inject" "$@"
fi
fi fi
;; ;;
*) *)
err "Unrecognised inject mode: '$2'" "inject" "$@" ;; err "Unrecognised inject mode: '$2'" "inject" "$@" ;;
esac esac
if [ "$new_mac" = "keep" ]; then [ "$new_mac" = "keep" ] && \
new_mac="" new_mac=""
fi
check_release check_release
if check_target; then if check_target; then
patch_release || return 0
if ! patch_release; then
return 0
fi
fi fi
[ "$xchanged" = "y" ] && \
if [ "$xchanged" = "y" ]; then
remktar remktar
fi
if [ "$xchanged" = "y" ]; then
printf "\n'%s' was modified\n" "$archive" 1>&2
else
printf "\n'%s' was NOT modified\n" "$archive" 1>&2
fi
x_ rm -Rf "$tmpromdel" x_ rm -Rf "$tmpromdel"
} }
check_release() check_release()
{ {
if [ -L "$archive" ]; then [ -L "$archive" ] && \
err "'$archive' is a symlink" "check_release" "$@" err "'$archive' is a symlink" "check_release" "$@"
fi e "$archive" f missing && \
if e "$archive" f missing; then
err "'$archive' missing" "check_release" "$@" err "'$archive' missing" "check_release" "$@"
fi
archivename="`basename "$archive" || err "Can't get '$archive' name"`" \ archivename="`basename "$archive" || err "Can't get '$archive' name"`" \
|| err "can't get '$archive' name" "check_release" "$@" || err "can't get '$archive' name" "check_release" "$@"
if [ -z "$archivename" ]; then [ -z "$archivename" ] && \
err "Can't determine archive name" "check_release" "$@" err "Can't determine archive name" "check_release" "$@"
fi
case "$archivename" in case "$archivename" in
*_src.tar.xz) *_src.tar.xz)
err "'$archive' is a src archive!" "check_release" "$@" err "'$archive' is a src archive!" "check_release" "$@"
;; ;;
grub_*|seagrub_*|custom_*|seauboot_*|seabios_withgrub_*) grub_*|seagrub_*|custom_*|seauboot_*|seabios_withgrub_*)
err "'$archive' is a ROM image" "check_release" "$@" err "'$archive' is a ROM image" "check_release" "$@"
;; ;;
*.tar.xz) _stripped_prefix="${archivename#*_}" *.tar.xz) _stripped_prefix="${archivename#*_}"
board="${_stripped_prefix%.tar.xz}" board="${_stripped_prefix%.tar.xz}"
;; ;;
*) *)
err "'$archive': cannot detect board" "check_release" "$@" err "'$archive': cannot detect board" "check_release" "$@"
;; ;;
esac; : esac; :
} }
check_target() check_target()
{ {
if [ "$board" != "${board#serprog_}" ]; then [ "$board" = "${board#serprog_}" ] || return 1
return 1
fi
boarddir="$cbcfgsdir/$board" boarddir="$cbcfgsdir/$board"
. "$boarddir/target.cfg" || \ . "$boarddir/target.cfg" || \
err "Can't read '$boarddir/target.cfg'" "check_target" "$@" err "Can't read '$boarddir/target.cfg'" "check_target" "$@"
if [ -z "$tree" ]; then [ -z "$tree" ] && \
err "tree unset in '$boarddir/target.cfg'" "check_target" "$@" err "tree unset in '$boarddir/target.cfg'" "check_target" "$@"
fi
x_ ./mk -d coreboot "$tree" x_ "$mk" -d coreboot "$tree"
ifdtool="elf/coreboot/$tree/ifdtool" ifdtool="elf/coreboot/$tree/ifdtool"
[ -n "$IFD_platform" ] && \
if [ -n "$IFD_platform" ]; then ifdprefix="-p $IFD_platform"; :
ifdprefix="-p $IFD_platform"
fi
} }
patch_release() patch_release()
{ {
if [ "$nuke" != "nuke" ]; then [ "$nuke" != "nuke" ] && \
x_ "$mk" download "$board"
x_ ./mk download "$board"
fi
has_hashes="n" has_hashes="n"
tmpromdir="$tmpromdel/bin/$board" tmpromdir="$tmpromdel/bin/$board"
remkdir "${tmpromdir%"/bin/$board"}" remkdir "${tmpromdir%"/bin/$board"}"
x_ tar -xf "$archive" -C "${tmpromdir%"/bin/$board"}" x_ tar -xf "$archive" -C "${tmpromdir%"/bin/$board"}"
for _hashes in "vendorhashes" "blobhashes"; do for _hashes in "vendorhashes" "blobhashes"; do
if e "$tmpromdir/$_hashes" f; then if e "$tmpromdir/$_hashes" f; then
has_hashes="y" has_hashes="y"
hashfile="$_hashes" hashfile="$_hashes"
@@ -203,41 +120,29 @@ patch_release()
fi fi
done done
if ! readkconfig; then readkconfig || return 1
return 1 [ -n "$new_mac" ] && [ -n "$CONFIG_GBE_BIN_PATH" ] && \
modify_mac; :
elif [ -n "$new_mac" ] && \
[ -n "$CONFIG_GBE_BIN_PATH" ]; then
modify_mac
fi
} }
readkconfig() readkconfig()
{ {
x_ rm -f "$xbtmp/cbcfg" x_ rm -f "$xbtmp/cbcfg"
fx_ scankconfig x_ find "$boarddir/config" -type f fx_ scankconfig x_ find "$boarddir/config" -type f
if e "$xbtmp/cbcfg" f missing; then e "$xbtmp/cbcfg" f missing && \
return 1 return 1
fi
. "$xbtmp/cbcfg" || \ . "$xbtmp/cbcfg" || \
err "Can't read '$xbtmp/cbcfg'" "readkconfig" "$@" err "Can't read '$xbtmp/cbcfg'" "readkconfig" "$@"
if ! setvfile "$@"; then setvfile "$@" || return 1; :
return 1
fi
} }
scankconfig() scankconfig()
{ {
for cbc in $checkvars; do for cbc in $checkvars; do
grep "$cbc" "$1" 2>/dev/null 1>>"$xbtmp/cbcfg" || : grep "$cbc" "$1" 2>/dev/null 1>>"$xbtmp/cbcfg" || :
done done
} }
@@ -246,45 +151,35 @@ modify_mac()
{ {
x_ cp "${CONFIG_GBE_BIN_PATH##*../}" "$xbtmp/gbe" x_ cp "${CONFIG_GBE_BIN_PATH##*../}" "$xbtmp/gbe"
if [ -n "$new_mac" ] && \ if [ -n "$new_mac" ] && [ "$new_mac" != "restore" ]; then
[ "$new_mac" != "restore" ]; then forx 'x_ make -C util/nvmutil %s' clean nvmutil
x_ make -C util/nvmutil clean
x_ make -C util/nvmutil
x_ "$nvmutil" "$xbtmp/gbe" setmac "$new_mac" x_ "$nvmutil" "$xbtmp/gbe" setmac "$new_mac"
fi fi
fx_ newmac x_ find "$tmpromdir" -maxdepth 1 -type f -name "*.rom" fx_ newmac x_ find "$tmpromdir" -mindepth 1 -maxdepth 1 \
-type f -name "*.rom"
printf "\nThe following GbE NVM data will be written:\n" printf "\nThe following GbE NVM data will be written:\n"
x_ "$nvmutil" "$xbtmp/gbe" dump | grep -v "bytes read from file" || : x_ "$nvmutil" "$xbtmp/gbe" dump | grep -v "bytes read from file" || :
} }
newmac() newmac()
{ {
if e "$1" f; then e "$1" f || return 0
xchanged="y"
xchanged="y" x_ "$ifdtool" $ifdprefix -i GbE:"$xbtmp/gbe" "$1" -O "$1"
x_ "$ifdtool" $ifdprefix -i GbE:"$xbtmp/gbe" "$1" -O "$1"
fi
} }
remktar() remktar()
{ {
( (
x_ cd "${tmpromdir%"/bin/$board"}" x_ cd "${tmpromdir%"/bin/$board"}"
printf "Re-building tar archive (please wait)\n" printf "Re-building tar archive (please wait)\n"
mkrom_tarball "bin/$board" 1>/dev/null
mkrom_tarball "bin/$board" 1>/dev/null
) || err "Cannot re-generate '$archive'" "remktar" "$@" ) || err "Cannot re-generate '$archive'" "remktar" "$@"
mv "${tmpromdir%"/bin/$board"}/bin/${relname}_${board}.tar.xz" \ mv "${tmpromdir%"/bin/$board"}/bin/${relname}_${board}.tar.xz" \
"$archive" || \ "$archive" || err "'$archive' -> Can't overwrite" "remktar" "$@"; :
err "'$archive' -> Can't overwrite" "remktar" "$@"; :
} }
+7 -22
View File
@@ -4,11 +4,7 @@
# Modifications in this version are Copyright 2021,2023-2025 Leah Rowe. # Modifications in this version are Copyright 2021,2023-2025 Leah Rowe.
# Original copyright detailed in repo: https://review.coreboot.org/coreboot/ # Original copyright detailed in repo: https://review.coreboot.org/coreboot/
MRC_board="" eval "`newvar MRC_board MRC_hash MRC_url MRC_url_bkup SHELLBALL`"
MRC_hash=""
MRC_url=""
MRC_url_bkup=""
SHELLBALL=""
extract_refcode() extract_refcode()
{ {
@@ -18,43 +14,33 @@ extract_refcode()
# and refcode is extracted from an image using the old scheme. we use # and refcode is extracted from an image using the old scheme. we use
# cbfstool from coreboot 4.11_branch, the tree used by ASUS KGPE-D16: # cbfstool from coreboot 4.11_branch, the tree used by ASUS KGPE-D16:
if [ -z "$cbfstoolref" ]; then [ -z "$cbfstoolref" ] && \
err "cbfstoolref not set" "extract_refcode" "$@" err "cbfstoolref not set" "extract_refcode" "$@"
fi
x_ xbmkdir "${_pre_dest%/*}" x_ mkdir -p "${_pre_dest%/*}"
x_ "$cbfstoolref" "$appdir/bios.bin" extract \ x_ "$cbfstoolref" "$appdir/bios.bin" extract \
-m x86 -n fallback/refcode -f "$appdir/ref" -r RO_SECTION -m x86 -n fallback/refcode -f "$appdir/ref" -r RO_SECTION
# enable the Intel GbE device, if told by offset MRC_refcode_gbe: # enable the Intel GbE device, if told by offset MRC_refcode_gbe
[ -n "$MRC_refcode_gbe" ] && \
if [ -n "$MRC_refcode_gbe" ]; then
x_ dd if="config/ifd/hp820g2/1.bin" of="$appdir/ref" bs=1 \ x_ dd if="config/ifd/hp820g2/1.bin" of="$appdir/ref" bs=1 \
seek=$MRC_refcode_gbe count=1 conv=notrunc; : seek=$MRC_refcode_gbe count=1 conv=notrunc; :
fi
x_ mv "$appdir/ref" "$_pre_dest" x_ mv "$appdir/ref" "$_pre_dest"
} }
extract_mrc() extract_mrc()
{ {
if [ -z "$MRC_board" ]; then [ -z "$MRC_board" ] && \
err "MRC_board unset" "extract_mrc" "$@" err "MRC_board unset" "extract_mrc" "$@"
[ -z "$CONFIG_MRC_FILE" ] && \
elif [ -z "$CONFIG_MRC_FILE" ]; then
err "CONFIG_MRC_FILE unset" "extract_mrc" "$@" err "CONFIG_MRC_FILE unset" "extract_mrc" "$@"
fi
SHELLBALL="chromeos-firmwareupdate-$MRC_board" SHELLBALL="chromeos-firmwareupdate-$MRC_board"
( (
x_ cd "$appdir" x_ cd "$appdir"
extract_partition "${MRC_url##*/}" extract_partition "${MRC_url##*/}"
extract_archive "$SHELLBALL" . extract_archive "$SHELLBALL" .
@@ -72,7 +58,6 @@ extract_partition()
parted "${1%.zip}" 2>/dev/null | grep "ROOT-A" ) parted "${1%.zip}" 2>/dev/null | grep "ROOT-A" )
START=$(( $( echo $ROOTP | cut -f2 -d\ | tr -d "B" ) )) START=$(( $( echo $ROOTP | cut -f2 -d\ | tr -d "B" ) ))
SIZE=$(( $( echo $ROOTP | cut -f4 -d\ | tr -d "B" ) )) SIZE=$(( $( echo $ROOTP | cut -f4 -d\ | tr -d "B" ) ))
x_ dd if="${1%.zip}" of="root-a.ext2" bs=1024 \ x_ dd if="${1%.zip}" of="root-a.ext2" bs=1024 \
+79 -330
View File
@@ -11,29 +11,20 @@ grubdata="config/data/grub"
buildser() buildser()
{ {
if [ "$1" = "pico" ]; then if [ "$1" = "pico" ]; then
x_ cmake -DPICO_BOARD="$2" \ x_ cmake -DPICO_BOARD="$2" \
-DPICO_SDK_PATH="$picosdk" -B "$sersrc/build" "$sersrc" -DPICO_SDK_PATH="$picosdk" -B "$sersrc/build" "$sersrc"
x_ cmake --build "$sersrc/build" x_ cmake --build "$sersrc/build"
elif [ "$1" = "stm32" ]; then elif [ "$1" = "stm32" ]; then
x_ make -C "$sersrc" libopencm3-just-make BOARD=$2 x_ make -C "$sersrc" libopencm3-just-make BOARD=$2
x_ make -C "$sersrc" BOARD=$2 x_ make -C "$sersrc" BOARD=$2
fi fi
x_ xbmkdir "bin/serprog_$1" x_ mkdir -p "bin/serprog_$1"
x_ mv "$serx" "bin/serprog_$1/serprog_$2.${serx##*.}" x_ mv "$serx" "bin/serprog_$1/serprog_$2.${serx##*.}"
} }
copyps1bios() copyps1bios()
{ {
$if_dry_build \
return 0
remkdir "bin/playstation" remkdir "bin/playstation"
x_ cp src/pcsx-redux/src/mips/openbios/openbios.bin bin/playstation x_ cp src/pcsx-redux/src/mips/openbios/openbios.bin bin/playstation
@@ -47,11 +38,7 @@ copyps1bios()
mkpayload_grub() mkpayload_grub()
{ {
grub_modules="" eval "`newvar grub_modules grub_install_modules`"
grub_install_modules=""
$if_dry_build \
return 0
. "$grubdata/module/$tree" || \ . "$grubdata/module/$tree" || \
err "Can't read '$grubdata/module/$tree'" "mkpayload_grub" "$@" err "Can't read '$grubdata/module/$tree'" "mkpayload_grub" "$@"
@@ -69,112 +56,65 @@ mkpayload_grub()
corebootpremake() corebootpremake()
{ {
if [ "$XBMK_RELEASE" = "y" ] && \ [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ] && \
[ "$release" = "n" ]; then
return 0 return 0
fi
$if_not_dry_build \
cook_coreboot_config
fx_ check_coreboot_util printf "cbfstool\nifdtool\n" fx_ check_coreboot_util printf "cbfstool\nifdtool\n"
printf "%s\n" "${version%%-*}" > "$srcdir/.coreboot-version" || \ printf "%s\n" "${version%%-*}" > "$srcdir/.coreboot-version" || \
err "!mk $srcdir .coreboot-version" "corebootpremake" "$@" err "!mk $srcdir .coreboot-version" "corebootpremake" "$@"
if [ -z "$mode" ] && \ [ "$target" != "$tree" ] && \
[ "$target" != "$tree" ]; then x_ "$mk" download "$target"; :
x_ ./mk download "$target"
fi
}
cook_coreboot_config()
{
if [ -z "$mode" ] && \
[ -f "$srcdir/.config" ]; then
printf "CONFIG_CCACHE=y\n" >> "$srcdir/.config" || \
err "can't cook '$srcdir'" "cook_coreboot_config" "$@"
fi
} }
check_coreboot_util() check_coreboot_util()
{ {
if [ "$badhash" = "y" ]; then [ "$badhash" = "y" ] && \
x_ rm -f "elf/coreboot/$tree/$1" x_ rm -f "elf/coreboot/$tree/$1"
fi e "elf/coreboot/$tree/$1" f && \
if e "elf/coreboot/$tree/$1" f; then
return 0 return 0
fi
utilelfdir="elf/coreboot/$tree" utilelfdir="elf/coreboot/$tree"
utilsrcdir="src/coreboot/$tree/util/$1" utilsrcdir="src/coreboot/$tree/util/$1"
utilmode="" utilmode=""
[ -n "$mode" ] && \
if [ -n "$mode" ]; then
utilmode="clean" utilmode="clean"
fi
x_ make -C "$utilsrcdir" $utilmode -j$XBMK_THREADS $makeargs x_ make -C "$utilsrcdir" $utilmode -j$XBMK_THREADS $makeargs
if [ -n "$mode" ]; then if [ -n "$mode" ]; then
# TODO: is this rm command needed?
x_ rm -Rf "$utilelfdir" x_ rm -Rf "$utilelfdir"
return 0 return 0
elif [ -n "$mode" ] || [ -f "$utilelfdir/$1" ]; then
elif [ -n "$mode" ] || \
[ -f "$utilelfdir/$1" ]; then
return 0 return 0
fi fi
x_ xbmkdir "$utilelfdir" x_ mkdir -p "$utilelfdir"
x_ cp "$utilsrcdir/$1" "$utilelfdir" x_ cp "$utilsrcdir/$1" "$utilelfdir"
if [ "$1" = "cbfstool" ]; then [ "$1" = "cbfstool" ] && \
x_ cp "$utilsrcdir/rmodtool" "$utilelfdir"; :
x_ cp "$utilsrcdir/rmodtool" "$utilelfdir"
fi
} }
coreboot_pad_one_byte() coreboot_pad_one_byte()
{ {
if [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ]; then [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ] && \
return 0 return 0
fi
$if_not_dry_build \ pad_one_byte "$srcdir/build/coreboot.rom"
pad_one_byte "$srcdir/build/coreboot.rom"
} }
mkcorebootbin() mkcorebootbin()
{ {
if [ "$XBMK_RELEASE" = "y" ] && \ [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ] && \
[ "$release" = "n" ]; then
return 0 return 0
fi
$if_not_dry_build \ forx 'check_coreboot_util %s' cbfstool ifdtool
check_coreboot_util cbfstool
$if_not_dry_build \
check_coreboot_util ifdtool
for y in "$target_dir/config"/*; do for y in "$target_dir/config"/*; do
defconfig="$y" defconfig="$y"
mkcorebootbin_real mkcorebootbin_real
done done
@@ -183,138 +123,78 @@ mkcorebootbin()
mkcorebootbin_real() mkcorebootbin_real()
{ {
if [ "$target" = "$tree" ]; then [ "$target" = "$tree" ] && return 0
return 0
fi
tmprom="$xbtmp/coreboot.rom" tmprom="$xbtmp/coreboot.rom"
initmode="${defconfig##*/}" initmode="${defconfig##*/}"
displaymode="${initmode##*_}" displaymode="${initmode##*_}"
if [ "$displaymode" = "$initmode" ]; then if [ "$displaymode" = "$initmode" ]; then
# blank it for "normal" or "fspgop" configs: # blank it for "normal" or "fspgop" configs:
displaymode="" displaymode=""
fi fi
initmode="${initmode%%_*}" initmode="${initmode%%_*}"
cbfstool="elf/coreboot/$tree/cbfstool" cbfstool="elf/coreboot/$tree/cbfstool"
# cbfstool option backends, if they exist # cbfstool option backends, if they exist
cbfscfg="config/coreboot/$target/cbfs.cfg" cbfscfg="config/coreboot/$target/cbfs.cfg"
elfrom="elf/coreboot/$tree/$target/$initmode" elfrom="elf/coreboot/$tree/$target/$initmode"
[ -n "$displaymode" ] && \
if [ -n "$displaymode" ]; then
elfrom="${elfrom}_$displaymode" elfrom="${elfrom}_$displaymode"
fi
elfrom="$elfrom/coreboot.rom" elfrom="$elfrom/coreboot.rom"
$if_not_dry_build \ x_ cp "$elfrom" "$tmprom"
x_ cp "$elfrom" "$tmprom" unpad_one_byte "$tmprom"
$if_not_dry_build \ [ -n "$payload_uboot" ] && [ "$payload_uboot" != "amd64" ] && \
unpad_one_byte "$tmprom" [ "$payload_uboot" != "i386" ] && [ "$payload_uboot" != "arm64" ] \
&& err "'$target' defines bad u-boot type '$payload_uboot'" \
if [ -n "$payload_uboot" ] && \
[ "$payload_uboot" != "amd64" ] && \
[ "$payload_uboot" != "i386" ] && \
[ "$payload_uboot" != "arm64" ]; then
err "'$target' defines bad u-boot type '$payload_uboot'" \
"mkcorebootbin_real" "$@" "mkcorebootbin_real" "$@"
fi
if [ -n "$payload_uboot" ] && \
[ "$payload_uboot" != "arm64" ]; then
[ -n "$payload_uboot" ] && [ "$payload_uboot" != "arm64" ] && \
payload_seabios="y" payload_seabios="y"
fi
if [ -z "$uboot_config" ]; then
[ -z "$uboot_config" ] && \
uboot_config="default" uboot_config="default"
fi [ "$payload_grub" = "y" ] && \
if [ "$payload_grub" = "y" ]; then
payload_seabios="y" payload_seabios="y"
fi [ "$payload_seabios" = "y" ] && [ "$payload_uboot" = "arm64" ] && \
err "$target: U-Boot arm / SeaBIOS/GRUB both enabled" \
if [ "$payload_seabios" = "y" ] && \ "mkcorebootbin_real" "$@"
[ "$payload_uboot" = "arm64" ]; then
$if_not_dry_build \
err "$target: U-Boot arm / SeaBIOS/GRUB both enabled" \
"mkcorebootbin_real" "$@"
fi
if [ -z "$grub_scan_disk" ]; then
[ -z "$grub_scan_disk" ] && \
grub_scan_disk="nvme ahci ata" grub_scan_disk="nvme ahci ata"
fi [ -z "$grubtree" ] && \
if [ -z "$grubtree" ]; then
grubtree="default" grubtree="default"
fi
grubelf="elf/grub/$grubtree/$grubtree/payload/grub.elf" grubelf="elf/grub/$grubtree/$grubtree/payload/grub.elf"
if [ "$payload_memtest" != "y" ]; then [ "$payload_memtest" != "y" ] && \
payload_memtest="n" payload_memtest="n"
fi [ "$(uname -m)" != "x86_64" ] && \
if [ "$(uname -m)" != "x86_64" ]; then
payload_memtest="n" payload_memtest="n"
fi
if [ "$payload_grubsea" = "y" ] && \
[ "$initmode" = "normal" ]; then
[ "$payload_grubsea" = "y" ] && [ "$initmode" = "normal" ] && \
payload_grubsea="n" payload_grubsea="n"
fi [ "$payload_grub" != "y" ] && \
if [ "$payload_grub" != "y" ]; then
payload_grubsea="n" payload_grubsea="n"
fi
$if_dry_build \
return 0
if [ -f "$cbfscfg" ]; then
[ -f "$cbfscfg" ] && \
dx_ add_cbfs_option "$cbfscfg" dx_ add_cbfs_option "$cbfscfg"
fi
if grep "CONFIG_PAYLOAD_NONE=y" "$defconfig"; then if grep "CONFIG_PAYLOAD_NONE=y" "$defconfig"; then
if [ "$payload_seabios" = "y" ]; then if [ "$payload_seabios" = "y" ]; then
pname="seabios" pname="seabios"
add_seabios add_seabios
fi fi
if [ "$payload_uboot" = "arm64" ]; then if [ "$payload_uboot" = "arm64" ]; then
pname="uboot" pname="uboot"
add_uboot "" fallback/payload default \
add_uboot "$target" u-boot.elf
fi fi
else else
pname="custom" pname="custom"
cprom cprom
fi; : fi; :
} }
@@ -323,15 +203,10 @@ mkcorebootbin_real()
add_cbfs_option() add_cbfs_option()
{ {
# TODO: input sanitization (currently mitigated by careful config)
op_name="`printf "%s\n" "$1" | awk '{print $1}'`" op_name="`printf "%s\n" "$1" | awk '{print $1}'`"
op_arg="`printf "%s\n" "$1" | awk '{print $2}'`" op_arg="`printf "%s\n" "$1" | awk '{print $2}'`"
if [ -z "$op_name" ] || \ if [ -z "$op_name" ] || [ -z "$op_arg" ]; then
[ -z "$op_arg" ]; then
return 0 return 0
fi fi
@@ -350,92 +225,53 @@ add_cbfs_option()
add_seabios() add_seabios()
{ {
if [ -n "$payload_uboot" ] && \ [ -n "$payload_uboot" ] && [ "$payload_uboot" != "arm64" ] && \
[ "$payload_uboot" != "arm64" ]; then [ "$displaymode" != "txtmode" ] && [ "$initmode" != "normal" ] && \
add_uboot_x86 # u-boot first, due to fixed cbfs offset
# we must add u-boot first, because it's added as a flat
# binary at a specific offset for secondary program loader
$if_not_dry_build \
add_uboot
fi
_seabioself="elf/seabios/default/default/$initmode/bios.bin.elf" _seabioself="elf/seabios/default/default/$initmode/bios.bin.elf"
[ "$initmode" = "fspgop" ] && \
if [ "$initmode" = "fspgop" ]; then
_seabioself="elf/seabios/default/default/libgfxinit/bios.bin.elf" _seabioself="elf/seabios/default/default/libgfxinit/bios.bin.elf"
fi
_seaname="fallback/payload" _seaname="fallback/payload"
[ "$payload_grubsea" = "y" ] && \
if [ "$payload_grubsea" = "y" ]; then
_seaname="seabios.elf" _seaname="seabios.elf"
fi
cbfs "$tmprom" "$_seabioself" "$_seaname" cbfs "$tmprom" "$_seabioself" "$_seaname"
x_ "$cbfstool" "$tmprom" add-int -i 3000 -n etc/ps2-keyboard-spinup x_ "$cbfstool" "$tmprom" add-int -i 3000 -n etc/ps2-keyboard-spinup
opexec="2" opexec="2"
[ "$initmode" = "vgarom" ] && \
if [ "$initmode" = "vgarom" ]; then
opexec="0" opexec="0"
fi
x_ "$cbfstool" "$tmprom" add-int -i $opexec -n etc/pci-optionrom-exec x_ "$cbfstool" "$tmprom" add-int -i $opexec -n etc/pci-optionrom-exec
x_ "$cbfstool" "$tmprom" add-int -i 0 -n etc/optionroms-checksum x_ "$cbfstool" "$tmprom" add-int -i 0 -n etc/optionroms-checksum
if [ "$initmode" = "libgfxinit" ] || [ "$initmode" = "fspgop" ]; then
if [ "$initmode" = "libgfxinit" ] || \
[ "$initmode" = "fspgop" ]; then
cbfs "$tmprom" "$seavgabiosrom" vgaroms/seavgabios.bin raw cbfs "$tmprom" "$seavgabiosrom" vgaroms/seavgabios.bin raw
fi fi
if [ "$payload_memtest" = "y" ]; then [ "$payload_memtest" = "y" ] && \
# because why not have memtest?
# we can have it. we are entitled to it.
# so we shall have it, yes. having memtest86+
# in your boot flash makes you a better person.
cbfs "$tmprom" "elf/memtest86plus/memtest.bin" img/memtest cbfs "$tmprom" "elf/memtest86plus/memtest.bin" img/memtest
fi
if [ "$payload_grub" = "y" ]; then
[ "$payload_grub" = "y" ] && \
add_grub add_grub
fi
if [ "$payload_grubsea" != "y" ]; then [ "$payload_grubsea" != "y" ] && \
cprom # seabios, but don't load grub/u-boot first
# ROM image where SeaBIOS doesn't load grub/u-boot first. # now make seauboot(u-boot loaded by seabios) and SeaGRUB (GRUB loaded
# U-Boot/GRUB available in ESC menu if enabled for the board # by SeaBIOS) images; users can bypass via ESC to boot from SeaBIOS
cprom
fi
# now make "SeaUBoot" and "SeaGRUB" images, where SeaBIOS auto-loads
# SeaBIOS or U-Boot first; users can bypass this by pressing ESC
# in the SeaBIOS menu, to boot devices using SeaBIOS itself instead
if [ "$payload_uboot" = "amd64" ] && \ if [ "$payload_uboot" = "amd64" ] && \
[ "$displaymode" != "txtmode" ] && \ [ "$displaymode" != "txtmode" ] && \
[ "$initmode" != "normal" ] && \ [ "$initmode" != "normal" ] && [ "$payload_grubsea" != "y" ]; then
[ "$payload_grubsea" != "y" ]; then
pname="seauboot" pname="seauboot"
cprom "seauboot" cprom "seauboot"
fi fi
if [ "$payload_grub" = "y" ]; then if [ "$payload_grub" = "y" ]; then
pname="seagrub" pname="seagrub"
mkseagrub mkseagrub
fi fi
} }
@@ -444,11 +280,8 @@ add_grub()
{ {
# path in CBFS for the GRUB payload # path in CBFS for the GRUB payload
_grubname="img/grub2" _grubname="img/grub2"
[ "$payload_grubsea" = "y" ] && \
if [ "$payload_grubsea" = "y" ]; then
_grubname="fallback/payload" _grubname="fallback/payload"
fi
cbfs "$tmprom" "$grubelf" "$_grubname" cbfs "$tmprom" "$grubelf" "$_grubname"
@@ -458,107 +291,44 @@ add_grub()
cbfs "$tmprom" "$xbtmp/tmpcfg" scan.cfg raw cbfs "$tmprom" "$xbtmp/tmpcfg" scan.cfg raw
if [ "$initmode" != "normal" ] && \ [ "$initmode" != "normal" ] && [ "$displaymode" != "txtmode" ] && \
[ "$displaymode" != "txtmode" ]; then
cbfs "$tmprom" "$grubdata/background/background1280x800.png" \ cbfs "$tmprom" "$grubdata/background/background1280x800.png" \
"background.png" raw "background.png" raw; :
fi
} }
mkseagrub() mkseagrub()
{ {
if [ "$payload_grubsea" = "y" ]; then if [ "$payload_grubsea" = "y" ]; then
pname="grub" pname="grub"
else else
cbfs "$tmprom" "$grubdata/bootorder" bootorder raw cbfs "$tmprom" "$grubdata/bootorder" bootorder raw
fi fi
fx_ cprom x_ find "$grubdata/keymap" -type f -name "*.gkb" fx_ cprom x_ find "$grubdata/keymap" -type f -name "*.gkb"
} }
add_uboot_x86()
{
[ "$payload_uboot" = "amd64" ] && \
add_uboot "-l 0x1110000 -e 0x1110000" "img/u-boot" \
"x86_64" "amd64coreboot" "u-boot-x86-with-spl.bin"
[ "$payload_uboot" = "i386" ] && \
add_uboot "-l 0x1110000 -e 0x1110000" "u-boot" "x86" \
"i386coreboot" "u-boot-dtb.bin"; :
}
add_uboot() add_uboot()
{ {
if [ "$displaymode" = "txtmode" ]; then ubootelf="elf/u-boot/$3/$4/$uboot_config/$5"
[ ! -f "$ubootelf" ] && \
ubootelf="${ubootelf%.elf}" # hack (fix arm64 build)
printf "cb/%s: Can't use U-Boot in text mode\n" "$target" 1>&2 cbfs "$tmprom" "$ubootelf" "$2" $1
[ "$payload_seabios" != "y" ] && \
return 0 cprom; :
elif [ "$initmode" = "normal" ]; then
printf "cb/%s: Can't use U-Boot in normal initmode\n" \
"$target" 1>&2
return 0
fi
# TODO: re-work to allow each coreboot target to say which ub tree
# instead of hardcoding as in the current logic below:
# aarch64 targets:
ubcbfsargs=""
ubpath="fallback/payload"
ubtree="default"
ubtarget="$target"
# override for x86/x86_64 targets:
if [ -n "$payload_uboot" ] && [ "$payload_uboot" != "arm64" ]; then
ubcbfsargs="-l 0x1110000 -e 0x1110000" # 64-bit and 32-bit
# on 64-bit, 0x1120000 is the SPL, with a stub that
# loads it, located at 0x1110000
ubpath="img/u-boot" # 64-bit
ubtree="x86_64"
ubtarget="amd64coreboot"
if [ "$payload_uboot" = "i386" ]; then
# override for 32-bit
ubpath="u-boot"
ubtree="x86"
ubtarget="i386coreboot"; :
fi
fi
ubdir="elf/u-boot/$ubtree/$ubtarget/$uboot_config"
# aarch64 targets:
ubootelf="$ubdir/u-boot.elf"
if [ ! -f "$ubootelf" ]; then
ubootelf="$ubdir/u-boot"
fi
# override for x86/x86_64 targets:
if [ "$payload_uboot" = "i386" ]; then
ubootelf="$ubdir/u-boot-dtb.bin"
elif [ "$payload_uboot" = "amd64" ]; then
ubootelf="$ubdir/u-boot-x86-with-spl.bin" # EFI-compatible
fi
cbfs "$tmprom" "$ubootelf" "$ubpath" $ubcbfsargs
if [ "$payload_seabios" != "y" ]; then
cprom
fi
} }
# prepare the final image in bin/ for user installation: # prepare the final image in bin/ for user installation:
cprom() cprom()
{ {
cpcmd="cp" cpcmd="cp"
@@ -566,14 +336,9 @@ cprom()
tmpnew="" tmpnew=""
newrom="bin/$target/${pname}_${target}_$initmode.rom" newrom="bin/$target/${pname}_${target}_$initmode.rom"
if [ -n "$displaymode" ]; then [ -n "$displaymode" ] && \
newrom="${newrom%.rom}_$displaymode.rom" newrom="${newrom%.rom}_$displaymode.rom"
fi if [ $# -gt 0 ] && [ "${1%.gkb}" != "$1" ]; then
if [ $# -gt 0 ] && \
[ "${1%.gkb}" != "$1" ]; then
tmpnew="${1##*/}" tmpnew="${1##*/}"
newrom="${newrom%.rom}_${tmpnew%.gkb}.rom" newrom="${newrom%.rom}_${tmpnew%.gkb}.rom"
fi fi
@@ -581,26 +346,21 @@ cprom()
irom="$tmprom" irom="$tmprom"
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
irom="$(mktemp || err "!mk irom, $(echo "$@")")" || \ irom="$(mktemp || err "!mk irom, $(echo "$@")")" || \
err "can't copy rom" "cprom" "$@" err "can't copy rom" "cprom" "$@"
x_ cp "$tmprom" "$irom" && cpcmd="mv" x_ cp "$tmprom" "$irom" && cpcmd="mv"
if [ "${1%.gkb}" != "$1" ]; then if [ "${1%.gkb}" != "$1" ]; then
cbfs "$irom" "$grubdata/keymap/$tmpnew" keymap.gkb raw cbfs "$irom" "$grubdata/keymap/$tmpnew" keymap.gkb raw
elif [ "$1" = "seauboot" ]; then elif [ "$1" = "seauboot" ]; then
cbfs "$irom" "$grubdata/bootorder_uboot" bootorder raw cbfs "$irom" "$grubdata/bootorder_uboot" bootorder raw
fi fi
fi fi
printf "Creating new %s image: '%s'\n" "$projectname" "$newrom" printf "Creating new %s image: '%s'\n" "$projectname" "$newrom"
x_ xbmkdir "bin/$target" x_ mkdir -p "bin/$target"
x_ $cpcmd "$irom" "$newrom" x_ $cpcmd "$irom" "$newrom"
} }
@@ -609,15 +369,10 @@ cbfs()
ccmd="add-payload" ccmd="add-payload"
lzma="-c lzma" lzma="-c lzma"
if [ $# -gt 3 ] && \ if [ $# -gt 3 ] && [ $# -lt 5 ]; then
[ $# -lt 5 ]; then
ccmd="add" ccmd="add"
lzma="-t $4" lzma="-t $4"
elif [ $# -gt 4 ] && [ "$5" = "0x1110000" ]; then
elif [ $# -gt 4 ] && \
[ "$5" = "0x1110000" ]; then
ccmd="add-flat-binary" && \ ccmd="add-flat-binary" && \
lzma="-c lzma -l 0x1110000 -e 0x1110000" lzma="-c lzma -l 0x1110000 -e 0x1110000"
fi fi
@@ -629,17 +384,11 @@ cbfs()
mkcoreboottar() mkcoreboottar()
{ {
$if_dry_build \ if [ "$target" = "$tree" ] || [ "$XBMK_RELEASE" != "y" ] || \
return 0
if [ "$target" = "$tree" ] || \
[ "$XBMK_RELEASE" != "y" ] || \
[ "$release" = "n" ]; then [ "$release" = "n" ]; then
return 0 return 0
fi fi
mkrom_tarball "bin/$target" mkrom_tarball "bin/$target"
x_ "$mk" inject "bin/${relname}_${target}.tar.xz" nuke
x_ ./mk inject "bin/${relname}_${target}.tar.xz" nuke
} }
+129 -488
View File
@@ -2,7 +2,7 @@
# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com>
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
# Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2023-2026 Leah Rowe <leah@libreboot.org>
# These are variables and functions, extending the functionality of # These are variables and functions, extending the functionality of
# inject.sh, to be used with lbmk; they are kept separate here, so that # inject.sh, to be used with lbmk; they are kept separate here, so that
@@ -36,147 +36,63 @@ checkvarsxbmk="CONFIG_ME_BIN_PATH CONFIG_SMSC_SCH5545_EC_FW_FILE \
CONFIG_FSP_FD_PATH CONFIG_IFD_BIN_PATH CONFIG_MRC_FILE CONFIG_FSP_M_CBFS" CONFIG_FSP_FD_PATH CONFIG_IFD_BIN_PATH CONFIG_MRC_FILE CONFIG_FSP_M_CBFS"
# lbmk-specific extensions; general variables # lbmk-specific extensions; general variables
cbdir="" eval "`newvar cbdir cbfstoolref has_hashes hashfile kbc1126_ec_dump mecleaner \
cbfstoolref="" mfs nuke rom vcfg xromsize _7ztest _dest _dl _dl_bin _me _metmp _pre_dest`"
has_hashes=""
hashfile=""
kbc1126_ec_dump=""
mecleaner=""
mfs=""
nuke=""
rom=""
vcfg=""
xromsize=""
_7ztest="" # lbmk-specific extensions; declared by pkg.cfg files in config/vendor/
_dest="" eval "`newvar DL_hash DL_url DL_url_bkup E6400_VGA_bin_hash E6400_VGA_DL_hash \
_dl="" E6400_VGA_DL_url E6400_VGA_DL_url_bkup E6400_VGA_offset E6400_VGA_romname \
_dl_bin="" EC_FW1_hash EC_FW2_hash EC_hash EC_url EC_url_bkup FSPFD_hash \
_me="" FSPM_bin_hash FSPS_bin_hash ME11bootguard ME11delta ME11pch ME11sku \
_metmp="" ME11version ME_bin_hash MEcheck MEclean MEshrink MRC_bin_hash \
_pre_dest="" MRC_refcode_cbtree MRC_refcode_gbe REF_bin_hash SCH5545EC_bin_hash \
SCH5545EC_DL_hash SCH5545EC_DL_url SCH5545EC_DL_url_bkup TBFW_bin_hash \
# lbmk-specific extensions; declared in pkg.cfg files in config/vendor/ TBFW_hash TBFW_size TBFW_url TBFW_url_bkup XBMKmecleaner`"
DL_hash=""
DL_url=""
DL_url_bkup=""
E6400_VGA_bin_hash=""
E6400_VGA_DL_hash=""
E6400_VGA_DL_url=""
E6400_VGA_DL_url_bkup=""
E6400_VGA_offset=""
E6400_VGA_romname=""
EC_FW1_hash=""
EC_FW2_hash=""
EC_hash=""
EC_url=""
EC_url_bkup=""
FSPFD_hash=""
FSPM_bin_hash=""
FSPS_bin_hash=""
ME11bootguard=""
ME11delta=""
ME11pch=""
ME11sku=""
ME11version=""
ME_bin_hash=""
MEcheck=""
MEclean=""
MEshrink=""
MRC_bin_hash=""
MRC_refcode_cbtree=""
MRC_refcode_gbe=""
REF_bin_hash=""
SCH5545EC_bin_hash=""
SCH5545EC_DL_hash=""
SCH5545EC_DL_url=""
SCH5545EC_DL_url_bkup=""
TBFW_bin_hash=""
TBFW_hash=""
TBFW_size=""
TBFW_url=""
TBFW_url_bkup=""
XBMKmecleaner=""
download() download()
{ {
if [ $# -lt 1 ]; then [ $# -lt 1 ] && err "No argument given" "download" "$@"
err "No argument given" "download" "$@"
fi
export PATH="$PATH:/sbin" export PATH="$PATH:/sbin"
board="$1" board="$1"
if check_target; then check_target && readkconfig download; :
readkconfig download
fi
} }
getfiles() getfiles()
{ {
if [ -n "$CONFIG_HAVE_ME_BIN" ];then [ -n "$CONFIG_HAVE_ME_BIN" ] && \
fetch intel_me "$DL_url" "$DL_url_bkup" "$DL_hash" \ fetch intel_me "$DL_url" "$DL_url_bkup" "$DL_hash" \
"$CONFIG_ME_BIN_PATH" curl "$ME_bin_hash" "$CONFIG_ME_BIN_PATH" curl "$ME_bin_hash"
fi [ -n "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" ] && \
if [ -n "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" ]; then
fetch sch5545ec "$SCH5545EC_DL_url" "$SCH5545EC_DL_url_bkup" \ fetch sch5545ec "$SCH5545EC_DL_url" "$SCH5545EC_DL_url_bkup" \
"$SCH5545EC_DL_hash" "$CONFIG_SMSC_SCH5545_EC_FW_FILE" \ "$SCH5545EC_DL_hash" "$CONFIG_SMSC_SCH5545_EC_FW_FILE" \
"curl" "$SCH5545EC_bin_hash" "curl" "$SCH5545EC_bin_hash"
fi [ -n "$CONFIG_KBC1126_FW1" ] && \
if [ -n "$CONFIG_KBC1126_FW1" ]; then
fetch kbc1126ec "$EC_url" "$EC_url_bkup" "$EC_hash" \ fetch kbc1126ec "$EC_url" "$EC_url_bkup" "$EC_hash" \
"$CONFIG_KBC1126_FW1" curl "$EC_FW1_hash" "$CONFIG_KBC1126_FW1" curl "$EC_FW1_hash"
fi [ -n "$CONFIG_KBC1126_FW2" ] && \
if [ -n "$CONFIG_KBC1126_FW2" ]; then
fetch kbc1126ec "$EC_url" "$EC_url_bkup" "$EC_hash" \ fetch kbc1126ec "$EC_url" "$EC_url_bkup" "$EC_hash" \
"$CONFIG_KBC1126_FW2" curl "$EC_FW2_hash" "$CONFIG_KBC1126_FW2" curl "$EC_FW2_hash"
fi [ -n "$CONFIG_VGA_BIOS_FILE" ] && \
if [ -n "$CONFIG_VGA_BIOS_FILE" ]; then
fetch e6400vga "$E6400_VGA_DL_url" "$E6400_VGA_DL_url_bkup" \ fetch e6400vga "$E6400_VGA_DL_url" "$E6400_VGA_DL_url_bkup" \
"$E6400_VGA_DL_hash" "$CONFIG_VGA_BIOS_FILE" "curl" \ "$E6400_VGA_DL_hash" "$CONFIG_VGA_BIOS_FILE" "curl" \
"$E6400_VGA_bin_hash" "$E6400_VGA_bin_hash"
fi [ -n "$CONFIG_HAVE_MRC" ] && \
if [ -n "$CONFIG_HAVE_MRC" ]; then
fetch "mrc" "$MRC_url" "$MRC_url_bkup" "$MRC_hash" \ fetch "mrc" "$MRC_url" "$MRC_url_bkup" "$MRC_hash" \
"$CONFIG_MRC_FILE" "curl" "$MRC_bin_hash" "$CONFIG_MRC_FILE" "curl" "$MRC_bin_hash"
fi [ -n "$CONFIG_REFCODE_BLOB_FILE" ] && \
if [ -n "$CONFIG_REFCODE_BLOB_FILE" ]; then
fetch "refcode" "$MRC_url" "$MRC_url_bkup" "$MRC_hash" \ fetch "refcode" "$MRC_url" "$MRC_url_bkup" "$MRC_hash" \
"$CONFIG_REFCODE_BLOB_FILE" "curl" "$REF_bin_hash" "$CONFIG_REFCODE_BLOB_FILE" "curl" "$REF_bin_hash"
fi [ -n "$CONFIG_LENOVO_TBFW_BIN" ] && \
if [ -n "$CONFIG_LENOVO_TBFW_BIN" ]; then
fetch "tbfw" "$TBFW_url" "$TBFW_url_bkup" "$TBFW_hash" \ fetch "tbfw" "$TBFW_url" "$TBFW_url_bkup" "$TBFW_hash" \
"$CONFIG_LENOVO_TBFW_BIN" "curl" "$TBFW_bin_hash" "$CONFIG_LENOVO_TBFW_BIN" "curl" "$TBFW_bin_hash"
fi [ -n "$CONFIG_FSP_M_FILE" ] && \
if [ -n "$CONFIG_FSP_M_FILE" ]; then
fetch "fsp" "$CONFIG_FSP_FD_PATH" "$CONFIG_FSP_FD_PATH" \ fetch "fsp" "$CONFIG_FSP_FD_PATH" "$CONFIG_FSP_FD_PATH" \
"$FSPFD_hash" "$CONFIG_FSP_M_FILE" "copy" "$FSPM_bin_hash" "$FSPFD_hash" "$CONFIG_FSP_M_FILE" "copy" "$FSPM_bin_hash"
fi [ -n "$CONFIG_FSP_S_FILE" ] && \
if [ -n "$CONFIG_FSP_S_FILE" ]; then
fetch "fsp" "$CONFIG_FSP_FD_PATH" "$CONFIG_FSP_FD_PATH" \ fetch "fsp" "$CONFIG_FSP_FD_PATH" "$CONFIG_FSP_FD_PATH" \
"$FSPFD_hash" "$CONFIG_FSP_S_FILE" "copy" "$FSPS_bin_hash" "$FSPFD_hash" "$CONFIG_FSP_S_FILE" copy "$FSPS_bin_hash"; :
fi
} }
fetch() fetch()
@@ -190,137 +106,74 @@ fetch()
dlop="$6" dlop="$6"
binsum="$7" binsum="$7"
if [ -z "$binsum" ]; then [ -z "$binsum" ] && err "binsum is empty (no checksum)" "fetch" "$@"
err "binsum is empty (no checksum)" "fetch" "$@"
fi
_dl="$XBMK_CACHE/file/$dlsum" # internet file to extract from e.g. .exe _dl="$XBMK_CACHE/file/$dlsum" # internet file to extract from e.g. .exe
_dl_bin="$XBMK_CACHE/file/$binsum" # extracted file e.g. me.bin _dl_bin="$XBMK_CACHE/file/$binsum" # extracted file e.g. me.bin
if [ "$5" = "/dev/null" ]; then [ "$5" = "/dev/null" ] && return 0 # fetch/extract disabled
return 0
fi
# an extracted vendor file will be placed in pre_dest first, for # an extracted vendor file will be placed in pre_dest first, for
# verifying its checksum. if it matches, it is later moved to _dest: # verifying its checksum. if it matches, it is later moved to _dest
remkdir "${_pre_dest%/*}" "$appdir" remkdir "${_pre_dest%/*}" "$appdir"
# HACK: if grabbing fsp from coreboot, fix the path for lbmk: # HACK: if grabbing fsp from coreboot, fix the path for lbmk
[ "$dl_type" = "fsp" ] && for bkup in "" "_bkup"; do
if [ "$dl_type" = "fsp" ]; then eval "dl$bkup=\"\${dl$bkup##*../}\""
eval "_cdp=\"\$dl$bkup\""
dl="${dl##*../}"
_cdp="$dl"
if [ ! -f "$_cdp" ]; then
[ ! -f "$_cdp" ] && \
_cdp="$cbdir/$_cdp" _cdp="$cbdir/$_cdp"
fi [ -f "$_cdp" ] && \
eval "dl$bkup=\"\$_cdp\""; :
if [ -f "$_cdp" ]; then done; :
dl="$_cdp"
fi
dl_bkup="${dl_bkup##*../}"
_cdp="$dl_bkup"
if [ ! -f "$_cdp" ]; then
_cdp="$cbdir/$_cdp"
fi
if [ -f "$_cdp" ]; then
dl_bkup="$_cdp"; :
fi
fi
# download the file (from the internet) to extract from: # download the file (from the internet) to extract from:
xbget "$dlop" "$dl" "$dl_bkup" "$_dl" "$dlsum" xbget "$dlop" "$dl" "$dl_bkup" "$_dl" "$dlsum"
x_ rm -Rf "${_dl}_extracted" x_ rm -Rf "${_dl}_extracted"
# skip extraction if a cached extracted file exists: # skip extraction if a cached extracted file exists:
( xbget copy "$_dl_bin" "$_dl_bin" "$_dest" "$binsum" 2>/dev/null ) || : ( xbget copy "$_dl_bin" "$_dl_bin" "$_dest" "$binsum" 2>/dev/null ) || :
[ -f "$_dest" ] && \
if [ -f "$_dest" ]; then
return 0 return 0
fi
x_ xbmkdir "${_dest%/*}" x_ mkdir -p "${_dest%/*}"
if [ "$dl_type" != "fsp" ]; then
[ "$dl_type" = "fsp" ] || \
extract_archive "$_dl" "$appdir" || \ extract_archive "$_dl" "$appdir" || \
[ "$dl_type" = "e6400vga" ] || \ [ "$dl_type" = "e6400vga" ] || \
err "$_dest $dl_type: !extract" "fetch" "$@" err "$_dest $dl_type: !extract" "fetch" "$@"
fi
x_ extract_$dl_type "$_dl" "$appdir" x_ extract_$dl_type "$_dl" "$appdir"
set -u -e set -u -e
# some functions don't output directly to the given file, _pre_dest. # some functions don't output directly to the given file, _pre_dest.
# instead, they put multiple files there, but we need the one matching # instead, they put multiple files there, but we need the one matching
# the given hashsum. So, search for a matching file via bruteforce: # the given hashsum. So, search for a matching file via bruteforce:
( fx_ "mkdst $binsum" x_ find "${_pre_dest%/*}" -type f ) || : ( fx_ "mkdst $binsum" x_ find "${_pre_dest%/*}" -type f ) || :
if ! bad_checksum "$binsum" "$_dest"; then bad_checksum "$binsum" "$_dest" || \
[ ! -f "$_dest" ] || return 0; :
if [ -f "$_dest" ]; then x_ rm -f "$_dest"
return 0
fi
fi
if [ -z "$binsum" ]; then
printf "'%s': checksum undefined\n" "$_dest" 1>&2
fi
if [ -L "$_dest" ]; then
printf "WARNING: '%s' is a link!\n" "$_dest" 1>&2
else
x_ rm -f "$_dest"
fi
[ -z "$binsum" ] && printf "WARNING: %s: no checksum\n" "$_dest" 1>&2
err "Can't safely extract '$_dest', for board '$board'" "fetch" "$@" err "Can't safely extract '$_dest', for board '$board'" "fetch" "$@"
} }
mkdst() mkdst()
{ {
if bad_checksum "$1" "$2" 2>/dev/null; then if ! bad_checksum "$1" "$2" 2>/dev/null; then
x_ rm -f "$2"
else
x_ mv "$2" "$_dl_bin" x_ mv "$2" "$_dl_bin"
x_ cp "$_dl_bin" "$_dest" x_ cp "$_dl_bin" "$_dest"
exit 1 exit 1
fi fi
x_ rm -f "$2"
} }
extract_intel_me() extract_intel_me()
{ {
if e "$mecleaner" f missing; then
err "$cbdir: me_cleaner missing" "extract_intel_me" "$@"
fi
mfs="" mfs=""
_7ztest="$xbtmp/metmp/a" _7ztest="$xbtmp/metmp/a"
_metmp="$xbtmp/me.bin" _metmp="$xbtmp/me.bin"
@@ -328,31 +181,20 @@ extract_intel_me()
x_ rm -Rf "$_7ztest" x_ rm -Rf "$_7ztest"
# maintain compatibility with older configs # maintain compatibility with older configs
# because in the past, shrink was assumed: # because in the past, shrink was assumed
[ -z "$MEshrink" ] && \
if [ -z "$MEshrink" ]; then
MEshrink="y" MEshrink="y"
fi [ "$MEshrink" != "y" ] && [ "$MEshrink" != "n" ] && \
if [ "$MEshrink" != "y" ] && \
[ "$MEshrink" != "n" ]; then
err "MEshrink set badly on '$board' vendor config" err "MEshrink set badly on '$board' vendor config"
fi
if [ "$ME11bootguard" = "y" ]; then if [ "$ME11bootguard" = "y" ]; then
if [ -z "$ME11delta" ] || [ -z "$ME11version" ] || \
if [ -z "$ME11delta" ] || \ [ -z "$ME11sku" ] || [ -z "$ME11pch" ]; then
[ -z "$ME11version" ] || \
[ -z "$ME11sku" ] || \
[ -z "$ME11pch" ]; then
err "$board: ME11delta/ME11version/ME11sku/ME11pch" \ err "$board: ME11delta/ME11version/ME11sku/ME11pch" \
"extract_intel_me" "$@" "extract_intel_me" "$@"
fi fi
x_ ./mk -f deguard x_ "$mk" -f deguard
fi fi
set +u +e set +u +e
@@ -362,11 +204,8 @@ extract_intel_me()
set -u -e set -u -e
if [ "$ME11bootguard" != "y" ]; then if [ "$ME11bootguard" != "y" ]; then
x_ mv "$_metmp" "$_pre_dest" x_ mv "$_metmp" "$_pre_dest"
else else
( apply_deguard_hack ) || \ ( apply_deguard_hack ) || \
err "deguard error on '$_dest'" "extract_intel_me" "$@"; : err "deguard error on '$_dest'" "extract_intel_me" "$@"; :
fi fi
@@ -376,101 +215,47 @@ extract_intel_me()
# must be called inside a subshell. # must be called inside a subshell.
find_me() find_me()
{ {
if [ -f "$_metmp" ]; then [ -f "$_metmp" ] && exit 1 # me.bin found
[ -L "$1" ] && return 0 # symlinks disabled for security reasons
# we found me.bin, so we stop searching
exit 1
elif [ -L "$1" ]; then
return 0
fi
_7ztest="${_7ztest}a" _7ztest="${_7ztest}a"
_keep="" # -k: keep fptr modules even if they can be removed
_pass="" # -p: skip fptr check
_r="-r" # re-locate modules _r="-r" # re-locate modules
_trunc="-t" # -t: truncate the ME size _trunc="-t" # -t: truncate the ME size
eval "`newvar _keep _pass`" # -k (keep fptr modules), -p (skip checks)
if [ "$ME11bootguard" = "y" ]; then [ "$ME11bootguard" = "y" ] && \
mfs="--whitelist MFS" mfs="--whitelist MFS"
fi
if [ "$MEclean" = "n" ]; then if [ "$MEclean" = "n" ]; then
MEshrink="n" MEshrink="n"
_keep="-k" # keep ME modules, don't delete anything _keep="-k" # keep ME modules, don't delete anything
mfs="" # no MFS whitelist needed, due to -r: mfs="" # no MFS whitelist needed, due to -r:
fi fi
if [ "$MEclean" = "n" ] || [ "$MEshrink" != "y" ]; then
if [ "$MEclean" = "n" ] || \ eval "`newvar _r _trunc`"
[ "$MEshrink" != "y" ]; then
# MEclean can still be y, this just means don't shrink,
# so deleted modules would become padded space. this
# could also be used alongside --whitelist, if
# MEclean is otherwise enabled.
_r="" # don't re-locate ME modules
_trunc="" # don't shrink the me.bin file size
fi fi
[ "$MEcheck" = "n" ] && \
if [ "$MEcheck" = "n" ]; then
_pass="-p" # skip fptr check _pass="-p" # skip fptr check
fi [ -n "$mfs" ] && \
if [ -n "$mfs" ]; then
_r="" # cannot re-locate modules if using --whitelist MFS _r="" # cannot re-locate modules if using --whitelist MFS
fi
if "$mecleaner" $mfs $_r $_keep $_pass $_trunc -O "$xbtmp/a" \ if "$mecleaner" $mfs $_r $_keep $_pass $_trunc -O "$xbtmp/a" \
-M "$_metmp" "$1" \ -M "$_metmp" "$1" || [ -f "$_metmp" ]; then
|| \ : # me.bin extracted from a full image with ifd, then shrunk
elif "$mecleaner" $mfs $_r $_pass $_keep $_trunc -O "$_metmp" "$1" || \
[ -f "$_metmp" ]; then [ -f "$_metmp" ]; then
: # me.bin image already present, and we shrunk it
# me.bin extracted from a full image with ifd, then shrunk
:
elif "$mecleaner" $mfs $_r $_pass $_keep $_trunc -O "$_metmp" "$1" \
|| \
[ -f "$_metmp" ]; then
# me.bin image already present, and we shrunk it
:
elif "$me7updateparser" $_keep -O "$_metmp" "$1"; then elif "$me7updateparser" $_keep -O "$_metmp" "$1"; then
: # thinkpad sandybridge me.bin image e.g. x220/t420
# thinkpad sandybridge me.bin image e.g. x220/t420
:
elif extract_archive "$1" "$_7ztest"; then elif extract_archive "$1" "$_7ztest"; then
: # scan newly extracted archive within extracted archive
# scan newly extracted archive within extracted archive
:
else else
return 0 # can't extract, so try the next file
# could not extract anything, so we'll try the next file
return 0
fi fi
if [ -f "$_metmp" ]; then [ -f "$_metmp" ] && exit 1 # me.bin found
# we found me.bin, so we stop searching ( fx_ find_me x_ find "$_7ztest" -type f ) || exit 1; : # 1==me found
exit 1
else
# if the subshell does exit 1, we found me.bin, so exit 1
( fx_ find_me x_ find "$_7ztest" -type f ) || exit 1; :
fi
} }
apply_deguard_hack() apply_deguard_hack()
@@ -484,35 +269,15 @@ apply_deguard_hack()
extract_archive() extract_archive()
{ {
if innoextract "$1" -d "$2"; then innoextract "$1" -d "$2" || \
python "$pfs_extract" "$1" -e || \
: 7z x "$1" -o"$2" || \
"$bsdtar" -C "$2" -xf "$1" || \
elif python "$pfs_extract" "$1" -e; then "$bsdunzip" "$1" -d "$2" || \
:
elif 7z x "$1" -o"$2"; then
:
elif "$bsdtar" -C "$2" -xf "$1"; then
:
elif "$bsdunzip" "$1" -d "$2"; then
:
else
return 1 return 1
fi
if [ -d "${_dl}_extracted" ]; then [ -d "${_dl}_extracted" ] && \
x_ cp -R "${_dl}_extracted" "$2"; :
x_ cp -R "${_dl}_extracted" "$2"
fi
} }
extract_kbc1126ec() extract_kbc1126ec()
@@ -531,45 +296,23 @@ extract_kbc1126ec_dump()
{ {
x_ cd "$appdir/" x_ cd "$appdir/"
if mv Rompaq/68*.BIN ec.bin; then mv Rompaq/68*.BIN ec.bin || \
unar -D ROM.CAB Rom.bin || \
: unar -D Rom.CAB Rom.bin || \
unar -D 68*.CAB Rom.bin || \
elif unar -D ROM.CAB Rom.bin; then
:
elif unar -D Rom.CAB Rom.bin; then
:
elif unar -D 68*.CAB Rom.bin; then
:
else
err "!kbc1126 unar" "extract_kbc1126ec" "$@" err "!kbc1126 unar" "extract_kbc1126ec" "$@"
fi
if [ ! -f "ec.bin" ]; then [ -f "ec.bin" ] || x_ mv Rom.bin ec.bin
x_ mv Rom.bin ec.bin x_ e ec.bin f
fi x_ "$kbc1126_ec_dump" ec.bin
if x_ e ec.bin f; then
x_ "$kbc1126_ec_dump" ec.bin
fi
} }
extract_e6400vga() extract_e6400vga()
{ {
set +u +e set +u +e
if [ -z "$E6400_VGA_offset" ] || \ if [ -z "$E6400_VGA_offset" ] || [ -z "$E6400_VGA_romname" ]; then
[ -z "$E6400_VGA_romname" ]; then
err "$board: E6400_VGA_romname/E6400_VGA_offset unset" \ err "$board: E6400_VGA_romname/E6400_VGA_offset unset" \
"extract_e6400vga" "$@" "extract_e6400vga" "$@"
fi fi
@@ -577,15 +320,14 @@ extract_e6400vga()
tail -c +$E6400_VGA_offset "$_dl" | gunzip > "$appdir/bios.bin" || : tail -c +$E6400_VGA_offset "$_dl" | gunzip > "$appdir/bios.bin" || :
( (
x_ cd "$appdir" x_ cd "$appdir"
x_ e "bios.bin" f x_ e "bios.bin" f
"$e6400_unpack" bios.bin || printf "TODO: fix dell extract util\n" "$e6400_unpack" bios.bin || printf "TODO: fix dell extract util\n"
) || err "can't extract e6400 vga rom" "extract_e6400vga" "$@" ) || err "can't extract e6400 vga rom" "extract_e6400vga" "$@"
x_ cp "$appdir/$E6400_VGA_romname" "$_pre_dest" x_ cp "$appdir/$E6400_VGA_romname" "$_pre_dest"
set -u -e
} }
extract_sch5545ec() extract_sch5545ec()
@@ -599,7 +341,6 @@ extract_sch5545ec()
_sch5545ec_fw="$_sch5545ec_fw/0 Raw section/body.bin" # <-- this! _sch5545ec_fw="$_sch5545ec_fw/0 Raw section/body.bin" # <-- this!
x_ "$uefiextract" "$_bios" x_ "$uefiextract" "$_bios"
x_ cp "$_sch5545ec_fw" "$_pre_dest" x_ cp "$_sch5545ec_fw" "$_pre_dest"
} }
@@ -607,19 +348,14 @@ extract_sch5545ec()
# https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t480-type-20l5-20l6/20l5/solutions/ht508988 # https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t480-type-20l5-20l6/20l5/solutions/ht508988
extract_tbfw() extract_tbfw()
{ {
if [ -z "$TBFW_size" ]; then [ -z "$TBFW_size" ] && err "$board: TBFW_size unset" extract_tbfw "$@"
err "$board: TBFW_size unset" "extract_tbfw" "$@"
fi
fx_ copytb x_ find "$appdir" -type f -name "TBT.bin" fx_ copytb x_ find "$appdir" -type f -name "TBT.bin"
} }
copytb() copytb()
{ {
if [ -f "$1" ] && \ if [ -f "$1" ] && [ ! -L "$1" ]; then
[ ! -L "$1" ]; then
x_ dd if=/dev/null of="$1" bs=1 seek=$TBFW_size x_ dd if=/dev/null of="$1" bs=1 seek=$TBFW_size
x_ mv "$1" "$_pre_dest" x_ mv "$1" "$_pre_dest"
@@ -635,31 +371,23 @@ extract_fsp()
setvfile() setvfile()
{ {
[ -n "$vcfg" ] && for c in $checkvarschk; do [ -n "$vcfg" ] && for c in $checkvarschk
do
do_getvfile="n" do_getvfile="n"
vcmd="[ \"\${$c}\" != \"/dev/null\" ] && [ -n \"\${$c}\" ]" vcmd="[ \"\${$c}\" != \"/dev/null\" ] && [ -n \"\${$c}\" ]"
eval "$vcmd && do_getvfile=\"y\"" eval "$vcmd && do_getvfile=\"y\""
if [ "$do_getvfile" = "y" ]; then [ "$do_getvfile" = "y" ] && \
getvfile "$@" && \
if getvfile "$@"; then return 0; :
return 0
fi
fi
done && return 1; : done && return 1; :
} }
getvfile() getvfile()
{ {
if e "config/vendor/$vcfg/pkg.cfg" f missing; then e "config/vendor/$vcfg/pkg.cfg" f missing && \
return 1 return 1
fi
. "config/vendor/$vcfg/pkg.cfg" || \ . "config/vendor/$vcfg/pkg.cfg" || \
err "Can't read 'config/vendor/$vcfg/pkg.cfg'" "getvfile" "$@" err "Can't read 'config/vendor/$vcfg/pkg.cfg'" "getvfile" "$@"
@@ -667,16 +395,10 @@ getvfile()
bootstrap bootstrap
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
getfiles # ./mk download
# download vendor files else # ./mk inject
fx_ prep x_ find "$tmpromdir" -mindepth 1 -maxdepth 1 \
getfiles -type f -name "*.rom"
else
# inject vendor files
fx_ prep x_ find "$tmpromdir" -maxdepth 1 -type f -name "*.rom"
( check_vendor_hashes ) || \ ( check_vendor_hashes ) || \
err "$archive: Can't verify hashes" "getvfile" "$@"; : err "$archive: Can't verify hashes" "getvfile" "$@"; :
fi fi
@@ -691,29 +413,20 @@ bootstrap()
rmodtool="elf/coreboot/$tree/rmodtool" rmodtool="elf/coreboot/$tree/rmodtool"
mecleaner="$xbmkpwd/$cbdir/util/me_cleaner/me_cleaner.py" mecleaner="$xbmkpwd/$cbdir/util/me_cleaner/me_cleaner.py"
[ "$XBMKmecleaner" = "y" ] && \
if [ "$XBMKmecleaner" = "y" ]; then
mecleaner="$xbmkpwd/src/me_cleaner/me_cleaner.py" mecleaner="$xbmkpwd/src/me_cleaner/me_cleaner.py"
fi
x_ ./mk -f coreboot "${cbdir##*/}" x_ "$mk" -f coreboot "${cbdir##*/}"
x_ ./mk -f me_cleaner x_ "$mk" -f me_cleaner
x_ ./mk -b bios_extract forx 'x_ \"$mk\" -b %s' bios_extract biosutilities uefitool libarchive
x_ ./mk -b biosutilities
x_ ./mk -b uefitool
x_ ./mk -b libarchive # for bsdtar and bsdunzip
if [ -d "${kbc1126_ec_dump%/*}" ]; then
[ -d "${kbc1126_ec_dump%/*}" ] && \
x_ make -C "$cbdir/util/kbc1126" x_ make -C "$cbdir/util/kbc1126"
fi
if [ -n "$MRC_refcode_cbtree" ]; then if [ -n "$MRC_refcode_cbtree" ]; then
cbfstoolref="elf/coreboot/$MRC_refcode_cbtree/cbfstool" cbfstoolref="elf/coreboot/$MRC_refcode_cbtree/cbfstool"
x_ ./mk -d coreboot "$MRC_refcode_cbtree"; : x_ "$mk" -d coreboot "$MRC_refcode_cbtree"; :
fi fi
} }
@@ -723,24 +436,18 @@ prep()
_xromname="${1##*/}" _xromname="${1##*/}"
_xromnew="${_xrom%/*}/${_xromname#"$vfix"}" _xromnew="${_xrom%/*}/${_xromname#"$vfix"}"
if [ "$nuke" = "nuke" ]; then [ "$nuke" = "nuke" ] && \
_xromnew="${_xrom%/*}/$vfix${_xrom##*/}" _xromnew="${_xrom%/*}/$vfix${_xrom##*/}"
fi
if e "$_xrom" f missing; then
e "$_xrom" f missing && \
return 0 return 0
fi
if [ -z "${_xromname#"$vfix"}" ]; then
[ -z "${_xromname#"$vfix"}" ] && \
err "$_xromname / $vfix: name match" "prep" "$@" err "$_xromname / $vfix: name match" "prep" "$@"
fi
# Remove the prefix and 1-byte pad # Remove the prefix and 1-byte pad
if [ "${_xromname#"$vfix"}" != "$_xromname" ] && \ if [ "${_xromname#"$vfix"}" != "$_xromname" ] \
[ "$nuke" != "nuke" ]; then && [ "$nuke" != "nuke" ]; then
unpad_one_byte "$_xrom" unpad_one_byte "$_xrom"
x_ mv "$_xrom" "$_xromnew" x_ mv "$_xrom" "$_xromnew"
@@ -749,34 +456,23 @@ prep()
fi fi
if [ "$nuke" = "nuke" ]; then if [ "$nuke" = "nuke" ]; then
( mksha512 "$_xrom" "vendorhashes" ) || err; : ( mksha512 "$_xrom" "vendorhashes" ) || err; :
fi fi
if ! add_vfiles "$_xrom"; then add_vfiles "$_xrom" || return 1 # no need to insert files
# no need to insert files. we will later
# still process MAC addresses as required
return 1
fi
if [ "$nuke" = "nuke" ]; then if [ "$nuke" = "nuke" ]; then
pad_one_byte "$_xrom" pad_one_byte "$_xrom"
x_ mv "$_xrom" "$_xromnew" x_ mv "$_xrom" "$_xromnew"
fi fi
} }
mksha512() mksha512()
{ {
build_sbase eval "$build_sbase"
if [ "${1%/*}" != "$1" ]; then
[ "${1%/*}" != "$1" ] && \
x_ cd "${1%/*}" x_ cd "${1%/*}"
fi
x_ "$sha512sum" ./"${1##*/}" >> "$2" || \ x_ "$sha512sum" ./"${1##*/}" >> "$2" || \
err "!sha512sum \"$1\" > \"$2\"" "mksha512" "$@" err "!sha512sum \"$1\" > \"$2\"" "mksha512" "$@"
@@ -787,70 +483,37 @@ add_vfiles()
rom="$1" rom="$1"
if [ "$has_hashes" != "y" ] && [ "$nuke" != "nuke" ]; then if [ "$has_hashes" != "y" ] && [ "$nuke" != "nuke" ]; then
printf "'%s' has no hash file. Skipping.\n" "$archive" 1>&2 printf "'%s' has no hash file. Skipping.\n" "$archive" 1>&2
return 1 return 1
elif [ "$has_hashes" = "y" ] && [ "$nuke" = "nuke" ]; then elif [ "$has_hashes" = "y" ] && [ "$nuke" = "nuke" ]; then
printf "'%s' has a hash file. Skipping nuke.\n" "$archive" 1>&2 printf "'%s' has a hash file. Skipping nuke.\n" "$archive" 1>&2
return 1 return 1
fi fi
if [ -n "$CONFIG_HAVE_REFCODE_BLOB" ]; then [ -n "$CONFIG_HAVE_REFCODE_BLOB" ] && \
vfile "fallback/refcode" "$CONFIG_REFCODE_BLOB_FILE" "stage" vfile "fallback/refcode" "$CONFIG_REFCODE_BLOB_FILE" "stage"
fi [ "$CONFIG_HAVE_MRC" = "y" ] && \
if [ "$CONFIG_HAVE_MRC" = "y" ]; then
vfile "mrc.bin" "$CONFIG_MRC_FILE" "mrc" "0xfffa0000" vfile "mrc.bin" "$CONFIG_MRC_FILE" "mrc" "0xfffa0000"
fi [ "$CONFIG_HAVE_ME_BIN" = "y" ] && \
if [ "$CONFIG_HAVE_ME_BIN" = "y" ]; then
vfile IFD "$CONFIG_ME_BIN_PATH" me vfile IFD "$CONFIG_ME_BIN_PATH" me
fi [ -n "$CONFIG_KBC1126_FW1" ] && \
if [ -n "$CONFIG_KBC1126_FW1" ]; then
vfile ecfw1.bin "$CONFIG_KBC1126_FW1" raw \ vfile ecfw1.bin "$CONFIG_KBC1126_FW1" raw \
"$CONFIG_KBC1126_FW1_OFFSET" "$CONFIG_KBC1126_FW1_OFFSET"
fi [ -n "$CONFIG_KBC1126_FW2" ] && \
if [ -n "$CONFIG_KBC1126_FW2" ]; then
vfile ecfw2.bin "$CONFIG_KBC1126_FW2" raw \ vfile ecfw2.bin "$CONFIG_KBC1126_FW2" raw \
"$CONFIG_KBC1126_FW2_OFFSET" "$CONFIG_KBC1126_FW2_OFFSET"
fi [ -n "$CONFIG_VGA_BIOS_FILE" ] && [ -n "$CONFIG_VGA_BIOS_ID" ] && \
if [ -n "$CONFIG_VGA_BIOS_FILE" ] && [ -n "$CONFIG_VGA_BIOS_ID" ]; then
vfile "pci$CONFIG_VGA_BIOS_ID.rom" "$CONFIG_VGA_BIOS_FILE" \ vfile "pci$CONFIG_VGA_BIOS_ID.rom" "$CONFIG_VGA_BIOS_FILE" \
optionrom optionrom
fi [ "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" = "y" ] && \
[ -n "$CONFIG_SMSC_SCH5545_EC_FW_FILE" ] && \
if [ "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" = "y" ] && \
[ -n "$CONFIG_SMSC_SCH5545_EC_FW_FILE" ]; then
vfile sch5545_ecfw.bin "$CONFIG_SMSC_SCH5545_EC_FW_FILE" raw vfile sch5545_ecfw.bin "$CONFIG_SMSC_SCH5545_EC_FW_FILE" raw
fi [ -z "$CONFIG_FSP_USE_REPO" ] && [ -z "$CONFIG_FSP_FULL_FD" ] && \
[ -n "$CONFIG_FSP_M_FILE" ] && \
if [ -z "$CONFIG_FSP_USE_REPO" ] && \
[ -z "$CONFIG_FSP_FULL_FD" ] && \
[ -n "$CONFIG_FSP_M_FILE" ]; then
vfile "$CONFIG_FSP_M_CBFS" "$CONFIG_FSP_M_FILE" fsp --xip vfile "$CONFIG_FSP_M_CBFS" "$CONFIG_FSP_M_FILE" fsp --xip
fi [ -z "$CONFIG_FSP_USE_REPO" ] && [ -z "$CONFIG_FSP_FULL_FD" ] && \
[ -n "$CONFIG_FSP_S_FILE" ] && \
if [ -z "$CONFIG_FSP_USE_REPO" ] && \
[ -z "$CONFIG_FSP_FULL_FD" ] && \
[ -n "$CONFIG_FSP_S_FILE" ]; then
vfile "$CONFIG_FSP_S_CBFS" "$CONFIG_FSP_S_FILE" fsp vfile "$CONFIG_FSP_S_CBFS" "$CONFIG_FSP_S_FILE" fsp
fi
xchanged="y" xchanged="y"
@@ -859,10 +522,7 @@ add_vfiles()
vfile() vfile()
{ {
if [ "$2" = "/dev/null" ]; then [ "$2" = "/dev/null" ] && return 0
return 0
fi
cbfsname="$1" cbfsname="$1"
_dest="${2##*../}" _dest="${2##*../}"
@@ -870,50 +530,33 @@ vfile()
_offset="" _offset=""
if [ "$blobtype" = "fsp" ] && \ if [ "$blobtype" = "fsp" ] && [ $# -gt 3 ]; then
[ $# -gt 3 ]; then
_offset="$4" _offset="$4"
elif [ $# -gt 3 ] && _offset="-b $4" && [ -z "$4" ]; then
elif [ $# -gt 3 ] && \
_offset="-b $4" && [ -z "$4" ]; then
err "$rom: offset given but empty (undefined)" "vfile" "$@" err "$rom: offset given but empty (undefined)" "vfile" "$@"
fi fi
if [ "$nuke" != "nuke" ]; then [ "$nuke" != "nuke" ] && \
x_ e "$_dest" f x_ e "$_dest" f
fi
if [ "$cbfsname" = "IFD" ]; then if [ "$cbfsname" = "IFD" ]; then
if [ "$nuke" = "nuke" ]; then if [ "$nuke" = "nuke" ]; then
x_ "$ifdtool" $ifdprefix --nuke $blobtype "$rom" \ x_ "$ifdtool" $ifdprefix --nuke $blobtype "$rom" \
-O "$rom" -O "$rom"
else else
x_ "$ifdtool" $ifdprefix -i $blobtype:$_dest "$rom" \ x_ "$ifdtool" $ifdprefix -i $blobtype:$_dest "$rom" \
-O "$rom" -O "$rom"
fi fi
elif [ "$nuke" = "nuke" ]; then elif [ "$nuke" = "nuke" ]; then
x_ "$cbfstool" "$rom" remove -n "$cbfsname" x_ "$cbfstool" "$rom" remove -n "$cbfsname"
elif [ "$blobtype" = "stage" ]; then elif [ "$blobtype" = "stage" ]; then
# the only stage we handle is refcode # the only stage we handle is refcode
x_ rm -f "$xbtmp/refcode" x_ rm -f "$xbtmp/refcode"
x_ "$rmodtool" -i "$_dest" -o "$xbtmp/refcode" x_ "$rmodtool" -i "$_dest" -o "$xbtmp/refcode"
x_ "$cbfstool" "$rom" add-stage -f "$xbtmp/refcode" \ x_ "$cbfstool" "$rom" add-stage -f "$xbtmp/refcode" \
-n "$cbfsname" -t stage -n "$cbfsname" -t stage
else else
x_ "$cbfstool" "$rom" add -f "$_dest" -n "$cbfsname" \ x_ "$cbfstool" "$rom" add -f "$_dest" -n "$cbfsname" \
-t $blobtype $_offset -t $blobtype $_offset
fi fi
@@ -924,13 +567,11 @@ vfile()
# must be called from a subshell # must be called from a subshell
check_vendor_hashes() check_vendor_hashes()
{ {
build_sbase eval "$build_sbase"
x_ cd "$tmpromdir" x_ cd "$tmpromdir"
if [ "$has_hashes" != "n" ] && \ if [ "$has_hashes" != "n" ] && [ "$nuke" != "nuke" ]; then
[ "$nuke" != "nuke" ]; then
( x_ "$sha512sum" -c "$hashfile" ) || \ ( x_ "$sha512sum" -c "$hashfile" ) || \
x_ sha1sum -c "$hashfile" x_ sha1sum -c "$hashfile"
fi fi
+30 -180
View File
@@ -2,16 +2,23 @@
# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com>
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
# Copyright (c) 2020-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2020-2026 Leah Rowe <leah@libreboot.org>
# Copyright (c) 2025 Alper Nebi Yasak <alpernebiyasak@gmail.com> # Copyright (c) 2025 Alper Nebi Yasak <alpernebiyasak@gmail.com>
cbfstool="elf/coreboot/default/cbfstool" cbfstool="elf/coreboot/default/cbfstool"
rmodtool="elf/coreboot/default/rmodtool" rmodtool="elf/coreboot/default/rmodtool"
build_sbase="[ ! -f \"\$sha512sum\" ] && x_ make -C util/sbase"
newvar()
{
printf "%s\n" "$*" | \
awk '{ for (i=1; i<=NF; i++) $i = $i "=;"; print }'; :
}
mkrom_tarball() mkrom_tarball()
{ {
update_xbmkver "$1" update_xbmkver "$1"
mktarball "$1" "${1%/*}/${relname}_${1##*/}.tar.xz" mktarball "$1" "${1%/*}/${relname}_${1##*/}.tar.xz"
x_ rm -Rf "$1" x_ rm -Rf "$1"
@@ -21,6 +28,10 @@ update_xbmkver()
{ {
xbmk_sanitize_version xbmk_sanitize_version
if [ -z "${version-}" ] || [ -z "${versiondate-}" ]; then
err "version and/or versiondate unset" "update_xbmkver" "$@"
fi
printf "%s\n" "$version" > "$1/.version" || \ printf "%s\n" "$version" > "$1/.version" || \
err "can't write '$1'" "update_xbmkver" "$@"; : err "can't write '$1'" "update_xbmkver" "$@"; :
@@ -28,36 +39,26 @@ update_xbmkver()
err "can't write '$versiondate'" "update_xbmkver" "$@"; : err "can't write '$versiondate'" "update_xbmkver" "$@"; :
} }
version()
{
printf "%s\nWebsite: %s\n" "$relname" "$projectsite"
}
xbmk_sanitize_version() xbmk_sanitize_version()
{ {
if [ -z "$version" ]; then [ -n "$version" ] && version="`printf '%s\n' "$version" | sed \
's/[[:space:]]//g; s/\.\.//g; s/\.\///g; s/\//-/g; s/^-//'`" \
return 0 && [ -z "$version" ] && \
fi
version="`printf "%s\n" "$version" | sed -e 's/\t//g'`"
version="`printf "%s\n" "$version" | sed -e 's/\ //g'`"
version="`printf "%s\n" "$version" | sed -e 's/\.\.//g'`"
version="`printf "%s\n" "$version" | sed -e 's/\.\///g'`"
version="`printf "%s\n" "$version" | sed -e 's/\//-/g'`"
version="${version#-}"
if [ -z "$version" ]; then
err "'version' empty after sanitization" \ err "'version' empty after sanitization" \
"xbmk_sanitize_version" "$@" "xbmk_sanitize_version" "$@"; :
fi
} }
mktarball() mktarball()
{ {
printf "Creating tar archive '%s' from directory '%s'\n" "$2" "$1" printf "Creating tar archive '%s' from directory '%s'\n" "$2" "$1"
if [ "${2%/*}" != "$2" ]; then [ "${2%/*}" != "$2" ] && \
x_ mkdir -p "${2%/*}"
x_ xbmkdir "${2%/*}"
fi
x_ tar -c "$1" | xz -T$XBMK_THREADS -9e > "$2" || \ x_ tar -c "$1" | xz -T$XBMK_THREADS -9e > "$2" || \
err "can't make tarball '$1'" "mktarball" "$@" err "can't make tarball '$1'" "mktarball" "$@"
@@ -66,78 +67,27 @@ mktarball()
e() e()
{ {
es_t="e" es_t="e"
[ $# -gt 1 ] && \
if [ $# -gt 1 ]; then
es_t="$2" es_t="$2"
fi
es2="already exists" es2="already exists"
estr="[ -$es_t \"\$1\" ] || return 1" estr="[ -$es_t \"\$1\" ] || return 1"
if [ $# -gt 2 ]; then if [ $# -gt 2 ]; then
estr="[ -$es_t \"\$1\" ] && return 1" estr="[ -$es_t \"\$1\" ] && return 1"
es2="missing" es2="missing"
fi fi
eval "$estr" eval "$estr"
printf "%s %s\n" "$1" "$es2" 1>&2 printf "%s %s\n" "$1" "$es2" 1>&2
} }
setvars()
{
_setvars=""
if [ $# -lt 2 ]; then
return 0
fi
val="$1"
shift 1
while [ $# -gt 0 ]; do
printf "%s=\"%s\"\n" "$1" "$val"
shift 1
done
}
# return 0 if project is single-tree, otherwise 1
# e.g. coreboot is multi-tree, so 1
singletree() singletree()
{ {
( fx_ "eval exit 1 && err" find "config/$1/"*/ -type f \ ( fx_ "eval exit 1 && err" find "config/$1/"*/ -type f \
-name "target.cfg" ) || return 1; : -name "target.cfg" ) || return 1; :
} }
findpath()
{
if [ $# -lt 1 ]; then
err "findpath: No arguments provided" "findpath" "$@"
fi
while [ $# -gt 0 ]; do
found="`readlink -f "$1" 2>/dev/null`" || return 1; :
if [ -z "$found" ]; then
found="`realpath "$1" 2>/dev/null`" || \
return 1
fi
printf "%s\n" "$found"
shift 1
done
}
pad_one_byte() pad_one_byte()
{ {
paddedfile="`mktemp || err "mktemp pad_one_byte"`" || \ paddedfile="`mktemp || err "mktemp pad_one_byte"`" || \
@@ -154,58 +104,31 @@ unpad_one_byte()
xromsize="$(expr $(stat -c '%s' "$1") - 1)" || \ xromsize="$(expr $(stat -c '%s' "$1") - 1)" || \
err "can't increment file size" "unpad_one_byte" "$@" err "can't increment file size" "unpad_one_byte" "$@"
if [ $xromsize -lt 524288 ]; then [ $xromsize -lt 524288 ] && \
err "too small, $xromsize: $1" "unpad_one_byte" "$@" err "too small, $xromsize: $1" "unpad_one_byte" "$@"
fi
unpaddedfile="`mktemp || err "mktemp unpad_one_byte"`" || \ unpaddedfile="`mktemp || err "mktemp unpad_one_byte"`" || \
err "can't make tmp file" "unpad_one_byte" "$@" err "can't make tmp file" "unpad_one_byte" "$@"
x_ dd if="$1" of="$unpaddedfile" bs=$xromsize count=1 x_ dd if="$1" of="$unpaddedfile" bs=$xromsize count=1
x_ mv "$unpaddedfile" "$1" x_ mv "$unpaddedfile" "$1"
} }
build_sbase()
{
if [ ! -f "$sha512sum" ]; then
x_ make -C "$xbmkpwd/util/sbase"
fi
}
remkdir() remkdir()
{ {
x_ rm -Rf "$@" x_ rm -Rf "$@"
x_ mkdir -p "$@"
x_ xbmkdir "$@"
}
xbmkdir()
{
while [ $# -gt 0 ]; do
if [ ! -d "$1" ]; then
x_ mkdir -p "$1"
fi
shift 1
done
} }
fx_() fx_()
{ {
xchk fx_ "$@" xchk fx_ "$@"
xcmd="$1" xcmd="$1"
xfile="`mktemp || err "can't create tmpfile"`" || \ xfile="`mktemp || err "can't create tmpfile"`" || \
err "can't make tmpfile" "fx_" "$@" err "can't make tmpfile" "fx_" "$@"
x_ rm -f "$xfile" x_ rm -f "$xfile"
x_ touch "$xfile" x_ touch "$xfile"
shift 1 shift 1
@@ -214,7 +137,6 @@ fx_()
err "can't sort to '$xfile'" "fx_" "$xcmd" "$@" err "can't sort to '$xfile'" "fx_" "$xcmd" "$@"
dx_ "$xcmd" "$xfile" || : dx_ "$xcmd" "$xfile" || :
x_ rm -f "$xfile" x_ rm -f "$xfile"
} }
@@ -222,90 +144,18 @@ dx_()
{ {
xchk dx_ "$@" xchk dx_ "$@"
if [ ! -f "$2" ]; then [ ! -f "$2" ] && return 0
return 0
fi
while read -r fx; do while read -r fx; do
$1 "$fx" || return 1; : $1 "$fx" || return 1; :
done < "$2" || err "cannot read '$2'" "dx_" "$@"; :
done < "$2" \
|| err "cannot read '$2'" "dx_" "$@"; :
}
x_()
{
if [ $# -lt 1 ]; then
return 0
elif [ -z "$1" ]; then
err "Empty first arg" "x_" "$@"
else
"$@" || err "Unhandled error" "x_" "$@"
fi
} }
xchk() xchk()
{ {
if [ $# -lt 3 ]; then if [ $# -lt 3 ]; then
err "$1 needs at least two arguments" "xchk" "$@" err "$1 needs at least two arguments" "xchk" "$@"
elif [ -z "$2" ] || [ -z "$3" ]; then
elif [ -z "$2" ] || \
[ -z "$3" ]; then
err "arguments must not be empty" "xchk" "$@" err "arguments must not be empty" "xchk" "$@"
fi fi
} }
err()
{
if [ $# -eq 1 ]; then
printf "ERROR %s: %s\n" "$0" "$1" 1>&2 || :
elif [ $# -gt 1 ]; then
printf "ERROR %s: %s: in command with args: " "$0" "$1" 1>&2
shift 1
xprintf "$@" 1>&2
else
printf "ERROR, but no arguments provided to err\n" 1>&2
fi
exit 1
}
xprintf()
{
xprintfargs=0
while [ $# -gt 0 ]; do
printf "\"%s\"" "$1"
if [ $# -gt 1 ]; then
printf " "
fi
xprintfargs=1
shift 1
done
if [ $xprintfargs -gt 0 ]; then
printf "\n"
fi
}
+17 -71
View File
@@ -1,71 +1,32 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2023-2026 Leah Rowe <leah@libreboot.org>
reldest="" eval "`newvar reldest reldir rsrc vdir`"
reldir=""
relmode=""
rsrc=""
vdir=""
release() release()
{ {
export XBMK_RELEASE="y" export XBMK_RELEASE="y"
reldir="release" reldir="release"
while getopts m: option; do
if [ -z "$OPTARG" ]; then
err "empty argument not allowed" "release" "$@"
fi
case "$option" in
m)
relmode="$OPTARG"
;;
*)
err "invalid option '-$option'" "release" "$@"
;;
esac
done
reldest="$reldir/$version" reldest="$reldir/$version"
[ -e "$reldest" ] && \
if [ -e "$reldest" ]; then
err "already exists: \"$reldest\"" "release" "$@" err "already exists: \"$reldest\"" "release" "$@"
fi
vdir="`mktemp -d || err "can't make vdir"`" || \ vdir="`mktemp -d || err "can't make vdir"`" || \
err "can't make tmp vdir" "release" "$@" err "can't make tmp vdir" "release" "$@"
vdir="$vdir/$version" vdir="$vdir/$version"
rsrc="$vdir/${relname}_src" rsrc="$vdir/${relname}_src"
remkdir "$vdir" remkdir "$vdir"
x_ git clone . "$rsrc" x_ git clone . "$rsrc"
update_xbmkver "$rsrc" update_xbmkver "$rsrc"
prep_release src forx 'prep_release %s' src tarball bin
prep_release tarball
if [ "$relmode" != "src" ]; then
prep_release bin
fi
x_ rm -Rf "$rsrc" x_ rm -Rf "$rsrc"
x_ xbmkdir "$reldir" x_ mkdir -p "$reldir"
x_ mv "$vdir" "$reldir" x_ mv "$vdir" "$reldir"
x_ rm -Rf "${vdir%"/$version"}" x_ rm -Rf "${vdir%"/$version"}"
@@ -75,17 +36,13 @@ release()
prep_release() prep_release()
{ {
( (
if [ "$1" != "tarball" ]; then if [ "$1" != "tarball" ]; then
x_ cd "$rsrc"
[ ! -e "cache" ] && \
x_ ln -s "$XBMK_CACHE" "cache"; :
fi
x_ cd "$rsrc" prep_release_$1
if [ ! -e "cache" ]; then
x_ ln -s "$XBMK_CACHE" "cache"
fi
fi
prep_release_$1
) || err "can't prep release $1" "prep_release" "$@" ) || err "can't prep release $1" "prep_release" "$@"
} }
@@ -96,23 +53,18 @@ prep_release_src()
x_ ./mk -f x_ ./mk -f
fx_ "x_ rm -Rf" x_ find . -name ".git" forx 'fx_ \"x_ rm -Rf\" x_ find . -name \".%s\"' git gitmodules
fx_ "x_ rm -Rf" x_ find . -name ".gitmodules"
# delete unwanted files from the release
( fx_ nuke x_ find config -type f -name "nuke.list" ) || \ ( fx_ nuke x_ find config -type f -name "nuke.list" ) || \
err "can't prune project files" "prep_release_src" "$@"; : err "can't prune project files" "prep_release_src" "$@"; :
} }
# delete unwanted files from the release
nuke() nuke()
{ {
r="$rsrc/src/${1#config/}" r="$rsrc/src/${1#config/}"
if [ -d "${r%/*}" ]; then if [ -d "${r%/*}" ]; then
x_ cd "${r%/*}" x_ cd "${r%/*}"
dx_ "x_ rm -Rf" "$rsrc/$1" dx_ "x_ rm -Rf" "$rsrc/$1"
fi fi
} }
@@ -124,14 +76,12 @@ prep_release_tarball()
err "can't create '$rsrc/CHANGELOG'" "prep_release_tarball" "$@" err "can't create '$rsrc/CHANGELOG'" "prep_release_tarball" "$@"
x_ rm -f "$rsrc/lock" "$rsrc/cache" x_ rm -f "$rsrc/lock" "$rsrc/cache"
x_ rm -Rf "$rsrc/xbmkwd" "$rsrc/util/sbase" x_ rm -Rf "$rsrc/xbmkwd" "$rsrc/util/sbase"
x_ mv "$rsrc/util/sbase2" "$rsrc/util/sbase" x_ mv "$rsrc/util/sbase2" "$rsrc/util/sbase"
( (
x_ cd "${rsrc%/*}" x_ cd "${rsrc%/*}"
x_ mktarball "${rsrc##*/}" "${rsrc##*/}.tar.xz" x_ mktarball "${rsrc##*/}" "${rsrc##*/}.tar.xz"
) || err "can't create src tarball" "prep_release_tarball" "$@"; : ) || err "can't create src tarball" "prep_release_tarball" "$@"; :
} }
@@ -139,15 +89,11 @@ prep_release_tarball()
prep_release_bin() prep_release_bin()
{ {
x_ ./mk -d coreboot x_ ./mk -d coreboot
x_ ./mk -b coreboot
x_ ./mk -b pico-serprog forx 'x_ ./mk -b' coreboot pico-serprog stm32-vserprog pcsx-redux
x_ ./mk -b stm32-vserprog fx_ mkrom_tarball x_ find bin -mindepth 1 -maxdepth 1 \
-type d -name "serprog_*"
x_ ./mk -b pcsx-redux
fx_ mkrom_tarball x_ find bin -maxdepth 1 -type d -name "serprog_*"
x_ mv bin ../roms x_ mv bin ../roms
} }
-927
View File
@@ -1,927 +0,0 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (c) 2022-2023 Alper Nebi Yasak <alpernebiyasak@gmail.com>
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
# Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org>
# flag e.g. ./mk -b <-- mkflag would be "b"
flag=""
# macros, overridden depending on the flag
if_do_make=""
if_dry_build=":"
if_not_do_make=":"
if_not_dry_build=""
autoconfargs=""
autogenargs=""
badhash=""
badtghash=""
bootstrapargs=""
build_depend=""
buildtype=""
cleanargs=""
cmakedir=""
cmd=""
defconfig=""
dest_dir=""
elfdir=""
forcepull=""
gccdir=""
gccfull=""
gccver=""
gnatdir=""
gnatfull=""
gnatver=""
listfile=""
makeargs=""
mdir=""
mkhelper=""
mkhelpercfg=""
mode=""
postmake=""
premake=""
project=""
release=""
rev=""
srcdir=""
target=""
target_dir=""
targets=""
tree=""
xarch=""
xgcctree=""
xlang=""
trees()
{
flags="f:F:b:m:u:c:x:s:l:n:d:"
while getopts $flags option; do
if [ -n "$flag" ]; then
err "only one flag is permitted" "trees" "$@"
fi
flag="$1"
# the "mode" variable is affixed to a make command, example:
# ./mk -m coreboot does: make menuconfig -C src/coreboot/tree
case "$flag" in
-d)
# -d is similar to -b, except that
# a large number of operations will be
# skipped. these are "if_not_dry_build build" scenarios
# where only a subset of build tasks are done,
# and $if_not_dry_build is prefixed to skipped commands
if_dry_build=""
if_not_dry_build=":"
;;
-b) : ;;
-u) mode="oldconfig" ;;
-m) mode="menuconfig" ;;
-c) mode="distclean" ;;
-x) mode="crossgcc-clean" ;;
-f|-F) # download source code for a project
# macros. colon means false.
if_do_make=":"
if_dry_build=""
if_not_do_make=""
if_not_dry_build=":"
if [ "$flag" = "-F" ]; then
# don't skip git fetch/pull on cached src
forcepull="y"
fi
;;
-s) mode="savedefconfig" ;;
-l) mode="olddefconfig" ;;
-n) mode="nconfig" ;;
*) err "invalid option '-$option'" "trees" "$@" ;;
esac
if [ -z "${OPTARG+x}" ]; then
shift 1
break
fi
project="${OPTARG#src/}"
project="${project#config/git/}"
shift 2
done
if [ -z "$flag" ]; then
err "missing flag ($flags)" "trees" "$@"
elif [ -z "$project" ]; then
fx_ "x_ ./mk $flag" x_ ls -1 config/git
return 1
elif [ ! -f "config/git/$project/pkg.cfg" ]; then
err "config/git/$project/pkg.cfg missing" "trees" "$@"
fi
elfdir="elf/$project"
datadir="config/data/$project"
configdir="config/$project"
srcdir="src/$project"
dest_dir="$elfdir"
listfile="$datadir/build.list"
if [ ! -f "$listfile" ]; then
listfile="" # build.list is optional on all projects
fi
mkhelpercfg="$datadir/mkhelper.cfg"
if e "$mkhelpercfg" f missing; then
mkhelpercfg="$xbtmp/mkhelper.cfg"
x_ touch "$mkhelpercfg"
fi
targets="$*"
cmd="build_targets $targets"
if singletree "$project"; then
cmd="build_project"
fi
remkdir "${tmpgit%/*}"
}
build_project()
{
if ! configure_project "$configdir"; then
return 0
elif [ -f "$listfile" ]; then
if ! $if_not_dry_build elfcheck; then
return 0
fi
fi
if [ "$mode" = "distclean" ]; then
mode="clean"
fi
if ! run_make_command; then
return 0
fi
if [ -z "$mode" ]; then
$if_not_dry_build \
copy_elf; :
fi
}
build_targets()
{
if [ ! -d "$configdir" ]; then
err "directory '$configdir' doesn't exist" "build_targets" "$@"
elif [ $# -lt 1 ]; then
targets="$(ls -1 "$configdir")" || \
err "'$configdir': can't list targets" "build_targets" "$@"
fi
for x in $targets; do
unset CROSS_COMPILE
export PATH="$xbmkpath"
if [ "$x" = "list" ]; then
x_ ls -1 "config/$project"
listfile=""
break
fi
printf "'make %s', '%s', '%s'\n" "$mode" "$project" "$x"
target="$x"
x_ handle_defconfig
if [ -z "$mode" ]; then
x_ $postmake
fi
done; :
}
handle_defconfig()
{
target_dir="$configdir/$target"
if [ ! -f "CHANGELOG" ]; then
fetch_project "$project"
fi
if ! configure_project "$target_dir"; then
return 0
fi
if [ -z "$tree" ]; then
err "$configdir: 'tree' not set" "handle_defconfig" "$@"
fi
srcdir="src/$project/$tree"
if [ "$mode" = "${mode%clean}" ] && \
[ ! -d "$srcdir" ]; then
return 0
fi
for y in "$target_dir/config"/*; do
if [ "$flag" != "-d" ] && \
[ ! -f "$y" ]; then
continue
elif [ "$flag" != "-d" ]; then
defconfig="$y"
fi
if [ -z "$mode" ]; then
check_defconfig || continue; :
fi
if [ -z "$mode" ]; then
for _xarch in $xarch; do
$if_dry_build \
break
if [ -n "$_xarch" ]; then
check_cross_compiler "$_xarch"
fi
done; :
fi
handle_makefile
if [ -z "$mode" ]; then
$if_not_dry_build \
copy_elf
fi
done; :
}
configure_project()
{
tcfg="$1/target.cfg"
autoconfargs=""
badhash=""
badtghash=""
bootstrapargs=""
build_depend=""
buildtype=""
cleanargs=""
makeargs=""
mkhelper=""
postmake=""
premake=""
release=""
xarch=""
xgcctree=""
xlang=""
if [ ! -f "$tcfg" ]; then
buildtype="auto"
fi
# globally initialise all variables for a source tree / target:
if e "$datadir/mkhelper.cfg" f; then
. "$datadir/mkhelper.cfg" || \
err "Can't read '$datadir/mkhelper.cfg'" \
"configure_project" "$@"
fi
# override target/tree specific variables from per-target config:
while e "$tcfg" f || \
[ "$cmd" != "build_project" ]; do
# TODO: implement infinite loop detection here, caused
# by project targets pointing to other targets/trees
# when then ultimate point back repeatedly; this is
# currently avoided simply by careful configuration.
# temporary files per tree/target name could be created
# per iteration, and then checked the next time
printf "Loading %s config: %s\n" "$project" "$tcfg"
rev=""
tree=""
. "$tcfg" || \
err "Can't read '$tcfg'" "configure_project" "$@"
if [ "$flag" = "-d" ]; then
build_depend="" # dry run
fi
if [ "$cmd" = "build_project" ]; then
# single-tree, so it can't be a target pointing
# to a main source tree
break
fi
$if_do_make \
break
if [ "${tcfg%/*/target.cfg}" = "${tcfg%"/$tree/target.cfg"}" ]
then
# we have found the main source tree that
# a given target uses; no need to continue
break
else
tcfg="${tcfg%/*/target.cfg}/$tree/target.cfg"
fi
done
if [ "$XBMK_RELEASE" = "y" ] && \
[ "$release" = "n" ]; then
return 1
fi
if [ -n "$buildtype" ] && \
[ "${mode%config}" != "$mode" ]; then
return 1
fi
if [ -z "$mode" ]; then
$if_not_dry_build \
build_dependencies
fi
mdir="$xbmkpwd/config/submodule/$project"
if [ -n "$tree" ]; then
mdir="$mdir/$tree"
fi
if [ ! -f "CHANGELOG" ]; then
delete_old_project_files
$if_not_do_make \
fetch_${cmd#build_}
fi
$if_not_do_make \
return 1
x_ ./mk -f "$project" "$target"
}
# projects can specify which other projects
# to build first, as declared dependencies:
build_dependencies()
{
for bd in $build_depend; do
bd_project="${bd%%/*}"
bd_tree="${bd##*/}"
if [ -z "$bd_project" ]; then
$if_not_dry_build \
err "$project/$tree: !bd '$bd'" \
"build_dependencies" "$@"
fi
if [ "${bd##*/}" = "$bd" ]; then
bd_tree=""
fi
if [ -n "$bd_project" ]; then
$if_not_dry_build \
x_ ./mk -b $bd_project $bd_tree; :
fi
done; :
}
# delete_old_project_files along with project_up_to_date,
# concatenates the sha512sum hashes of all files related to
# a project, tree or target, then gets the sha512sum of that
# concatenation. this is checked against any existing
# calculation previously cached; if the result differs, or
# nothing was previously stored, we know to delete resources
# such as builds, project sources and so on, for auto-rebuild:
delete_old_project_files()
{
# delete an entire source tree along with its builds:
if ! project_up_to_date hash "$tree" badhash "$datadir" \
"$configdir/$tree" "$mdir"; then
x_ rm -Rf "src/$project/$tree" "elf/$project/$tree"
fi
x_ cp "$xbtmp/new.hash" "$XBMK_CACHE/hash/$project$tree"
if singletree "$project" || \
[ -z "$target" ] || \
[ "$target" = "$tree" ]; then
return 0
fi
# delete only the builds of a given target, but not src.
# this is useful when only the target config changes, for
# example x200_8mb coreboot configs change, but not coreboot:
if ! project_up_to_date tghash "$target" badtghash "$configdir/$target"
then
x_ rm -Rf "elf/$project/$tree/$target"
fi
x_ cp "$xbtmp/new.hash" "$XBMK_CACHE/tghash/$project$target"
}
project_up_to_date()
{
old_hash=""
hash=""
hashdir="$1"
hashname="$2"
badhashvar="$3"
shift 3
x_ xbmkdir "$XBMK_CACHE/$hashdir"
if [ -f "$XBMK_CACHE/$hashdir/$project$hashname" ]; then
read -r old_hash < "$XBMK_CACHE/$hashdir/$project$hashname" \
|| err \
"$hashdir: err '$XBMK_CACHE/$hashdir/$project$hashname'" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" \
"$@"
fi
build_sbase
fx_ "x_ util/sbase/sha512sum" find "$@" -type f -not -path \
"*/.git*/*" | awk '{print $1}' > "$xbtmp/tmp.hash" || \
err "!h $project $hashdir" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@"
hash="$(x_ "$sha512sum" "$xbtmp/tmp.hash" | awk '{print $1}' || \
err)" || err "$hashname: Can't read sha512 of '$xbtmp/tmp.hash'" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@"
if [ "$hash" != "$old_hash" ] || \
[ ! -f "$XBMK_CACHE/$hashdir/$project$hashname" ]; then
eval "$badhashvar=\"y\""
fi
printf "%s\n" "$hash" > "$xbtmp/new.hash" || \
err "!mkhash $xbtmp/new.hash ($hashdir $hashname $badhashvar)" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@"
eval "[ \"\$$badhashvar\" = \"y\" ] && return 1"; :
}
check_cross_compiler()
{
cbdir="src/coreboot/$tree"
if [ "$project" != "coreboot" ]; then
cbdir="src/coreboot/default"
fi
if [ -n "$xgcctree" ]; then
cbdir="src/coreboot/$xgcctree"
fi
xfix="${1%-*}"
if [ "$xfix" = "x86_64" ]; then
xfix="x64"
fi
xgccfile="elf/coreboot/$tree/xgcc_${xfix}_was_compiled"
xgccargs="crossgcc-$xfix UPDATED_SUBMODULES=1 CPUS=$XBMK_THREADS"
x_ ./mk -f coreboot "${cbdir#src/coreboot/}"
x_ xbmkdir "elf/coreboot/$tree" # TODO: is this needed?
export PATH="$xbmkpwd/$cbdir/util/crossgcc/xgcc/bin:$PATH"
export CROSS_COMPILE="${xarch% *}-"
if [ -n "$xlang" ]; then
export BUILD_LANGUAGES="$xlang"
fi
if [ -f "$xgccfile" ]; then
# skip the build, because a build already exists:
return 0
fi
check_gnu_path gcc gnat || x_ check_gnu_path gnat gcc
# try twice because xgcc sometimes fails for, like, no reason
#
make -C "$cbdir" $xgccargs || x_ make -C "$cbdir" $xgccargs
# this tells subsequent runs that the build was already done:
#
x_ touch "$xgccfile"
# reset hostcc in PATH:
#
remkdir "$xbtmp/gnupath"
}
# host toolchain version correction:
# fix mismatching gcc/gnat versions on debian trixie/sid. as of december 2024,
# trixie/sid had gnat-13 as gnat and gcc-14 as gcc, but has gnat-14 in apt. in
# some cases, gcc 13+14 and gnat-13 are present; or gnat-14 and gcc-14, but
# gnat in PATH never resolves to gnat-14, because gnat-14 was "experimental"
# note that this was implemented for debian trixie-testing, but this same
# issue will likely occur in future distros, including newer debian testing
# releases. this just matches up the versions of each toolchain component.
check_gnu_path()
{
if ! command -v "$1" 1>/dev/null; then
err "Host '$1' unavailable" "check_gnu_path" "$@"
fi
gccdir=""
gccfull=""
gccver=""
gnatdir=""
gnatfull=""
gnatver=""
if host_gcc_gnat_match "$@"; then
return 0
elif ! match_gcc_gnat_versions "$@"; then
return 1
fi
}
# check if gcc/gnat versions already match:
host_gcc_gnat_match()
{
if ! gnu_setver "$1" "$1"; then
err "Command '$1' unavailable." "check_gnu_path" "$@"
fi
gnu_setver "$2" "$2" || :
eval "[ -z \"\$$1ver\" ] && err \"Cannot detect host '$1' version\""
if [ "$gnatfull" != "$gccfull" ]; then
# non-matching host gcc/gnat versions
return 1
fi
}
# find all host gcc/gnat versions, matching them up in PATH:
match_gcc_gnat_versions()
{
eval "$1dir=\"$(dirname "$(command -v "$1")")\""
eval "_gnudir=\"\$$1dir\""
eval "_gnuver=\"\$$1ver\""
for _bin in "$_gnudir/$2-"*; do
if [ "${_bin#"$_gnudir/$2-"}" = "$_gnuver" ] && [ -x "$_bin" ]
then
_gnuver="${_bin#"$_gnudir/$2-"}"
break
fi
done
if ! gnu_setver "$2" "$_gnudir/$2-$_gnuver"; then
return 1
elif [ "$gnatfull" != "$gccfull" ]; then
return 1
fi
( link_gcc_gnat_versions "$@" "$_gnudir" "$_gnuver" ) || \
err "Can't link '$2-$_gnuver' '$_gnudir'" "check_gnu_path" "$@"; :
}
# create symlinks in PATH, so that the GCC/GNAT versions match:
link_gcc_gnat_versions()
{
_gnudir="$3"
_gnuver="$4"
remkdir "$xbtmp/gnupath"
x_ cd "$xbtmp/gnupath"
for _gnubin in "$_gnudir/$2"*"-$_gnuver"; do
_gnuutil="${_gnubin##*/}"
if [ -e "$_gnubin" ]; then
x_ ln -s "$_gnubin" "${_gnuutil%"-$_gnuver"}"
fi
done
}
# get the gcc/gnat version
# fail: return 1 if util not found
gnu_setver()
{
eval "$2 --version 1>/dev/null 2>/dev/null || return 1"
eval "$1ver=\"`"$2" --version 2>/dev/null | head -n1`\""
eval "$1ver=\"\${$1ver##* }\""
eval "$1full=\"\$$1ver\""
eval "$1ver=\"\${$1ver%%.*}\""; :
}
check_defconfig()
{
if [ ! -f "$defconfig" ]; then
$if_not_dry_build \
err "$project/$target: no config" "check_defconfig" "$@"
fi
dest_dir="$elfdir/$tree/$target/${defconfig#"$target_dir/config/"}"
# skip build if a previous one exists:
$if_dry_build \
return 0
if ! elfcheck; then
return 1
fi
}
elfcheck()
{
# TODO: *STILL* very hacky check. do it properly (based on build.list)
# extremely hacky check that glues the entire universe together
# beware demons
( fx_ "eval exit 1 && err" find "$dest_dir" -type f ) || return 1; :
}
handle_makefile()
{
if $if_not_dry_build check_makefile "$srcdir"; then
$if_not_dry_build \
x_ make -C "$srcdir" $cleanargs clean
fi
if [ -f "$defconfig" ]; then
x_ cp "$defconfig" "$srcdir/.config"
fi
run_make_command || \
err "no makefile!" "handle_makefile" "$@"
_copy=".config"
if [ "$mode" = "savedefconfig" ]; then
_copy="defconfig"
fi
if [ "${mode%config}" != "$mode" ]; then
$if_not_dry_build \
x_ cp "$srcdir/$_copy" "$defconfig"; :
fi
if [ -e "$srcdir/.git" ] && \
[ "$project" = "u-boot" ] && \
[ "$mode" = "distclean" ]; then
$if_not_dry_build \
x_ git -C "$srcdir" $cleanargs clean -fdx; :
fi
}
run_make_command()
{
if [ -z "$mode" ]; then
x_ $premake
fi
if $if_not_dry_build check_cmake "$srcdir"; then
if [ -z "$mode" ]; then
$if_not_dry_build \
check_autoconf "$srcdir"
fi
fi
if ! $if_not_dry_build check_makefile "$srcdir"; then
return 1
fi
$if_not_dry_build \
x_ make -C "$srcdir" $mode -j$XBMK_THREADS $makeargs
if [ -z "$mode" ]; then
x_ $mkhelper
fi
if ! check_makefile "$srcdir"; then
return 0
fi
if [ "$mode" = "clean" ]; then
$if_dry_build \
return 0
if ! make -C "$srcdir" $cleanargs distclean; then
x_ make -C "$srcdir" $cleanargs clean
fi
fi
}
check_cmake()
{
$if_dry_build \
return 0
if [ ! -n "$cmakedir" ]; then
return 0
elif ! check_makefile "$1"; then
if ! cmake -B "$1" "$1/$cmakedir"; then
x_ check_makefile "$1"
fi
fi
x_ check_makefile "$1"; :
}
check_autoconf()
{
(
x_ cd "$1"
if [ -f "bootstrap" ]; then
x_ ./bootstrap $bootstrapargs
fi
if [ -f "autogen.sh" ]; then
x_ ./autogen.sh $autogenargs
fi
if [ -f "configure" ]; then
x_ ./configure $autoconfargs; :
fi
) || err "can't bootstrap project: $1" "check_autoconf" "$@"; :
}
check_makefile()
{
if [ ! -f "$1/Makefile" ] && \
[ ! -f "$1/makefile" ] && \
[ ! -f "$1/GNUmakefile" ]; then
return 1
fi
}
copy_elf()
{
if [ -f "$listfile" ]; then
x_ xbmkdir "$dest_dir"
fi
if [ -f "$listfile" ]; then
while read -r f; do
if [ -f "$srcdir/$f" ]; then
x_ cp "$srcdir/$f" "$dest_dir"
fi
done < "$listfile" || err \
"cannot read '$listfile'" "copy_elf" "$@"; :
fi
( x_ make clean -C "$srcdir" $cleanargs ) || \
err "can't make-clean '$srcdir'" "copy_elf" "$@"; :
}
+519 -51
View File
@@ -1,82 +1,550 @@
#!/usr/bin/env sh #!/bin/sh
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (c) 2020-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2020-2026 Leah Rowe <leah@libreboot.org>
# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com>
# Copyright (c) 2022-2023 Alper Nebi Yasak <alpernebiyasak@gmail.com>
# Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
set -u -e set -u -e
ispwd="true" findpath()
{
forx 'readlink -f \"%s\" 2>/dev/null || \
x_ realpath \"%s\" 2>/dev/null' "$@"
}
if [ "$0" != "./mk" ]; then printf "%s\n" "%s" | grep -o "%s" 1>/dev/null || exit 1 # safety (-o check)
forx()
{
awkarg="{printf \"${1-};\""
shift 1 2>/dev/null || :
ispwd="false" scount="$(printf "%s\n" "$awkarg" | grep -o "%s" | wc -l)"
fi while [ $scount -gt 0 ]; do
if [ "$ispwd" = "true" ] && [ -L "mk" ]; then awkarg="$awkarg,\$0"
scount="$(expr $scount - 1 || :)"
done
ispwd="false" while [ $# -gt 0 ]; do
fi eval "$(printf '%s\n' "$1" | awk "$awkarg}")"
if [ "$ispwd" = "false" ]; then shift 1
done
}
x_()
{
[ $# -lt 1 ] || "$@" || err "UNHANDLED ERROR" "x_" "$@"; :
}
err()
{
printf '%s\n' "$@" | awk '{printf "\"%s\" ", $0}'
printf "ERROR!\n"
printf "You must run this in the proper work directory.\n" 1>&2
exit 1 exit 1
fi }
forx 'export %s=\"C.UTF-8\"' LANG LANGUAGE LC_CTYPE LC_NUMERIC LC_TIME \
LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS \
LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION LC_ALL
(
mk="$0"
[ "${mk##*/}" != "$mk" ] || \
mk="$(x_ command -v "$mk")" || exit 1
mk="$(x_ findpath "$mk")" || exit 1
xbmkpwd="$(x_ dirname "$mk")" || exit 1
x_ cd "$xbmkpwd"
. "include/lib.sh" . "include/lib.sh"
. "include/init.sh" . "include/env/init.sh"
. "include/vendor.sh" x_ xbmk_init "$@"
. "include/mrc.sh"
. "include/inject.sh" . "include/env/get.sh"
. "include/rom.sh"
. "include/release.sh" . "include/fw/vendor.sh"
. "include/get.sh" . "include/fw/mrc.sh"
. "include/chromebook.sh" . "include/fw/inject.sh"
. "include/fw/rom.sh"
. "include/mk/release.sh"
_f="${1-}"
shift 1 2>/dev/null || :
eval "$(printf "version release download inject\n" | awk '{ for (i=1; i<=NF; \
i++) $i = "[ \""$i"\" = \"$_f\" ] && x_ "$i" \"$@\" && exit 0;"; print }')"
# macros, overridden depending on the flag
if_not_do_make=":" # : means false
if_make_config=":"
if_build=":" # can be false even if make is true
if_dry_build=":"
if_single_tree=":"
eval "`newvar if_do_make if_not_make_config if_not_build if_not_dry_build`"
eval "`newvar configureargs autogenargs badhash badtghash bootstrapargs \
build_depend buildtype cleanargs cmakedir cmd defconfig dest_dir elfdir \
flag forcepull listfile makeargs mdir mkhelper mkhelpercfg mode postmake \
premake project release rev srcdir target target_dir tree xarch xgcctree \
xlang`"
main() main()
{ {
cmd="" flags="f:F:b:m:u:s:l:n:d:"
if [ $# -gt 0 ]; then
cmd="$1" while getopts $flags option
shift 1 do
[ -n "$flag" ] && \
err "only one flag is permitted" "trees" "$@"
flag="$1"
# the "mode" variable is affixed to a make command, example:
# "$mk" -m coreboot does: make menuconfig -C src/coreboot/tree
case "$flag" in
-b) : ;; # build a source tree
-d) # dry builds. -d is like -b but skips many build steps
if_dry_build=""
if_not_dry_build=":"
;;
-f|-F) # download source code for a project
eval "`newvar if_not_do_make if_dry_build`"
if_do_make=":"
if_not_dry_build=":"
[ "$flag" = "-F" ] && \
forcepull="y"; : # never skip git fetch/pull
;;
-u) mode="oldconfig" ;;
-m) mode="menuconfig" ;;
-s) mode="savedefconfig" ;;
-l) mode="olddefconfig" ;;
-n) mode="nconfig" ;;
*) err "invalid option '-$option'" "trees" "$@" ;;
esac
if [ -z "$mode" ]; then
if_build=""
if_not_build=":"
fi
if [ "${mode%config}" != "$mode" ]; then
if_make_config=""
if_not_make_config=":"
fi
if [ -z "${OPTARG+x}" ]; then
shift 1
break
fi
project="${OPTARG#src/}"
project="${project#config/git/}"
shift 2
done
if [ -z "$flag" ]; then
err "missing flag ($flags)" "trees" "$@"
elif [ -z "$project" ]; then
fx_ "x_ "$mk" $flag" x_ ls -1 config/git
return 0
elif [ ! -f "config/git/$project/pkg.cfg" ]; then
err "config/git/$project/pkg.cfg missing" "trees" "$@"
fi fi
case "$cmd" in elfdir="elf/$project"
datadir="config/data/$project"
configdir="config/$project"
srcdir="src/$project"
dest_dir="$elfdir"
version) listfile="$datadir/build.list"
[ ! -f "$listfile" ] && \
listfile="" # build.list is optional on all projects
printf "%s\nWebsite: %s\n" "$relname" "$projectsite" mkhelpercfg="$datadir/mkhelper.cfg"
;; if e "$mkhelpercfg" f missing; then
mkhelpercfg="$xbtmp/mkhelper.cfg"
x_ touch "$mkhelpercfg"
fi
release|download|inject|prep_mr_import) if singletree "$project"; then
cmd="mk_single_tree"
if_single_tree=""
else
cmd="mk_multi_tree"
fi
$cmd "$@" remkdir "${tmpgit%/*}"
;; x_ touch "$mkhelpercfg"
-*) . "$mkhelpercfg"
$cmd "$@"
return 0
;;
*)
err "bad command" main "$@"
;;
esac
# some commands disable them. turn them back on!
set -u -e
return 1
} }
main "$@" || exit 0 mk_single_tree()
{
configure_project "$configdir" || \
return 0
. "include/tree.sh" [ ! -f "$listfile" ] || $if_not_dry_build \
elfcheck || return 0
trees "$@" || exit 0 run_make_command && $if_build $if_not_dry_build \
copy_elf; :
}
x_ touch "$mkhelpercfg" mk_multi_tree()
{
[ ! -d "$configdir" ] && err "missing '$configdir'" mk_multi_tree "$@"
[ $# -lt 1 ] && fx_ mk_multi_tree find "$configdir" \
-mindepth 1 -maxdepth 1 -type d
. "$mkhelpercfg" [ $# -gt 0 ] && for x in "$@"
$cmd do
unset CROSS_COMPILE
export PATH="$xbmkpath"
if [ "$x" = "list" ]; then
x_ ls -1 "config/$project"
listfile=""
break
fi
printf "'make %s', '%s', '%s'\n" "$mode" "$project" "$x"
target="${x##*/}"
x_ handle_defconfig
$if_build \
x_ $postmake; :
done; :
}
handle_defconfig()
{
target_dir="$configdir/$target"
[ ! -f "CHANGELOG" ] && \
single_tree_fetch "$project"
configure_project "$target_dir" || \
return 0
[ -z "$tree" ] && err "$configdir: 'tree' unset" handle_defconfig "$@"
srcdir="src/$project/$tree"
[ -d "$srcdir" ] && for y in "$target_dir/config"/*
do
[ ! -f "$y" ] && \
$if_not_dry_build \
continue
$if_not_dry_build eval \
defconfig="$y"
$if_build \
prep_mk_multi_tree || continue
handle_makefile
$if_build $if_not_dry_build \
copy_elf; :
done; :
}
configure_project()
{
_tcfg="$1/target.cfg"
eval "`newvar configureargs badhash badtghash bootstrapargs \
build_depend buildtype cleanargs makeargs mkhelper postmake \
premake release xarch xgcctree xlang`"
[ ! -f "$_tcfg" ] && buildtype="auto"
# globally initialise all variables for a source tree / target:
if e "$datadir/mkhelper.cfg" f; then
. "$datadir/mkhelper.cfg" || \
err "Can't read '$datadir/mkhelper.cfg'" \
"configure_project" "$@"
fi
# override target/tree specific variables from per-target config:
while e "$_tcfg" f || [ "$cmd" != "mk_single_tree" ]
do
printf "Loading %s config: %s\n" "$project" "$_tcfg"
eval "`newvar rev tree`"
. "$_tcfg" || err "Can't read '$_tcfg'" configure_project "$@"
$if_dry_build eval \
build_depend=""
$if_single_tree \
break
$if_do_make \
break
[ "${_tcfg%/*/target.cfg}" = "${_tcfg%"/$tree/target.cfg"}" ] \
&& break # target and tree matching was successful
_tcfg="${_tcfg%/*/target.cfg}/$tree/target.cfg" # try next
done
[ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ] && \
return 1
[ -n "$buildtype" ] && $if_make_config \
return 1
$if_build $if_not_dry_build \
build_dependencies
mdir="$xbmkpwd/config/submodule/$project"
[ -n "$tree" ] && mdir="$mdir/$tree"
if [ ! -f "CHANGELOG" ]; then
delete_old_project_files
$if_not_do_make \
${cmd#mk_}_fetch
fi
$if_not_do_make \
return 1
x_ "$mk" -f "$project" "$target"
}
# projects can specify which other projects
# to build first, as declared dependencies:
build_dependencies()
{
for bd in $build_depend
do
bd_project="${bd%%/*}"
bd_tree="${bd##*/}"
[ -z "$bd_project" ] && \
$if_not_dry_build \
err "$project/$tree: !bd '$bd'" \
"build_dependencies" "$@"
[ "${bd##*/}" = "$bd" ] && \
bd_tree=""
[ -n "$bd_project" ] && \
$if_not_dry_build \
x_ "$mk" -b $bd_project $bd_tree; :
done; :
}
# delete_old_project_files along with project_up_to_date,
# concatenates the sha512sum hashes of all files related to
# a project, tree or target, then gets the sha512sum of that
# concatenation. this is checked against any existing
# calculation previously cached; if the result differs, or
# nothing was previously stored, we know to delete resources
# such as builds, project sources and so on, for auto-rebuild:
delete_old_project_files()
{
# delete an entire source tree along with its builds:
project_up_to_date hash "$tree" badhash "$datadir" \
"$configdir/$tree" "$mdir" || \
x_ rm -Rf "src/$project/$tree" "elf/$project/$tree"
x_ cp "$xbtmp/new.hash" "$XBMK_CACHE/hash/$project$tree"
if singletree "$project" || [ -z "$target" ] || [ "$target" = "$tree" ]
then
return 0
fi
# delete only the builds of a given target, but not src.
# this is useful when only the target config changes, for
# example x200_8mb coreboot configs change, but not coreboot:
project_up_to_date tghash "$target" badtghash "$configdir/$target" || \
x_ rm -Rf "elf/$project/$tree/$target"
x_ cp "$xbtmp/new.hash" "$XBMK_CACHE/tghash/$project$target"
}
project_up_to_date()
{
eval "`newvar hash old_hash`"
hashdir="$1"
hashname="$2"
badhashvar="$3"
shift 3
x_ mkdir -p "$XBMK_CACHE/$hashdir"
if [ -f "$XBMK_CACHE/$hashdir/$project$hashname" ]; then
read -r old_hash < "$XBMK_CACHE/$hashdir/$project$hashname" \
|| err \
"$hashdir: err '$XBMK_CACHE/$hashdir/$project$hashname'" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" \
"$@"
fi
eval "$build_sbase"
fx_ "x_ util/sbase/sha512sum" find "$@" -type f -not -path \
"*/.git*/*" | awk '{print $1}' > "$xbtmp/tmp.hash" || \
err "!h $project $hashdir" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@"
hash="$(x_ "$sha512sum" "$xbtmp/tmp.hash" | awk '{print $1}' || \
err)" || err "$hashname: Can't read sha512 of '$xbtmp/tmp.hash'" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@"
if [ "$hash" != "$old_hash" ] || \
[ ! -f "$XBMK_CACHE/$hashdir/$project$hashname" ]; then
eval "$badhashvar=\"y\""
fi
printf "%s\n" "$hash" > "$xbtmp/new.hash" || \
err "!mkhash $xbtmp/new.hash ($hashdir $hashname $badhashvar)" \
"project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@"
eval "[ \"\$$badhashvar\" = \"y\" ] && return 1"; :
}
prep_mk_multi_tree()
{
dest_dir="$elfdir/$tree/$target/${defconfig#"$target_dir/config/"}"
$if_not_dry_build elfcheck || return 1 # skip if a build exists
$if_not_dry_build eval "$(printf '%s\n' "$xarch" | awk \
'{ for (i=1; i<=NF; i++) $i = "check_xgcc \""$i"\";"; print }')"
}
check_xgcc()
{
cbdir="src/coreboot/$tree"
[ "$project" != "coreboot" ] && \
cbdir="src/coreboot/default"
[ -n "$xgcctree" ] && \
cbdir="src/coreboot/$xgcctree"
cbelfdir="elf${cbdir#src}"
xfix="${1%-*}"
[ "$xfix" = "x86_64" ] && xfix="x64"
xgccfile="$cbelfdir/xgcc_${xfix}_was_compiled"
xgccargs="crossgcc-$xfix UPDATED_SUBMODULES=1 CPUS=$XBMK_THREADS"
x_ "$mk" -f coreboot "${cbdir#src/coreboot/}"
x_ mkdir -p "$cbelfdir"
# tell build systems what cross-compiler to use
export PATH="$xbmkpwd/$cbdir/util/crossgcc/xgcc/bin:$PATH"
export CROSS_COMPILE="${xarch% *}-" # used by e.g. u-boot
# coreboot-specific (we disable gnat on some trees)
[ -n "$xlang" ] && \
export BUILD_LANGUAGES="$xlang"
[ -f "$xgccfile" ] && return 0 # skip (build already exists)
make -C "$cbdir" $xgccargs || x_ make -C "$cbdir" $xgccargs
x_ touch "$xgccfile" # prevent unnecessary re-build operations
}
elfcheck()
{
# TODO: *STILL* very hacky check. do it properly (based on build.list)
( fx_ "eval exit 1 && err" find "$dest_dir" -type f ) || return 1; :
}
handle_makefile()
{
check_makefile "$srcdir" && $if_not_dry_build \
x_ make -C "$srcdir" clean $cleanargs
[ -f "$defconfig" ] && \
x_ cp "$defconfig" "$srcdir/.config"
run_make_command || err "no makefile!" "handle_makefile" "$@"
_copy=".config"
[ "$mode" = "savedefconfig" ] && \
_copy="defconfig"
$if_make_config \
x_ cp "$srcdir/$_copy" "$defconfig"; :
}
run_make_command()
{
$if_build \
x_ $premake
$if_not_dry_build \
run_make_command_real || return 1
$if_build \
x_ $mkhelper; :
}
run_make_command_real()
{
[ -z "$cmakedir" ] || \
x_ cmake -B "$srcdir" "$srcdir/$cmakedir"
$if_build \
check_autoconf "$srcdir"
check_makefile "$srcdir" || return 1
x_ make -C "$srcdir" $mode -j$XBMK_THREADS $makeargs
}
check_autoconf()
{
(
x_ cd "$1"
[ -f "bootstrap" ] && \
x_ ./bootstrap $bootstrapargs
[ -f "autogen.sh" ] && \
x_ ./autogen.sh $autogenargs
[ -f "configure" ] && \
x_ ./configure $configureargs; :
) || err "can't bootstrap project: $1" check_autoconf "$@"; :
}
check_makefile()
{
[ ! -f "$1/Makefile" ] && [ ! -f "$1/makefile" ] && \
[ ! -f "$1/GNUmakefile" ] && return 1; :
}
copy_elf()
{
[ -f "$listfile" ] && \
x_ mkdir -p "$dest_dir"
if [ -f "$listfile" ]; then
while read -r f; do
[ -f "$srcdir/$f" ] && \
x_ cp "$srcdir/$f" "$dest_dir"; :
done < "$listfile" || err \
"cannot read '$listfile'" "copy_elf" "$@"; :
fi
( x_ make -C "$srcdir" clean $cleanargs ) || \
err "can't make-clean '$srcdir'" "copy_elf" "$@"; :
}
x_ main "$_f" "$@"
) || exit 1; :
-7
View File
@@ -1,7 +0,0 @@
/nvm
/nvmutil
/mkhtemp
/lottery
*.bin
*.o
*.d
-2
View File
@@ -1,2 +0,0 @@
Leah Rowe
Riku Viitanen
-21
View File
@@ -1,21 +0,0 @@
Copyright (C) 2022-2026 Leah Rowe <leah@libreboot.org>
Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com>
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.
-60
View File
@@ -1,60 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2022,2026 Leah Rowe <leah@libreboot.org>
# Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com>
CC = cc
CFLAGS = -Os -Wall -Wextra -std=c99 -pedantic
LDFLAGS =
PREFIX = /usr/local
DESTDIR =
INSTALL = install
PROGS = nvmutil mkhtemp lottery
LIB_OBJS = \
lib/state.o \
lib/file.o \
lib/string.o \
lib/usage.o \
lib/command.o \
lib/num.o \
lib/io.o \
lib/checksum.o \
lib/word.o \
lib/mkhtemp.o \
lib/rand.o
OBJS_NVMUTIL = nvmutil.o $(LIB_OBJS)
OBJS_MKHTEMP = mkhtemp.o lib/file.o lib/string.o lib/num.o lib/mkhtemp.o lib/rand.o
OBJS_LOTTERY = lottery.o lib/file.o lib/string.o lib/num.o lib/mkhtemp.o lib/rand.o
all: $(PROGS)
nvmutil: $(OBJS_NVMUTIL)
$(CC) $(CFLAGS) $(OBJS_NVMUTIL) -o $@ $(LDFLAGS)
mkhtemp: $(OBJS_MKHTEMP)
$(CC) $(CFLAGS) $(OBJS_MKHTEMP) -o $@ $(LDFLAGS)
lottery: $(OBJS_LOTTERY)
$(CC) $(CFLAGS) $(OBJS_LOTTERY) -o $@ $(LDFLAGS)
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
install: $(PROGS)
mkdir -p $(DESTDIR)$(PREFIX)/bin
for p in $(PROGS); do \
$(INSTALL) $$p $(DESTDIR)$(PREFIX)/bin/$$p; \
chmod 755 $(DESTDIR)$(PREFIX)/bin/$$p; \
done
uninstall:
for p in $(PROGS); do \
rm -f $(DESTDIR)$(PREFIX)/bin/$$p; \
done
clean:
rm -f $(PROGS) *.o lib/*.o
distclean: clean
-254
View File
@@ -1,254 +0,0 @@
Mkhtemp - Hardened mktemp
-------------------------
Just like normal mktemp, but hardened.
Create new files and directories randomly as determined by
the user's TMPDIR, or fallback. These temporary files and
directories can be generated from e.g. shell scripts, running
mkhtemp. There is also a library that you could use in your
program. Portable to Linux and BSD. **WORK IN PROGRESS.
This is a very new project. Expect bugs - a stable release
will be announced, when the code has matured.**
A brief summary of *why* mkhtemp is more secure (more
details provided later in this readme - please also
read the source code):
Detect and mitigate symlink attacks, directory access
race conditions, unsecure TMPDIR (e.g. bad enforce sticky
bit policy on world writeable dirs), implement in user
space a virtual sandbox (block directory escape and resolve
paths by walking from `/` manually instead of relying on
the kernel/system), voluntarily error out (halt all
operation) if accessing files you don't own - that's why
sticky bits are checked for example, even when you're root.
It... blocks symlinks, relative paths, attempts to prevent
directory escape (outside of the directory that the file
you're creating is in), basically implementing an analog
of something like e.g. unveil, but in userspace!
Mkhtemp is designed to be the most secure implementation
possible, of mktemp, offering a heavy amount of hardening
over traditional mktemp. Written in C99, and the plan is
very much to keep this code portable over time - patches
very much welcome.
i.e. please read the source code
```
/*
* WARNING: WORK IN PROGRESS.
* Do not use this software in
* your distro yet. It's ready
* when it's ready. Read the src.
*
* What you see is an early beta.
*
* Please do not merge this in
* your Linux distro package repo
* yet (unless maybe you're AUR).
*/
```
Supported mktemp flags:
```
mkhtemp: usage: mkhtemp [-d] [-p dir] [template]
-p DIR <-- set directory, overriding TMPDIR
-d <-- make a directory instead of a file
-q <-- silence errors (exit status unchanged)
```
The rest of them will be added later (the same ones
that GNU and BSD mktemp implement). With these options,
you can generate files/directories already.
You can also write a template at the end. e.g.
```
mkhtemp -d -p path/to/directory vickysomething_XXXXXXXXXXX
```
On most sane/normal setups, the program should already
actually work, but please know that it's very different
internally than every other mktemp implementation.
Read the source code if you're interested. As of this
time of writing, mkhtemp is very new, and under
development. A stable release will be announced when ready.
### What does mkhtemp do differently?
This software attempts to provide mitigation against
several TOCTOU-based
attacks e.g. directory rename / symlink / re-mount, and
generally provides much higher strictness than previous
implementations such as mktemp, mkstemp or even mkdtemp.
It uses several modern features by default, e.g. openat2
and `O_TMPFILE` (plus `O_EXCL`) on Linux, with additional
hardening; BSD projects only have openat so the code uses
that there, but some (not all) of the kinds of checks
Openat2 enforces are done manually (in userspace).
File system sandboxing in userspace (pathless discovery,
and operations are done only with FDs). At startup, the
root directory is opened, and then everything is relative
to that.
Many programs rely on mktemp, and they use TMPDIR in a way
that is quite insecure. Mkhtemp intends to change that,
quite dramatically, with: userspace sandbox (and use OS
level options e.g. OBSD pledge where available), constant
identity/ownership checks on files, MUCH stricter ownership
restrictions (e.g. enforce sticky bit policy on world-
writeable tmpdirs), preventing operation on other people's
files (only your own files) - even root is restricted,
depending on how the code is compiled. Please read the code.
Basically, the gist of it is that normal mktemp *trusts*
your system is set up properly. It will just run however
you tell it to, on whatever directory you tell it to, and
if you're able to write to it, it will write to it.
Some implementations (e.g. OpenBSD one) do some checks,
but not all of them do *all* checks. The purpose of
mkhtemp is to be as strict as possible, while still being
reliable enough that people can use it. Instead of catering
to legacy requirements, mkhtemp says that systems should
be secure. So if you're running in an insecure environment,
the goal of mkhtemp is to *exit* when you run it; better
this than files being corrupted.
Security and reliability are the same thing. They both
mean that your computer is behaving as it should, in a
manner that you can predict.
It doesn't matter how many containers you have, or how
memory-safe your programming language is, the same has
been true forever: code equals bugs, and code usually
has the same percentage of bugs, so more code equals
more bugs. Therefore, highly secure systems (such as
OpenBSD) typically try to keep their code as small and
clean as possible, so that they can audit it. Mkhtemp
assumes that your system is hostile, and is designed
accordingly.
What?
-----
This is the utility version, which makes use of the also-
included library. No docs yet - source code are the docs,
and the (ever evolving, and hardening) specification.
This was written from scratch, for use in nvmutil, and
it is designed to be portable (BSD, Linux). Patches
very much welcome.
Caution
-------
This is a new utility. Expect bugs.
```
WARNING: This is MUCH stricter than every other mktemp
implementation, even more so than mkdtemp or
the OpenBSD version of mkstemp. It *will* break,
or more specifically, reveal the flaws in, almost
every major critical infrastructure, because most
people already use mktemp extremely insecurely.
```
This tool is written by me, for me, and also Libreboot, but
it will be summitted for review to various Linux distros
and BSD projects once it has reached maturity.
### Why was this written?
Atomic writes were implemented in nvmutil (Libreboot's
Intel GbE NVM editor), but one element remained: the
program mktemp, itself, which has virtually no securitty
checks whatsoever. GNU and BSD implementations use
mkstemp now, which is a bit more secure, and they offer
additional hardening, but I wanted to be reasonably
assured that my GbE files were not being corrupted in
any way, and that naturally led to writing a hardened
tool. It was originally just going to be for nvmutil,
but then it became its own standard utility.
Existing implementations of mktemp just simply do not
have sufficient checks in place to prevent misuse. This
tool, mkhtemp, intentionally focuses on being secure
instead of easy. For individuals just running Linux on
their personal machine, it might not make much difference,
but corporations and projects running computers for lots
of big infrastructure need something reliable, since
mktemp is just one of those things everyone uses.
Every big program needs to make temporary files.
But the real reason I wrote this tool is because, it's
fun, and because I wanted to challenge myself.
Roadmap
-------
Some things that are in the near future for mkhtemp
development:
Thoroughly document every known case of CVEs in the wild,
and major attacks against individuals/projects/corporations
that were made possible by mktemp - that mkhtemp might
have prevented. There are several.
More hardening; still a lot more that can be done, depending
on OS. E.g. integrate FreeBSD capsicum.
Another example: although usually reliable, comparing the
inode and device of a file/directory isn't by itself sufficient.
There are other checks that mkhtemp does; for example I could
implement it so that directories are more aggressively re-
opened by mkhtemp itself, mid-operation. This re-opening
would be quite expensive computationally, but it would then
allow us to re-check everything, since we store state from
when the program starts.
Tidy up the code: the current code was thrown together in
a week, and needs tidying. A proper specification should be
written, to define how it works, and then the code should
be auditted for compliance. A lot of the functions are
also quite complex and do a lot; they could be split up.
Right now, mkhtemp mainly returns a file descriptor and
a path, after operation, ironic given the methods it uses
while opening your file/dir. After it's done, you then have
to handle everything again. Mkhtemp could keep everything
open instead, and continue to provide verification; in
other words, it could provide a completely unified way for
Linux/BSD programs to open files, write to them atomically,
and close. Programs like Vim will do this for example, or
other text editors, but every program has its own way. So
what mkhtemp could do is provide a well-defined API alongside
its mktemp hardening. Efforts would be made to avoid
feature creep, and ensure that the code remains small and
nimble.
Compatibility mode: another thing is that mkhtemp is a bit
too strict for some users, so it may break some setups. What
it could do is provide a compatibility mode, and in this
mode, behave like regular mktemp. That way, it could become
a drop-in replacement on Linux distros (and BSDs if they
want it), while providing a more hardened version and
recommending that where possible.
~~Rewrite it in rust~~ (nothing against it though, I just like C99 for some reason)
Also, generally document the history of mktemp, and how
mkhtemp works in comparison.
Also a manpage.
Once all this is done, and the project is fully polished,
then it will be ready for your Linux distro. For now, I
just use it in nvmutil (and I also use it on my personal
computer).
-607
View File
@@ -1,607 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
TODO: this file should be split, into headers for each
C source file specifically. it was originally just
for nvmutil, until i added mkhtemp to the mix
*/
#ifndef COMMON_H
#define COMMON_H
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
/* dangerously cool macros:
*/
#define SUCCESS(x) ((x) >= 0)
/* syscalls can set errno even on success; this
* is rare, but permitted. in various functions, we
* reset errno on success, to what the caller had,
* but we must still honour what was returned.
*
* lib/file.c is littered with examples
*/
#define reset_caller_errno(return_value) \
do { \
if (SUCCESS(return_value) && (!errno)) \
errno = saved_errno; \
} while (0)
#define items(x) (sizeof((x)) / sizeof((x)[0]))
#define MKHTEMP_RETRY_MAX 512
#define MKHTEMP_SPIN_THRESHOLD 32
#define MKHTEMP_FILE 0
#define MKHTEMP_DIR 1
/* if 1: on operations that
* check ownership, always
* permit root to access even
* if not the file/dir owner
*/
#ifndef ALLOW_ROOT_OVERRIDE
#define ALLOW_ROOT_OVERRIDE 0
#endif
/*
*/
#ifndef SSIZE_MAX
#define SSIZE_MAX ((ssize_t)(~((ssize_t)1 << (sizeof(ssize_t)*CHAR_BIT-1))))
#endif
/* build config
*/
#ifndef NVMUTIL_H
#define NVMUTIL_H
#define MAX_CMD_LEN 50
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#ifndef PATH_MAX
#error PATH_MAX_undefined
#elif ((PATH_MAX) < 1024)
#error PATH_MAX_too_low
#endif
#ifndef S_ISVTX
#define S_ISVTX 01000
#endif
#if defined(S_IFMT) && ((S_ISVTX & S_IFMT) != 0)
#error "Unexpected bit layout"
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
#ifndef O_ACCMODE
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef O_EXCL
#define O_EXCL 0
#endif
#ifndef O_CREAT
#define O_CREAT 0
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK 0
#endif
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 0
#endif
#ifndef FD_CLOEXEC
#define FD_CLOEXEC 0
#endif
/* Sizes in bytes:
*/
#define SIZE_1KB 1024
#define SIZE_4KB (4 * SIZE_1KB)
#define SIZE_8KB (8 * SIZE_1KB)
#define SIZE_16KB (16 * SIZE_1KB)
#define SIZE_128KB (128 * SIZE_1KB)
#define GBE_BUF_SIZE (SIZE_128KB)
/* First 128 bytes of gbe.bin is NVM.
* Then extended area. All of NVM must
* add up to BABA, truncated (LE)
*
* First 4KB of each half of the file
* contains NVM+extended.
*/
#define GBE_WORK_SIZE (SIZE_8KB)
#define GBE_PART_SIZE (GBE_WORK_SIZE >> 1)
#define NVM_CHECKSUM 0xBABA
#define NVM_SIZE 128
#define NVM_WORDS (NVM_SIZE >> 1)
#define NVM_CHECKSUM_WORD (NVM_WORDS - 1)
/* argc minimum (dispatch)
*/
#define ARGC_3 3
#define ARGC_4 4
/* For checking if an fd is a normal file.
* Portable for old Unix e.g. v7 (S_IFREG),
* 4.2BSD (S_IFMT), POSIX (S_ISREG).
*
* IFREG: assumed 0100000 (classic bitmask)
*/
#ifndef S_ISREG
#if defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#elif defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFREG) != 0)
#else
#error "can't determine types with stat()"
#endif
#endif
#define IO_READ 0
#define IO_WRITE 1
#define IO_PREAD 2
#define IO_PWRITE 3
/* for nvmutil commands
*/
#define CMD_DUMP 0
#define CMD_SETMAC 1
#define CMD_SWAP 2
#define CMD_COPY 3
#define CMD_CAT 4
#define CMD_CAT16 5
#define CMD_CAT128 6
#define ARG_NOPART 0
#define ARG_PART 1
#define SKIP_CHECKSUM_READ 0
#define CHECKSUM_READ 1
#define SKIP_CHECKSUM_WRITE 0
#define CHECKSUM_WRITE 1
/* command table
*/
typedef void (*func_t)(void);
struct commands {
size_t chk;
char *str;
func_t run;
int argc;
unsigned char arg_part;
unsigned char chksum_read;
unsigned char chksum_write;
size_t rw_size; /* within the 4KB GbE part */
int flags; /* e.g. O_RDWR or O_RDONLY */
};
/* mac address
*/
struct macaddr {
char *str; /* set to rmac, or argv string */
char rmac[18]; /* xx:xx:xx:xx:xx:xx */
unsigned short mac_buf[3];
};
/* gbe.bin and tmpfile
*/
struct xfile {
int gbe_fd;
struct stat gbe_st;
int tmp_fd;
struct stat tmp_st;
char *tname; /* path of tmp file */
char *fname; /* path of gbe file */
unsigned char *buf; /* work memory for files */
int io_err_gbe; /* intermediary write (verification) */
int io_err_gbe_bin; /* final write (real file) */
int rw_check_err_read[2];
int rw_check_partial_read[2];
int rw_check_bad_part[2];
int post_rw_checksum[2];
off_t gbe_file_size;
off_t gbe_tmp_size;
size_t part;
unsigned char part_modified[2];
unsigned char part_valid[2];
unsigned char real_buf[GBE_BUF_SIZE];
unsigned char bufcmp[GBE_BUF_SIZE]; /* compare gbe/tmp/reads */
unsigned char pad[GBE_WORK_SIZE]; /* the file that wouldn't die */
/* we later rename in-place, using old fd. renameat() */
int dirfd;
char *base;
char *tmpbase;
};
/* Command table, MAC address, files
*
* BE CAREFUL when editing this
* to ensure that you also update
* the tables in xstatus()
*/
struct xstate {
struct commands cmd[7];
struct macaddr mac;
struct xfile f;
size_t i; /* index to cmd[] for current command */
int no_cmd;
/* Cat commands set this.
the cat cmd helpers check it */
int cat;
};
struct filesystem {
int rootfd;
};
struct xstate *xstart(int argc, char *argv[]);
struct xstate *xstatus(void);
/* Sanitize command tables.
*/
void sanitize_command_list(void);
void sanitize_command_index(size_t c);
/* Argument handling (user input)
*/
void set_cmd(int argc, char *argv[]);
void set_cmd_args(int argc, char *argv[]);
size_t conv_argv_part_num(const char *part_str);
/* Prep files for reading
*/
void open_gbe_file(void);
int fd_verify_regular(int fd,
const struct stat *expected,
struct stat *out);
int fd_verify_identity(int fd,
const struct stat *expected,
struct stat *out);
int fd_verify_dir_identity(int fd,
const struct stat *expected);
int is_owner(struct stat *st);
int lock_file(int fd, int flags);
int same_file(int fd, struct stat *st_old, int check_size);
/* Read GbE file and verify checksums
*/
void copy_gbe(void);
void read_file(void);
void read_checksums(void);
int good_checksum(size_t partnum);
/* validate commands
*/
void check_command_num(size_t c);
unsigned char valid_command(size_t c);
/* Helper functions for command: setmac
*/
void cmd_helper_setmac(void);
void parse_mac_string(void);
void set_mac_byte(size_t mac_byte_pos);
void set_mac_nib(size_t mac_str_pos,
size_t mac_byte_pos, size_t mac_nib_pos);
void write_mac_part(size_t partnum);
/* string functions
*/
size_t page_remain(const void *p);
long pagesize(void);
char *smalloc(char **buf, size_t size);
void *vmalloc(void **buf, size_t size);
size_t slen(const char *scmp, size_t maxlen,
size_t *rval);
int vcmp(const void *s1, const void *s2, size_t n);
int scmp(const char *a, const char *b,
size_t maxlen, int *rval);
int ccmp(const char *a, const char *b, size_t i,
int *rval);
int dup_pair(char **dir, const char *d,
char **base, const char *b);
char *sdup(const char *s,
size_t n, char **dest);
char *scatn(ssize_t sc, const char **sv,
size_t max, char **rval);
char *scat(const char *s1, const char *s2,
size_t n, char **dest);
void dcat(const char *s, size_t n,
size_t off, char **dest1,
char **dest2);
/* numerical functions
*/
unsigned short hextonum(char ch_s);
void spew_hex(const void *data, size_t len);
void *rmalloc(size_t n);
void rset(void *buf, size_t n);
void *rmalloc(size_t n);
char *rchars(size_t n);
size_t rsize(size_t n);
/* Helper functions for command: dump
*/
void cmd_helper_dump(void);
void print_mac_from_nvm(size_t partnum);
/* Helper functions for command: swap
*/
void cmd_helper_swap(void);
/* Helper functions for command: copy
*/
void cmd_helper_copy(void);
/* Helper functions for commands:
* cat, cat16 and cat128
*/
void cmd_helper_cat(void);
void cmd_helper_cat16(void);
void cmd_helper_cat128(void);
void cat(size_t nff);
void cat_buf(unsigned char *b);
/* Command verification/control
*/
void check_cmd(void (*fn)(void), const char *name);
void cmd_helper_err(void);
/* Write GbE files to disk
*/
void write_gbe_file(void);
void set_checksum(size_t part);
unsigned short calculated_checksum(size_t p);
/* NVM read/write
*/
unsigned short nvm_word(size_t pos16, size_t part);
void set_nvm_word(size_t pos16,
size_t part, unsigned short val16);
void set_part_modified(size_t p);
void check_nvm_bound(size_t pos16, size_t part);
void check_bin(size_t a, const char *a_name);
/* GbE file read/write
*/
void rw_gbe_file_part(size_t p, int rw_type,
const char *rw_type_str);
void write_to_gbe_bin(void);
int gbe_mv(void);
void check_written_part(size_t p);
void report_io_err_rw(void);
unsigned char *gbe_mem_offset(size_t part, const char *f_op);
off_t gbe_file_offset(size_t part, const char *f_op);
off_t gbe_x_offset(size_t part, const char *f_op,
const char *d_type, off_t nsize, off_t ncmp);
ssize_t rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
off_t off, int rw_type);
/* Generic read/write
*/
int fsync_dir(const char *path);
ssize_t rw_exact(int fd, unsigned char *mem, size_t len,
off_t off, int rw_type);
ssize_t rw(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
int io_args(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
int check_file(int fd, struct stat *st);
ssize_t rw_over_nrw(ssize_t r, size_t nrw);
int sys_retry(int saved_errno, long rval);
int fs_retry(int saved_errno, int rval);
int rw_retry(int saved_errno, ssize_t rval);
/* Error handling and cleanup
*/
void usage(void);
int with_fallback_errno(int fallback);
void exitf(const char *msg, ...);
func_t errhook(func_t ptr); /* hook function for cleanup on err */
const char *lbgetprogname(void);
void no_op(void);
void err_mkhtemp(int errval, const char *msg, ...);
/* libc hardening
*/
int new_tmpfile(int *fd, char **path, char *tmpdir,
const char *template);
int new_tmpdir(int *fd, char **path, char *tmpdir,
const char *template);
int new_tmp_common(int *fd, char **path, int type,
char *tmpdir, const char *template);
int mkhtemp_try_create(int dirfd,
struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
int *fd,
struct stat *st,
int type);
int
mkhtemp_tmpfile_linux(int dirfd,
struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
int *fd,
struct stat *st);
int mkhtemp(int *fd, struct stat *st,
char *template, int dirfd, const char *fname,
struct stat *st_dir_first, int type);
int world_writeable_and_sticky(const char *s,
int sticky_allowed, int always_sticky);
int same_dir(const char *a, const char *b);
int tmpdir_policy(const char *path,
int *allow_noworld_unsticky);
char *env_tmpdir(int always_sticky, char **tmpdir,
char *override_tmpdir);
int secure_file(int *fd,
struct stat *st,
struct stat *expected,
int bad_flags,
int check_seek,
int do_lock,
mode_t mode);
void xclose(int *fd);
int fsync_on_eintr(int fd);
int fs_rename_at(int olddirfd, const char *old,
int newdirfd, const char *new);
int fs_open(const char *path, int flags);
void free_and_set_null(char **buf);
void open_file_on_eintr(const char *path, int *fd, int flags, mode_t mode,
struct stat *st);
struct filesystem *rootfs(void);
int fs_resolve_at(int dirfd, const char *path, int flags);
int fs_next_component(const char **p,
char *name, size_t namesz);
int fs_open_component(int dirfd, const char *name,
int flags, int is_last);
int fs_dirname_basename(const char *path,
char **dir, char **base, int allow_relative);
int openat_on_eintr(int dirfd, const char *path,
int flags, mode_t mode);
int mkdirat_on_eintr(int dirfd,
const char *pathname, mode_t mode);
int if_err(int condition, int errval);
int if_err_sys(int condition);
char *lbsetprogname(char *argv0);
/* asserts */
/* type asserts */
typedef char static_assert_char_is_8_bits[(CHAR_BIT == 8) ? 1 : -1];
typedef char static_assert_char_is_1[(sizeof(char) == 1) ? 1 : -1];
typedef char static_assert_unsigned_char_is_1[
(sizeof(unsigned char) == 1) ? 1 : -1];
typedef char static_assert_unsigned_short_is_2[
(sizeof(unsigned short) >= 2) ? 1 : -1];
typedef char static_assert_short_is_2[(sizeof(short) >= 2) ? 1 : -1];
typedef char static_assert_unsigned_int_is_4[
(sizeof(unsigned int) >= 4) ? 1 : -1];
typedef char static_assert_unsigned_ssize_t_is_4[
(sizeof(size_t) >= 4) ? 1 : -1];
typedef char static_assert_ssize_t_ussize_t[
(sizeof(size_t) == sizeof(ssize_t)) ? 1 : -1];
typedef char static_assert_int_ge_32[(sizeof(int) >= 4) ? 1 : -1];
typedef char static_assert_twos_complement[
((-1 & 3) == 3) ? 1 : -1
];
typedef char assert_unsigned_ssize_t_ptr[
(sizeof(size_t) >= sizeof(void *)) ? 1 : -1
];
/*
* We set _FILE_OFFSET_BITS 64, but we only handle
* but we only need smaller files, so require 4-bytes.
* Some operating systems ignore the define, hence assert:
*/
typedef char static_assert_off_t_is_32[(sizeof(off_t) >= 4) ? 1 : -1];
/*
* asserts (variables/defines sanity check)
*/
typedef char assert_argc3[(ARGC_3==3)?1:-1];
typedef char assert_argc4[(ARGC_4==4)?1:-1];
typedef char assert_read[(IO_READ==0)?1:-1];
typedef char assert_write[(IO_WRITE==1)?1:-1];
typedef char assert_pread[(IO_PREAD==2)?1:-1];
typedef char assert_pwrite[(IO_PWRITE==3)?1:-1];
typedef char assert_pathlen[(PATH_MAX>=1024)?1:-1];
/* commands */
typedef char assert_cmd_dump[(CMD_DUMP==0)?1:-1];
typedef char assert_cmd_setmac[(CMD_SETMAC==1)?1:-1];
typedef char assert_cmd_swap[(CMD_SWAP==2)?1:-1];
typedef char assert_cmd_copy[(CMD_COPY==3)?1:-1];
typedef char assert_cmd_cat[(CMD_CAT==4)?1:-1];
typedef char assert_cmd_cat16[(CMD_CAT16==5)?1:-1];
typedef char assert_cmd_cat128[(CMD_CAT128==6)?1:-1];
/* bool */
typedef char bool_arg_nopart[(ARG_NOPART==0)?1:-1];
typedef char bool_arg_part[(ARG_PART==1)?1:-1];
typedef char bool_skip_checksum_read[(SKIP_CHECKSUM_READ==0)?1:-1];
typedef char bool_checksum_read[(CHECKSUM_READ==1)?1:-1];
typedef char bool_skip_checksum_write[(SKIP_CHECKSUM_WRITE==0)?1:-1];
typedef char bool_checksum_write[(CHECKSUM_WRITE==1)?1:-1];
#endif
#endif
-108
View File
@@ -1,108 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
*
* Functions related to GbE NVM checksums.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include "../include/common.h"
void
read_checksums(void)
{
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
size_t _p;
size_t _skip_part;
unsigned char _num_invalid;
unsigned char _max_invalid;
f->part_valid[0] = 0;
f->part_valid[1] = 0;
if (!cmd->chksum_read)
return;
_num_invalid = 0;
_max_invalid = 2;
if (cmd->arg_part)
_max_invalid = 1;
/* Skip verification on this part,
* but only when arg_part is set.
*/
_skip_part = f->part ^ 1;
for (_p = 0; _p < 2; _p++) {
/* Only verify a part if it was *read*
*/
if (cmd->arg_part && (_p == _skip_part))
continue;
f->part_valid[_p] = good_checksum(_p);
if (!f->part_valid[_p])
++_num_invalid;
}
if (_num_invalid >= _max_invalid) {
if (_max_invalid == 1)
exitf("%s: part %lu has a bad checksum",
f->fname, (size_t)f->part);
exitf("%s: No valid checksum found in file",
f->fname);
}
}
int
good_checksum(size_t partnum)
{
unsigned short expected_checksum;
unsigned short actual_checksum;
expected_checksum =
calculated_checksum(partnum);
actual_checksum =
nvm_word(NVM_CHECKSUM_WORD, partnum);
if (expected_checksum == actual_checksum) {
return 1;
} else {
return 0;
}
}
void
set_checksum(size_t p)
{
check_bin(p, "part number");
set_nvm_word(NVM_CHECKSUM_WORD, p, calculated_checksum(p));
}
unsigned short
calculated_checksum(size_t p)
{
size_t c;
unsigned int val16;
val16 = 0;
for (c = 0; c < NVM_CHECKSUM_WORD; c++)
val16 += (unsigned int)nvm_word(c, p);
return (unsigned short)((NVM_CHECKSUM - val16) & 0xffff);
}
-521
View File
@@ -1,521 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include "../include/common.h"
void
sanitize_command_list(void)
{
struct xstate *x = xstatus();
size_t c;
size_t num_commands;
num_commands = items(x->cmd);
for (c = 0; c < num_commands; c++)
sanitize_command_index(c);
}
void
sanitize_command_index(size_t c)
{
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[c];
int _flag;
size_t gbe_rw_size;
size_t rval;
check_command_num(c);
if (cmd->argc < 3)
exitf("cmd index %lu: argc below 3, %d",
(size_t)c, cmd->argc);
if (cmd->str == NULL)
exitf("cmd index %lu: NULL str",
(size_t)c);
if (*cmd->str == '\0')
exitf("cmd index %lu: empty str",
(size_t)c);
if (slen(cmd->str, MAX_CMD_LEN +1, &rval) > MAX_CMD_LEN) {
exitf("cmd index %lu: str too long: %s",
(size_t)c, cmd->str);
}
if (cmd->run == NULL)
exitf("cmd index %lu: cmd ptr null",
(size_t)c);
check_bin(cmd->arg_part, "cmd.arg_part");
check_bin(cmd->chksum_read, "cmd.chksum_read");
check_bin(cmd->chksum_write, "cmd.chksum_write");
gbe_rw_size = cmd->rw_size;
switch (gbe_rw_size) {
case GBE_PART_SIZE:
case NVM_SIZE:
break;
default:
exitf("Unsupported rw_size: %lu",
(size_t)gbe_rw_size);
}
if (gbe_rw_size > GBE_PART_SIZE)
exitf("rw_size larger than GbE part: %lu",
(size_t)gbe_rw_size);
_flag = (cmd->flags & O_ACCMODE);
if (_flag != O_RDONLY &&
_flag != O_RDWR)
exitf("invalid cmd.flags setting");
}
void
set_cmd(int argc, char *argv[])
{
struct xstate *x = xstatus();
const char *cmd;
int rval;
size_t c;
for (c = 0; c < items(x->cmd); c++) {
cmd = x->cmd[c].str;
if (scmp(argv[2], cmd, MAX_CMD_LEN, &rval))
continue; /* not the right command */
/* valid command found */
if (argc >= x->cmd[c].argc) {
x->no_cmd = 0;
x->i = c; /* set command */
return;
}
exitf(
"Too few args on command '%s'", cmd);
}
x->no_cmd = 1;
}
void
set_cmd_args(int argc, char *argv[])
{
struct xstate *x = xstatus();
size_t i = x->i;
struct commands *cmd = &x->cmd[i];
struct xfile *f = &x->f;
if (!valid_command(i) || argc < 3)
usage();
if (x->no_cmd)
usage();
/* Maintainer bug
*/
if (cmd->arg_part && argc < 4)
exitf(
"arg_part set for command that needs argc4");
if (cmd->arg_part && i == CMD_SETMAC)
exitf(
"arg_part set on CMD_SETMAC");
if (i == CMD_SETMAC) {
if (argc >= 4)
x->mac.str = argv[3];
else
x->mac.str = x->mac.rmac;
} else if (cmd->arg_part) {
f->part = conv_argv_part_num(argv[3]);
}
}
size_t
conv_argv_part_num(const char *part_str)
{
unsigned char ch;
if (part_str[0] == '\0' || part_str[1] != '\0')
exitf("Partnum string '%s' wrong length", part_str);
/* char signedness is implementation-defined
*/
ch = (unsigned char)part_str[0];
if (ch < '0' || ch > '1')
exitf("Bad part number (%c)", ch);
return (size_t)(ch - '0');
}
void
check_command_num(size_t c)
{
if (!valid_command(c))
exitf("Invalid run_cmd arg: %lu",
(size_t)c);
}
unsigned char
valid_command(size_t c)
{
struct xstate *x = xstatus();
struct commands *cmd;
if (c >= items(x->cmd))
return 0;
cmd = &x->cmd[c];
if (c != cmd->chk)
exitf(
"Invalid cmd chk value (%lu) vs arg: %lu",
cmd->chk, c);
return 1;
}
void
cmd_helper_setmac(void)
{
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
size_t partnum;
check_cmd(cmd_helper_setmac, "setmac");
printf("MAC address to be written: %s\n", mac->str);
parse_mac_string();
for (partnum = 0; partnum < 2; partnum++)
write_mac_part(partnum);
}
void
parse_mac_string(void)
{
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
size_t mac_byte;
size_t rval;
if (slen(x->mac.str, 18, &rval) != 17)
exitf("MAC address is the wrong length");
memset(mac->mac_buf, 0, sizeof(mac->mac_buf));
for (mac_byte = 0; mac_byte < 6; mac_byte++)
set_mac_byte(mac_byte);
if ((mac->mac_buf[0] | mac->mac_buf[1] | mac->mac_buf[2]) == 0)
exitf("Must not specify all-zeroes MAC address");
if (mac->mac_buf[0] & 1)
exitf("Must not specify multicast MAC address");
}
void
set_mac_byte(size_t mac_byte_pos)
{
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
char separator;
size_t mac_str_pos;
size_t mac_nib_pos;
mac_str_pos = mac_byte_pos * 3;
if (mac_str_pos < 15) {
if ((separator = mac->str[mac_str_pos + 2]) != ':')
exitf("Invalid MAC address separator '%c'",
separator);
}
for (mac_nib_pos = 0; mac_nib_pos < 2; mac_nib_pos++)
set_mac_nib(mac_str_pos, mac_byte_pos, mac_nib_pos);
}
void
set_mac_nib(size_t mac_str_pos,
size_t mac_byte_pos, size_t mac_nib_pos)
{
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
char mac_ch;
unsigned short hex_num;
mac_ch = mac->str[mac_str_pos + mac_nib_pos];
if ((hex_num = hextonum(mac_ch)) > 15) {
if (hex_num >= 17)
exitf("Randomisation failure");
else
exitf("Invalid character '%c'",
mac->str[mac_str_pos + mac_nib_pos]);
}
/* If random, ensure that local/unicast bits are set.
*/
if ((mac_byte_pos == 0) && (mac_nib_pos == 1) &&
((mac_ch | 0x20) == 'x' ||
(mac_ch == '?')))
hex_num = (hex_num & 0xE) | 2; /* local, unicast */
/* MAC words stored big endian in-file, little-endian
* logically, so we reverse the order.
*/
mac->mac_buf[mac_byte_pos >> 1] |= hex_num <<
(((mac_byte_pos & 1) << 3) /* left or right byte? */
| ((mac_nib_pos ^ 1) << 2)); /* left or right nib? */
}
void
write_mac_part(size_t partnum)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
struct macaddr *mac = &x->mac;
size_t w;
check_bin(partnum, "part number");
if (!f->part_valid[partnum])
return;
for (w = 0; w < 3; w++)
set_nvm_word(w, partnum, mac->mac_buf[w]);
printf("Wrote MAC address to part %lu: ",
(size_t)partnum);
print_mac_from_nvm(partnum);
}
void
cmd_helper_dump(void)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
size_t p;
check_cmd(cmd_helper_dump, "dump");
f->part_valid[0] = good_checksum(0);
f->part_valid[1] = good_checksum(1);
for (p = 0; p < 2; p++) {
if (!f->part_valid[p]) {
fprintf(stderr,
"BAD checksum %04x in part %lu (expected %04x)\n",
nvm_word(NVM_CHECKSUM_WORD, p),
(size_t)p,
calculated_checksum(p));
}
printf("MAC (part %lu): ",
(size_t)p);
print_mac_from_nvm(p);
spew_hex(f->buf + (p * GBE_PART_SIZE), NVM_SIZE);
}
}
void
print_mac_from_nvm(size_t partnum)
{
size_t c;
unsigned short val16;
for (c = 0; c < 3; c++) {
val16 = nvm_word(c, partnum);
printf("%02x:%02x",
(unsigned int)(val16 & 0xff),
(unsigned int)(val16 >> 8));
if (c == 2)
printf("\n");
else
printf(":");
}
}
void
cmd_helper_swap(void)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
check_cmd(cmd_helper_swap, "swap");
memcpy(
f->buf + (size_t)GBE_WORK_SIZE,
f->buf,
GBE_PART_SIZE);
memcpy(
f->buf,
f->buf + (size_t)GBE_PART_SIZE,
GBE_PART_SIZE);
memcpy(
f->buf + (size_t)GBE_PART_SIZE,
f->buf + (size_t)GBE_WORK_SIZE,
GBE_PART_SIZE);
set_part_modified(0);
set_part_modified(1);
}
void
cmd_helper_copy(void)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
check_cmd(cmd_helper_copy, "copy");
memcpy(
f->buf + (size_t)((f->part ^ 1) * GBE_PART_SIZE),
f->buf + (size_t)(f->part * GBE_PART_SIZE),
GBE_PART_SIZE);
set_part_modified(f->part ^ 1);
}
void
cmd_helper_cat(void)
{
struct xstate *x = xstatus();
check_cmd(cmd_helper_cat, "cat");
x->cat = 0;
cat(0);
}
void
cmd_helper_cat16(void)
{
struct xstate *x = xstatus();
check_cmd(cmd_helper_cat16, "cat16");
x->cat = 1;
cat(1);
}
void
cmd_helper_cat128(void)
{
struct xstate *x = xstatus();
check_cmd(cmd_helper_cat128, "cat128");
x->cat = 15;
cat(15);
}
void
cat(size_t nff)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
size_t p;
size_t ff;
p = 0;
ff = 0;
if ((size_t)x->cat != nff) {
exitf("erroneous call to cat");
}
fflush(NULL);
memset(f->pad, 0xff, GBE_PART_SIZE);
for (p = 0; p < 2; p++) {
cat_buf(f->bufcmp +
(size_t)(p * (f->gbe_file_size >> 1)));
for (ff = 0; ff < nff; ff++) {
cat_buf(f->pad);
}
}
}
void
cat_buf(unsigned char *b)
{
if (b == NULL)
exitf("null pointer in cat command");
if (rw_exact(STDOUT_FILENO, b,
GBE_PART_SIZE, 0, IO_WRITE) < 0)
exitf("stdout: cat");
}
void
check_cmd(void (*fn)(void),
const char *name)
{
struct xstate *x = xstatus();
size_t i = x->i;
if (x->cmd[i].run != fn)
exitf("Running %s, but cmd %s is set",
name, x->cmd[i].str);
/* prevent second command
*/
for (i = 0; i < items(x->cmd); i++)
x->cmd[i].run = cmd_helper_err;
}
void
cmd_helper_err(void)
{
exitf(
"Erroneously running command twice");
}
-817
View File
@@ -1,817 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*
* Pathless i/o, and some stuff you
* probably never saw in userspace.
*
* Be nice to the demon.
*/
/*
TODO: putting it here just so it's somewhere:
PATH_MAX is not reliable as a limit for paths,
because the real length depends on mount point,
and specific file systems.
more correct usage example:
long max = pathconf("/", _PC_PATH_MAX);
*/
/* for openat2: */
#ifdef __linux__
#if !defined(USE_OPENAT) || \
((USE_OPENAT) < 1) /* if 1: use openat, not openat2 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <linux/openat2.h>
#include <sys/syscall.h>
#endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../include/common.h"
/* check that a file changed
*/
int
same_file(int fd, struct stat *st_old,
int check_size)
{
struct stat st;
int saved_errno = errno;
int rval = 0;
errno = 0;
if (if_err(st_old == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
(rval = fstat(fd, &st)) < 0 ||
(rval = fd_verify_regular(fd, st_old, &st)) < 0 ||
if_err(check_size && st.st_size != st_old->st_size, ESTALE))
return with_fallback_errno(ESTALE);
reset_caller_errno(rval);
return 0;
}
int
fsync_dir(const char *path)
{
int saved_errno = errno;
size_t pathlen = 0;
char *dirbuf = NULL;
int dirfd = -1;
char *slash = NULL;
struct stat st = {0};
int rval = 0;
errno = 0;
if (if_err(slen(path, PATH_MAX, &pathlen) == 0, EINVAL))
goto err_fsync_dir;
memcpy(smalloc(&dirbuf, pathlen + 1),
path, pathlen + 1);
slash = strrchr(dirbuf, '/');
if (slash != NULL) {
*slash = '\0';
if (*dirbuf == '\0') {
dirbuf[0] = '/';
dirbuf[1] = '\0';
}
} else {
dirbuf[0] = '.';
dirbuf[1] = '\0';
}
dirfd = fs_open(dirbuf,
O_RDONLY | O_CLOEXEC | O_NOCTTY
#ifdef O_DIRECTORY
| O_DIRECTORY
#endif
#ifdef O_NOFOLLOW
| O_NOFOLLOW
#endif
);
if (if_err_sys(dirfd < 0) ||
if_err_sys((rval = fstat(dirfd, &st)) < 0) ||
if_err(!S_ISDIR(st.st_mode), ENOTDIR)
||
if_err_sys((rval = fsync_on_eintr(dirfd)) == -1))
goto err_fsync_dir;
xclose(&dirfd);
free_and_set_null(&dirbuf);
reset_caller_errno(rval);
return 0;
err_fsync_dir:
free_and_set_null(&dirbuf);
xclose(&dirfd);
return with_fallback_errno(EIO);
}
/* rw_exact() - Read perfectly or die
*
* Read/write, and absolutely insist on an
* absolute read; e.g. if 100 bytes are
* requested, this MUST return 100.
*
* This function will never return zero.
* It will only return below (error),
* or above (success). On error, -1 is
* returned and errno is set accordingly.
*
* Zero-byte returns are not allowed.
* It will re-spin a finite number of
* times upon zero-return, to recover,
* otherwise it will return an error.
*/
ssize_t
rw_exact(int fd, unsigned char *mem, size_t nrw,
off_t off, int rw_type)
{
int saved_errno = errno;
ssize_t rval = 0;
ssize_t rc = 0;
size_t nrw_cur;
off_t off_cur;
void *mem_cur;
errno = 0;
if (io_args(fd, mem, nrw, off, rw_type) == -1)
goto err_rw_exact;
while (1) {
/* Prevent theoretical overflow */
if (if_err(rval >= 0 && (size_t)rval > (nrw - (size_t)rc),
EOVERFLOW))
goto err_rw_exact;
rc += rval;
if ((size_t)rc >= nrw)
break;
mem_cur = (void *)(mem + (size_t)rc);
nrw_cur = (size_t)(nrw - (size_t)rc);
if (if_err(off < 0, EOVERFLOW))
goto err_rw_exact;
off_cur = off + (off_t)rc;
if ((rval = rw(fd, mem_cur, nrw_cur, off_cur, rw_type)) <= 0)
goto err_rw_exact;
}
if (if_err((size_t)rc != nrw, EIO) ||
(rval = rw_over_nrw(rc, nrw)) < 0)
goto err_rw_exact;
reset_caller_errno(rval);
return rval;
err_rw_exact:
return with_fallback_errno(EIO);
}
/**
* rw() - read-write but with more
* safety checks than barebones libc
*
* A fallback is provided for regular read/write.
* rw_type can be IO_READ (read), IO_WRITE (write),
* IO_PREAD (pread) or IO_PWRITE
*
* WARNING: this function allows zero-byte returns.
* this is intentional, to mimic libc behaviour.
* use rw_exact if you need to avoid this.
* (ditto partial writes/reads)
*
*/
ssize_t
rw(int fd, void *mem, size_t nrw,
off_t off, int rw_type)
{
ssize_t rval = 0;
ssize_t r = -1;
int saved_errno = errno;
errno = 0;
if (io_args(fd, mem, nrw, off, rw_type) == -1 ||
if_err(mem == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(off < 0, EFAULT) ||
if_err(nrw == 0, EINVAL))
return with_fallback_errno(EIO);
do {
switch (rw_type) {
case IO_READ:
r = read(fd, mem, nrw);
break;
case IO_WRITE:
r = write(fd, mem, nrw);
break;
case IO_PREAD:
r = pread(fd, mem, nrw, off);
break;
case IO_PWRITE:
r = pwrite(fd, mem, nrw, off);
break;
default:
errno = EINVAL;
break;
}
} while (rw_retry(saved_errno, r));
if ((rval = rw_over_nrw(r, nrw)) < 0)
return with_fallback_errno(EIO);
reset_caller_errno(rval);
return rval;
}
int
io_args(int fd, void *mem, size_t nrw,
off_t off, int rw_type)
{
int saved_errno = errno;
errno = 0;
if (if_err(mem == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(off < 0, ERANGE) ||
if_err(!nrw, EPERM) || /* TODO: toggle zero-byte check */
if_err(nrw > (size_t)SSIZE_MAX, ERANGE) ||
if_err(((size_t)off + nrw) < (size_t)off, ERANGE) ||
if_err(rw_type > IO_PWRITE, EINVAL))
goto err_io_args;
reset_caller_errno(0);
return 0;
err_io_args:
return with_fallback_errno(EINVAL);
}
int
check_file(int fd, struct stat *st)
{
int saved_errno = errno;
int rval = 0;
errno = 0;
if (if_err(fd < 0, EBADF) ||
if_err(st == NULL, EFAULT) ||
((rval = fstat(fd, st)) == -1) ||
if_err(!S_ISREG(st->st_mode), EBADF))
goto err_is_file;
reset_caller_errno(rval);
return 0;
err_is_file:
return with_fallback_errno(EINVAL);
}
/* POSIX can say whatever it wants.
* specification != implementation
*/
ssize_t
rw_over_nrw(ssize_t r, size_t nrw)
{
if (if_err(!nrw, EIO) ||
(r == -1) ||
if_err((size_t)r > SSIZE_MAX, ERANGE) ||
if_err((size_t)r > nrw, ERANGE))
return with_fallback_errno(EIO);
return r;
}
/* two functions that reduce sloccount by
* two hundred lines */
int
if_err(int condition, int errval)
{
if (!condition)
return 0;
if (errval)
errno = errval;
return 1;
}
int
if_err_sys(int condition)
{
if (!condition)
return 0;
return 1;
}
int
fs_rename_at(int olddirfd, const char *old,
int newdirfd, const char *new)
{
if (if_err(new == NULL || old == NULL, EFAULT) ||
if_err(olddirfd < 0 || newdirfd < 0, EBADF))
return -1;
return renameat(olddirfd, old, newdirfd, new);
}
/* secure open, based on relative path to root
*
* always a fixed fd for / see: rootfs()
* and fs_resolve_at()
*/
int
fs_open(const char *path, int flags)
{
struct filesystem *fs;
if (if_err(path == NULL, EFAULT) ||
if_err(path[0] != '/', EINVAL) ||
if_err_sys((fs = rootfs()) == NULL))
return -1;
return fs_resolve_at(fs->rootfd, path + 1, flags);
}
/* singleton function that returns a fixed descriptor of /
* used throughout, for repeated integrity checks
*/
struct filesystem *
rootfs(void)
{
static struct filesystem global_fs;
static int fs_initialised = 0;
if (!fs_initialised) {
global_fs.rootfd = -1;
open_file_on_eintr("/", &global_fs.rootfd,
O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0400, NULL);
if (global_fs.rootfd < 0)
return NULL;
fs_initialised = 1;
}
return &global_fs;
}
/* filesystem sandboxing in userspace
* TODO:
missing length bound check.
potential CPU DoS on very long paths, spammed repeatedly.
perhaps cap at MAX_PATH?
*/
int
fs_resolve_at(int dirfd, const char *path, int flags)
{
int nextfd = -1;
int curfd;
const char *p;
char name[PATH_MAX];
int saved_errno = errno;
int r;
int is_last;
errno = 0;
if (dirfd < 0 || path == NULL || *path == '\0') {
errno = EINVAL;
return -1;
}
p = path;
curfd = dirfd; /* start here */
for (;;) {
r = fs_next_component(&p, name, sizeof(name));
if (r < 0)
goto err;
if (r == 0)
break;
is_last = (*p == '\0');
nextfd = fs_open_component(curfd, name, flags, is_last);
if (nextfd < 0)
goto err;
/* close previous fd if not the original input */
if (curfd != dirfd)
xclose(&curfd);
curfd = nextfd;
nextfd = -1;
}
reset_caller_errno(0);
return curfd;
err:
saved_errno = errno;
if (nextfd >= 0)
xclose(&nextfd);
/* close curfd only if it's not the original */
if (curfd != dirfd && curfd >= 0)
xclose(&curfd);
errno = saved_errno;
return with_fallback_errno(EIO);
}
/* NOTE:
rejects . and .. but not empty strings
after normalisation. edge case:
//////
normalised implicitly, but might be good
to add a defensive check regardless. code
probably not exploitable in current state.
*/
int
fs_next_component(const char **p,
char *name, size_t namesz)
{
const char *s = *p;
size_t len = 0;
while (*s == '/')
s++;
if (*s == '\0') {
*p = s;
return 0;
}
while (s[len] != '/' && s[len] != '\0')
len++;
if (len == 0 || len >= namesz ||
len >= PATH_MAX) {
errno = ENAMETOOLONG;
return -1;
}
memcpy(name, s, len);
name[len] = '\0';
/* reject . and .. */
if (if_err((name[0] == '.' && name[1] == '\0') ||
(name[0] == '.' && name[1] == '.' && name[2] == '\0'), EPERM))
goto err;
*p = s + len;
return 1;
err:
return with_fallback_errno(EPERM);
}
int
fs_open_component(int dirfd, const char *name,
int flags, int is_last)
{
int saved_errno = errno;
int fd;
struct stat st;
errno = 0;
fd = openat_on_eintr(dirfd, name,
(is_last ? flags : (O_RDONLY | O_DIRECTORY)) |
O_NOFOLLOW | O_CLOEXEC, (flags & O_CREAT) ? 0600 : 0);
if (!is_last &&
(if_err(fd < 0, EBADF) ||
if_err_sys(fstat(fd, &st) < 0) ||
if_err(!S_ISDIR(st.st_mode), ENOTDIR)))
return with_fallback_errno(EIO);
reset_caller_errno(fd);
return fd;
}
int
fs_dirname_basename(const char *path,
char **dir, char **base,
int allow_relative)
{
int saved_errno = errno;
char *buf = NULL;
char *slash;
size_t len;
const char *d = NULL;
const char *b = NULL;
errno = 0;
if (if_err(path == NULL || dir == NULL || base == NULL, EFAULT))
goto err;
slen(path, PATH_MAX, &len);
memcpy(smalloc(&buf, len + 1),
path, len + 1);
/* strip trailing slashes */
while (len > 1 && buf[len - 1] == '/')
buf[--len] = '\0';
slash = strrchr(buf, '/');
if (slash) {
*slash = '\0';
d = buf;
b = slash + 1;
if (*d == '\0')
d = "/";
} else if (allow_relative) {
d = ".";
b = buf;
} else {
free_and_set_null(&buf);
goto err;
}
if (dup_pair(dir, d, base, b) < 0) {
free_and_set_null(&buf);
goto err;
}
free_and_set_null(&buf);
reset_caller_errno(0);
return 0;
err:
return with_fallback_errno(EINVAL);
}
/* TODO: why does this abort, but others
e.g. open_file_on_eintr, don't???
*/
void
open_file_on_eintr(const char *path,
int *fd, int flags, mode_t mode,
struct stat *st)
{
int saved_errno = errno;
int rval = 0;
errno = 0;
if (path == NULL)
exitf("open_file_on_eintr: null path");
if (fd == NULL)
exitf("%s: open_file_on_eintr: null fd ptr", path);
if (*fd >= 0)
exitf(
"%s: open_file_on_eintr: file already open", path);
errno = 0;
while (fs_retry(saved_errno,
rval = open(path, flags, mode)));
if (rval < 0)
exitf(
"%s: open_file_on_eintr: could not close", path);
reset_caller_errno(rval);
*fd = rval;
/* we don't care about edge case behaviour here,
even if the next operation sets errno on success,
because the open() call is our main concern.
however, we also must preserve the new errno,
assuming it changed above under the same edge case */
saved_errno = errno;
if (st != NULL) {
if (fstat(*fd, st) < 0)
exitf("%s: stat", path);
if (!S_ISREG(st->st_mode))
exitf("%s: not a regular file", path);
}
if (lseek(*fd, 0, SEEK_CUR) == (off_t)-1)
exitf("%s: file not seekable", path);
errno = saved_errno; /* see previous comment */
}
#if defined(__linux__) && \
(!defined(USE_OPENAT) || ((USE_OPENAT) < 1)) /* we use openat2 on linux */
int
openat_on_eintr(int dirfd, const char *path,
int flags, mode_t mode)
{
struct open_how how = {
.flags = (unsigned long long)flags,
.mode = mode,
.resolve =
RESOLVE_BENEATH |
RESOLVE_NO_SYMLINKS |
RESOLVE_NO_MAGICLINKS
};
int saved_errno = errno;
long rval = 0;
errno = 0;
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
goto err;
errno = 0;
while (sys_retry(saved_errno,
rval = syscall(SYS_openat2, dirfd, path, &how, sizeof(how))));
if (rval == -1) /* avoid long->int UB for -1 */
goto err;
reset_caller_errno(rval);
return (int)rval;
err:
return with_fallback_errno(EIO); /* -1 */
}
#else /* regular openat on non-linux e.g. openbsd */
int
openat_on_eintr(int dirfd, const char *path,
int flags, mode_t mode)
{
int saved_errno = errno;
int rval = 0;
errno = 0;
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
return with_fallback_errno(EIO);
while (fs_retry(saved_errno,
rval = openat(dirfd, path, flags, mode)));
reset_caller_errno(rval);
return rval;
}
#endif
int
mkdirat_on_eintr(int dirfd,
const char *path, mode_t mode)
{
int saved_errno = errno;
int rval = 0;
errno = 0;
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
return with_fallback_errno(EIO);
while (fs_retry(saved_errno,
rval = mkdirat(dirfd, path, mode)));
reset_caller_errno(rval);
return rval;
}
int
fsync_on_eintr(int fd)
{
int saved_errno = errno;
int rval = 0;
errno = 0;
if (if_err(fd < 0, EBADF))
return with_fallback_errno(EIO);
while (fs_retry(saved_errno,
rval = fsync(fd)));
reset_caller_errno(rval);
return rval;
}
void
xclose(int *fd)
{
int saved_errno = errno;
int rval = 0;
if (fd == NULL)
exitf("xclose: null pointer");
if (*fd < 0)
return;
/* nuance regarding EINTR on close():
* EINTR can be set on error, but there's
* no guarantee whether the fd is then still
* open or closed. on some other commands, we
* loop EINTR, but for close, we instead skip
* aborting *if the errno is EINTR* - so don't
* loop it, but do regard EINTR with rval -1
* as essenitally a successful close()
*/
/* because we don't want to mess with someone
* elses file if that fd is then reassigned.
* if the operation truly did fail, we ignore
* it. just leave it flying in the wind */
errno = 0;
if ((rval = close(*fd)) < 0) {
if (errno != EINTR)
exitf("xclose: could not close");
/* regard EINTR as a successful close */
rval = 0;
}
*fd = -1;
reset_caller_errno(rval);
}
/* unified eintr looping.
* differently typed functions
* to avoid potential UB
*
* ONE MACRO TO RULE THEM ALL:
*/
#define fs_err_retry() \
do { \
if ((rval == -1) && \
(errno == EINTR)) \
return 1; \
if (rval >= 0 && !errno) \
errno = saved_errno; \
return 0; \
} while(0)
/*
* Regarding the errno logic above:
* on success, it is permitted that
* a syscall could still set errno.
* We reset errno after storingit
* for later preservation, in functions
* that call *_retry() functions.
*
* They rely ultimately on this
* macro for errno restoration. We
* assume therefore that errno was
* reset to zero before the retry
* loop. If errno is then *set* on
* success, we leave it alone. Otherwise,
* we restore the caller's saved errno.
*
* This offers some consistency, while
* complying with POSIX specification.
*/
/* retry switch for functions that
return long status e.g. linux syscall
*/
int
sys_retry(int saved_errno, long rval)
{
fs_err_retry();
}
/* retry switch for functions that
return int status e.g. mkdirat
*/
int
fs_retry(int saved_errno, int rval)
{
fs_err_retry();
}
/* retry switch for functions that
return rw count in ssize_t e.g. read()
*/
int
rw_retry(int saved_errno, ssize_t rval)
{
fs_err_retry();
}
-563
View File
@@ -1,563 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*
* I/O functions specific to nvmutil.
*/
/* TODO: local tmpfiles not being deleted
when flags==O_RDONLY e.g. dump command
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../include/common.h"
void
open_gbe_file(void)
{
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
int saved_errno = errno;
errno = 0;
int _flags;
f->gbe_fd = -1;
open_file_on_eintr(f->fname, &f->gbe_fd,
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY,
((cmd->flags & O_ACCMODE) == O_RDONLY) ? 0400 : 0600,
&f->gbe_st);
if (f->gbe_st.st_nlink > 1)
exitf(
"%s: warning: file has multiple (%lu) hard links\n",
f->fname, (size_t)f->gbe_st.st_nlink);
if (f->gbe_st.st_nlink == 0)
exitf("%s: file unlinked while open", f->fname);
if ((_flags = fcntl(f->gbe_fd, F_GETFL)) == -1)
exitf("%s: fcntl(F_GETFL)", f->fname);
/* O_APPEND allows POSIX write() to ignore
* the current write offset and write at EOF,
* which would break positional read/write
*/
if (_flags & O_APPEND)
exitf("%s: O_APPEND flag", f->fname);
f->gbe_file_size = f->gbe_st.st_size;
switch (f->gbe_file_size) {
case SIZE_8KB:
case SIZE_16KB:
case SIZE_128KB:
break;
default:
exitf("File size must be 8KB, 16KB or 128KB");
}
/* currently fails (EBADF), locks are advisory anyway: */
/*
if (lock_file(f->gbe_fd, cmd->flags) == -1)
exitf("%s: can't lock", f->fname);
*/
reset_caller_errno(0);
}
void
copy_gbe(void)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
read_file();
if (f->gbe_file_size == SIZE_8KB)
return;
memcpy(f->buf + (size_t)GBE_PART_SIZE,
f->buf + (size_t)(f->gbe_file_size >> 1),
(size_t)GBE_PART_SIZE);
}
void
read_file(void)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
struct stat _st;
ssize_t _r;
/* read main file
*/
_r = rw_exact(f->gbe_fd, f->buf, f->gbe_file_size,
0, IO_PREAD);
if (_r < 0)
exitf("%s: read failed", f->fname);
/* copy to tmpfile
*/
_r = rw_exact(f->tmp_fd, f->buf, f->gbe_file_size,
0, IO_PWRITE);
if (_r < 0)
exitf("%s: %s: copy failed",
f->fname, f->tname);
/* file size comparison
*/
if (fstat(f->tmp_fd, &_st) == -1)
exitf("%s: stat", f->tname);
f->gbe_tmp_size = _st.st_size;
if (f->gbe_tmp_size != f->gbe_file_size)
exitf("%s: %s: not the same size",
f->fname, f->tname);
/* needs sync, for verification
*/
if (fsync_on_eintr(f->tmp_fd) == -1)
exitf("%s: fsync (tmpfile copy)", f->tname);
_r = rw_exact(f->tmp_fd, f->bufcmp, f->gbe_file_size,
0, IO_PREAD);
if (_r < 0)
exitf("%s: read failed (cmp)", f->tname);
if (vcmp(f->buf, f->bufcmp, f->gbe_file_size) != 0)
exitf("%s: %s: read contents differ (pre-test)",
f->fname, f->tname);
}
void
write_gbe_file(void)
{
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
size_t p;
unsigned char update_checksum;
if ((cmd->flags & O_ACCMODE) == O_RDONLY)
return;
if (same_file(f->tmp_fd, &f->tmp_st, 0) < 0)
exitf("%s: file inode/device changed", f->tname);
if (same_file(f->gbe_fd, &f->gbe_st, 1) < 0)
exitf("%s: file has changed", f->fname);
update_checksum = cmd->chksum_write;
for (p = 0; p < 2; p++) {
if (!f->part_modified[p])
continue;
if (update_checksum)
set_checksum(p);
rw_gbe_file_part(p, IO_PWRITE, "pwrite");
}
}
void
rw_gbe_file_part(size_t p, int rw_type,
const char *rw_type_str)
{
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
ssize_t rval;
off_t file_offset;
size_t gbe_rw_size;
unsigned char *mem_offset;
gbe_rw_size = cmd->rw_size;
if (rw_type < IO_PREAD || rw_type > IO_PWRITE)
exitf("%s: %s: part %lu: invalid rw_type, %d",
f->fname, rw_type_str, (size_t)p, rw_type);
mem_offset = gbe_mem_offset(p, rw_type_str);
file_offset = (off_t)gbe_file_offset(p, rw_type_str);
rval = rw_gbe_file_exact(f->tmp_fd, mem_offset,
gbe_rw_size, file_offset, rw_type);
if (rval == -1)
exitf("%s: %s: part %lu",
f->fname, rw_type_str, (size_t)p);
if ((size_t)rval != gbe_rw_size)
exitf("%s: partial %s: part %lu",
f->fname, rw_type_str, (size_t)p);
}
void
write_to_gbe_bin(void)
{
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
int saved_errno;
int mv;
if ((cmd->flags & O_ACCMODE) != O_RDWR)
return;
write_gbe_file();
/* We may otherwise read from
* cache, so we must sync.
*/
if (fsync_on_eintr(f->tmp_fd) == -1)
exitf("%s: fsync (pre-verification)",
f->tname);
check_written_part(0);
check_written_part(1);
report_io_err_rw();
if (f->io_err_gbe)
exitf("%s: bad write", f->fname);
saved_errno = errno;
xclose(&f->tmp_fd);
xclose(&f->gbe_fd);
errno = saved_errno;
/* tmpfile written, now we
* rename it back to the main file
* (we do atomic writes)
*/
f->tmp_fd = -1;
f->gbe_fd = -1;
if (!f->io_err_gbe_bin) {
mv = gbe_mv();
if (mv < 0) {
f->io_err_gbe_bin = 1;
fprintf(stderr, "%s: %s\n",
f->fname, strerror(errno));
} else {
/* removed by rename
*/
free_and_set_null(&f->tname);
}
}
if (!f->io_err_gbe_bin)
return;
fprintf(stderr, "FAIL (rename): %s: skipping fsync\n",
f->fname);
if (errno)
fprintf(stderr,
"errno %d: %s\n", errno, strerror(errno));
}
void
check_written_part(size_t p)
{
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
ssize_t rval;
size_t gbe_rw_size;
off_t file_offset;
unsigned char *mem_offset;
unsigned char *buf_restore;
if (!f->part_modified[p])
return;
gbe_rw_size = cmd->rw_size;
mem_offset = gbe_mem_offset(p, "pwrite");
file_offset = (off_t)gbe_file_offset(p, "pwrite");
memset(f->pad, 0xff, sizeof(f->pad));
if (same_file(f->tmp_fd, &f->tmp_st, 0) < 0)
exitf("%s: file inode/device changed", f->tname);
if (same_file(f->gbe_fd, &f->gbe_st, 1) < 0)
exitf("%s: file changed during write", f->fname);
rval = rw_gbe_file_exact(f->tmp_fd, f->pad,
gbe_rw_size, file_offset, IO_PREAD);
if (rval == -1)
f->rw_check_err_read[p] = f->io_err_gbe = 1;
else if ((size_t)rval != gbe_rw_size)
f->rw_check_partial_read[p] = f->io_err_gbe = 1;
else if (vcmp(mem_offset, f->pad, gbe_rw_size) != 0)
f->rw_check_bad_part[p] = f->io_err_gbe = 1;
if (f->rw_check_err_read[p] ||
f->rw_check_partial_read[p])
return;
/* We only load one part on-file, into memory but
* always at offset zero, for post-write checks.
* That's why we hardcode good_checksum(0)
*/
buf_restore = f->buf;
/* good_checksum works on f->buf
* so let's change f->buf for now
*/
f->buf = f->pad;
if (good_checksum(0))
f->post_rw_checksum[p] = 1;
f->buf = buf_restore;
}
void
report_io_err_rw(void)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
size_t p;
if (!f->io_err_gbe)
return;
for (p = 0; p < 2; p++) {
if (!f->part_modified[p])
continue;
if (f->rw_check_err_read[p])
fprintf(stderr,
"%s: pread: p%lu (post-verification)\n",
f->fname, (size_t)p);
if (f->rw_check_partial_read[p])
fprintf(stderr,
"%s: partial pread: p%lu (post-verification)\n",
f->fname, (size_t)p);
if (f->rw_check_bad_part[p])
fprintf(stderr,
"%s: pwrite: corrupt write on p%lu\n",
f->fname, (size_t)p);
if (f->rw_check_err_read[p] ||
f->rw_check_partial_read[p]) {
fprintf(stderr,
"%s: p%lu: skipped checksum verification "
"(because read failed)\n",
f->fname, (size_t)p);
continue;
}
fprintf(stderr, "%s: ", f->fname);
if (f->post_rw_checksum[p])
fprintf(stderr, "GOOD");
else
fprintf(stderr, "BAD");
fprintf(stderr, " checksum in p%lu on-disk.\n",
(size_t)p);
if (f->post_rw_checksum[p]) {
fprintf(stderr,
" This does NOT mean it's safe. it may be\n"
" salvageable if you use the cat feature.\n");
}
}
}
int
gbe_mv(void)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
int rval;
int saved_errno;
int tmp_gbe_bin_exists;
/* will be set 0 if it doesn't
*/
tmp_gbe_bin_exists = 1;
saved_errno = errno;
rval = fs_rename_at(f->dirfd, f->tmpbase,
f->dirfd, f->base);
if (rval > -1)
tmp_gbe_bin_exists = 0;
if (f->gbe_fd > -1) {
xclose(&f->gbe_fd);
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
rval = -1;
}
}
xclose(&f->tmp_fd);
/* before this function is called,
* tmp_fd may have been moved
*/
if (tmp_gbe_bin_exists) {
if (unlink(f->tname) < 0)
rval = -1;
else
tmp_gbe_bin_exists = 0;
}
if (rval >= 0)
goto out;
return with_fallback_errno(EIO);
out:
reset_caller_errno(rval);
return rval;
}
/* This one is similar to gbe_file_offset,
* but used to check Gbe bounds in memory,
* and it is *also* used during file I/O.
*/
unsigned char *
gbe_mem_offset(size_t p, const char *f_op)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
off_t gbe_off;
gbe_off = gbe_x_offset(p, f_op, "mem",
GBE_PART_SIZE, GBE_WORK_SIZE);
return (unsigned char *)
(f->buf + (size_t)gbe_off);
}
/* I/O operations filtered here. These operations must
* only write from the 0th position or the half position
* within the GbE file, and write 4KB of data.
*/
off_t
gbe_file_offset(size_t p, const char *f_op)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
off_t gbe_file_half_size;
gbe_file_half_size = f->gbe_file_size >> 1;
return gbe_x_offset(p, f_op, "file",
gbe_file_half_size, f->gbe_file_size);
}
off_t
gbe_x_offset(size_t p, const char *f_op, const char *d_type,
off_t nsize, off_t ncmp)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
off_t off;
check_bin(p, "part number");
off = ((off_t)p) * (off_t)nsize;
if (off > ncmp - GBE_PART_SIZE)
exitf("%s: GbE %s %s out of bounds",
f->fname, d_type, f_op);
if (off != 0 && off != ncmp >> 1)
exitf("%s: GbE %s %s at bad offset",
f->fname, d_type, f_op);
return off;
}
ssize_t
rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
off_t off, int rw_type)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
ssize_t r;
if (io_args(fd, mem, nrw, off, rw_type) == -1)
return -1;
if (mem != (void *)f->pad) {
if (mem < f->buf)
goto err_rw_gbe_file_exact;
if ((size_t)(mem - f->buf) >= GBE_WORK_SIZE)
goto err_rw_gbe_file_exact;
}
if (off < 0 || off >= f->gbe_file_size)
goto err_rw_gbe_file_exact;
if (nrw > (size_t)(f->gbe_file_size - off))
goto err_rw_gbe_file_exact;
if (nrw > (size_t)GBE_PART_SIZE)
goto err_rw_gbe_file_exact;
r = rw_exact(fd, mem, nrw, off, rw_type);
return rw_over_nrw(r, nrw);
err_rw_gbe_file_exact:
return with_fallback_errno(EIO);
}
-914
View File
@@ -1,914 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*
* Hardened mktemp (be nice to the demon).
*/
/* for openat2 / fast path: */
#ifdef __linux__
#if !defined(USE_OPENAT) || \
((USE_OPENAT) < 1) /* if 1: use openat, not openat2 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <sys/syscall.h>
#include <linux/openat2.h>
#ifndef O_TMPFILE
#define O_TMPFILE 020000000
#endif
#ifndef AT_EMPTY_PATH
#define AT_EMPTY_PATH 0x1000
#endif
#endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../include/common.h"
/* note: tmpdir is an override of TMPDIR or /tmp or /var/tmp */
int
new_tmpfile(int *fd, char **path, char *tmpdir,
const char *template)
{
return new_tmp_common(fd, path, MKHTEMP_FILE,
tmpdir, template);
}
/* note: tmpdir is an override of TMPDIR or /tmp or /var/tmp */
int
new_tmpdir(int *fd, char **path, char *tmpdir,
const char *template)
{
return new_tmp_common(fd, path, MKHTEMP_DIR,
tmpdir, template);
}
int
new_tmp_common(int *fd, char **path, int type,
char *tmpdir, const char *template)
{
struct stat st;
const char *templatestr;
size_t dirlen;
char *dest = NULL; /* final path (will be written into "path") */
int saved_errno = errno;
int dirfd = -1;
const char *fname = NULL;
struct stat st_dir_first;
char *fail_dir = NULL;
errno = 0;
if (if_err(path == NULL || fd == NULL, EFAULT) ||
if_err(*fd >= 0, EEXIST)) /* don't touch someone else's file */
goto err;
/* regarding **path:
* the pointer (to the pointer)
* must nott be null, but we don't
* care about the pointer it points
* to. you should expect it to be
* replaced upon successful return
*
* (on error, it will not be touched)
*/
*fd = -1;
if (tmpdir == NULL) { /* no user override */
#if defined(PERMIT_NON_STICKY_ALWAYS) && \
((PERMIT_NON_STICKY_ALWAYS) > 0)
tmpdir = env_tmpdir(PERMIT_NON_STICKY_ALWAYS, &fail_dir, NULL);
#else
tmpdir = env_tmpdir(0, &fail_dir, NULL);
#endif
} else {
#if defined(PERMIT_NON_STICKY_ALWAYS) && \
((PERMIT_NON_STICKY_ALWAYS) > 0)
tmpdir = env_tmpdir(PERMIT_NON_STICKY_ALWAYS, &fail_dir,
tmpdir);
#else
tmpdir = env_tmpdir(0, &fail_dir, tmpdir);
#endif
}
if (if_err(tmpdir ==NULL || *tmpdir == '\0' || *tmpdir != '/', EINVAL))
goto err;
if (template != NULL)
templatestr = template;
else
templatestr = "tmp.XXXXXXXXXX";
/* may as well calculate in advance */
dirlen = slen(tmpdir, PATH_MAX, &dirlen);
/* full path: */
dest = scatn(3, (const char *[]) { tmpdir, "/", templatestr },
PATH_MAX, &dest);
fname = dest + dirlen + 1;
dirfd = fs_open(tmpdir,
O_RDONLY | O_DIRECTORY);
if (dirfd < 0)
goto err;
if (fstat(dirfd, &st_dir_first) < 0)
goto err;
*fd = mkhtemp(fd, &st, dest, dirfd,
fname, &st_dir_first, type);
if (*fd < 0)
goto err;
xclose(&dirfd);
errno = saved_errno;
*path = dest;
reset_caller_errno(0);
return 0;
err:
free_and_set_null(&dest);
xclose(&dirfd);
xclose(fd);
/* where a TMPDIR isn't found, and we err,
* we pass this back through for the
* error message
*/
if (fail_dir != NULL)
*path = fail_dir;
errno = saved_errno;
return with_fallback_errno(EIO);
}
/* hardened TMPDIR parsing
*/
char *
env_tmpdir(int bypass_all_sticky_checks, char **tmpdir,
char *override_tmpdir)
{
char *t = NULL;
int allow_noworld_unsticky;
int saved_errno = errno;
static const char tmp[] = "/tmp";
static const char vartmp[] = "/var/tmp";
char *rval = NULL;
errno = 0;
/* tmpdir is a user override, if set */
if (override_tmpdir == NULL)
t = getenv("TMPDIR");
else
t = override_tmpdir;
if (t != NULL && *t != '\0') {
if (tmpdir_policy(t,
&allow_noworld_unsticky) < 0)
goto err;
if (!world_writeable_and_sticky(t,
allow_noworld_unsticky,
bypass_all_sticky_checks))
goto err;
rval = NULL;
if (t != NULL) {
if (sdup(t, PATH_MAX, &rval) == NULL)
goto err;
}
goto out;
}
allow_noworld_unsticky = 0;
if (world_writeable_and_sticky(tmp, allow_noworld_unsticky,
bypass_all_sticky_checks))
rval = (char *)tmp;
else if (world_writeable_and_sticky(vartmp,
allow_noworld_unsticky, bypass_all_sticky_checks))
rval = (char *)vartmp;
else
goto err;
out:
reset_caller_errno(0);
if (tmpdir != NULL)
*tmpdir = rval;
return rval;
err:
if (tmpdir != NULL && t != NULL)
*tmpdir = t;
(void) with_fallback_errno(EPERM);
return NULL;
}
int
tmpdir_policy(const char *path,
int *allow_noworld_unsticky)
{
int saved_errno = errno;
int r;
errno = 0;
if (if_err(path == NULL ||
allow_noworld_unsticky == NULL, EFAULT))
goto err_tmpdir_policy;
*allow_noworld_unsticky = 1;
r = same_dir(path, "/tmp");
if (r < 0)
goto err_tmpdir_policy;
if (r > 0)
*allow_noworld_unsticky = 0;
r = same_dir(path, "/var/tmp");
if (r < 0)
goto err_tmpdir_policy;
if (r > 0)
*allow_noworld_unsticky = 0;
reset_caller_errno(0);
return 0;
err_tmpdir_policy:
return with_fallback_errno(EPERM);
}
int
same_dir(const char *a, const char *b)
{
int fd_a = -1;
int fd_b = -1;
struct stat st_a;
struct stat st_b;
int saved_errno = errno;
int rval = 0; /* LOGICAL error, 0, if 0 is returned */
errno = 0;
/* optimisation: if both dirs
are the same, we don't need
to check anything. sehr schnell!
*/
/* bonus: scmp checks null for us */
if (!scmp(a, b, PATH_MAX, &rval))
goto success_same_dir;
else
rval = 0; /* reset */
if ((fd_a = fs_open(a, O_RDONLY | O_DIRECTORY | O_NOFOLLOW)) < 0 ||
(fd_b = fs_open(b, O_RDONLY | O_DIRECTORY | O_NOFOLLOW)) < 0 ||
fstat(fd_a, &st_a) < 0 ||
fstat(fd_b, &st_b) < 0)
goto err_same_dir;
if (st_a.st_dev == st_b.st_dev &&
st_a.st_ino == st_b.st_ino) {
success_same_dir:
rval = 1; /* SUCCESS */
}
xclose(&fd_a);
xclose(&fd_b);
/* we reset caller errno regardless
* of success, so long as it's not
* a syscall error
*/
reset_caller_errno(0);
return rval;
err_same_dir:
/* FAILURE (probably syscall) - returns -1
*/
xclose(&fd_a);
xclose(&fd_b);
return with_fallback_errno(EIO); /* -1 */
}
/* bypass_all_sticky_checks: if set,
disable stickiness checks (libc behaviour)
(if not set: leah behaviour)
allow_noworld_unsticky:
allow non-sticky files if not world-writeable
(still block non-sticky in standard TMPDIR)
*/
int
world_writeable_and_sticky(
const char *s,
int allow_noworld_unsticky,
int bypass_all_sticky_checks)
{
struct stat st;
int dirfd = -1;
int saved_errno = errno;
errno = 0;
if (if_err(s == NULL || *s == '\0', EINVAL) ||
(dirfd = fs_open(s, O_RDONLY | O_DIRECTORY)) < 0 ||
fstat(dirfd, &st) < 0 ||
if_err(!S_ISDIR(st.st_mode), ENOTDIR))
goto sticky_hell;
/* *normal-**ish mode (libc):
*/
if (bypass_all_sticky_checks)
goto sticky_heaven; /* normal == no security */
/* extremely not-libc mode:
* only require stickiness on world-writeable dirs:
*/
if (st.st_mode & S_IWOTH) { /* world writeable */
if (if_err(!(st.st_mode & S_ISVTX), EPERM))
goto sticky_hell; /* not sticky */
goto sticky_heaven; /* sticky! */
} else if (allow_noworld_unsticky) {
goto sticky_heaven; /* sticky visa */
} else {
goto sticky_hell; /* visa denied */
}
sticky_heaven:
if (faccessat(dirfd, ".", X_OK, AT_EACCESS) < 0)
goto sticky_hell; /* down you go! */
xclose(&dirfd);
reset_caller_errno(0);
return 1;
sticky_hell:
xclose(&dirfd);
(void) with_fallback_errno(EPERM);
return 0;
}
/* mk(h)temp - hardened mktemp.
* like mkstemp, but (MUCH) harder.
*
* designed to resist TOCTOU attacks
* e.g. directory race / symlink attack
*
* extremely strict and even implements
* some limited userspace-level sandboxing,
* similar in spirit to openbsd unveil,
* though unveil is from kernel space.
*
* supports both files and directories.
* file: type = MKHTEMP_FILE (0)
* dir: type = MKHTEMP_DIR (1)
*
* DESIGN NOTES:
*
* caller is expected to handle
* cleanup e.g. free(), on *st,
* *template, *fname (all of the
* pointers). ditto fd cleanup.
*
* some limited cleanup is
* performed here, e.g. directory/file
* cleanup on error in mkhtemp_try_create
*
* we only check if these are not NULL,
* and the caller is expected to take
* care; without too many conditions,
* these functions are more flexible,
* but some precauttions are taken:
*
* when used via the function new_tmpfile
* or new_tmpdir, thtis is extremely strict,
* much stricter than previous mktemp
* variants. for example, it is much
* stricter about stickiness on world
* writeable directories, and it enforces
* file ownership under hardened mode
* (only lets you touch your own files/dirs)
*/
/*
TODO:
some variables e.g. template vs suffix,
assumes they match.
we should test this explicitly,
but the way this is called is
currently safe - this would however
be nice for future library use
by outside projects.
this whole code needs to be reorganised
*/
int
mkhtemp(int *fd,
struct stat *st,
char *template,
int dirfd,
const char *fname,
struct stat *st_dir_first,
int type)
{
size_t template_len = 0;
size_t xc = 0;
size_t fname_len = 0;
char *fname_copy = NULL;
char *p;
size_t retries;
int saved_errno = errno;
int r;
char *end;
errno = 0;
if (if_err(fd == NULL || template == NULL || fname == NULL ||
st_dir_first == NULL, EFAULT) ||
if_err(*fd >= 0, EEXIST) ||
if_err(dirfd < 0, EBADF))
goto err;
/* count X */
for (end = template + slen(template, PATH_MAX, &template_len);
end > template && *--end == 'X'; xc++);
fname_len = slen(fname, PATH_MAX, &fname_len);
if (if_err(strrchr(fname, '/') != NULL, EINVAL))
goto err;
if (if_err(xc < 3 || xc > template_len, EINVAL) ||
if_err(fname_len > template_len, EOVERFLOW))
goto err;
if (if_err(vcmp(fname, template + template_len - fname_len,
fname_len) != 0, EINVAL))
goto err;
/* fname_copy = templatestr region only; p points to trailing XXXXXX */
memcpy(smalloc(&fname_copy, fname_len + 1),
template + template_len - fname_len,
fname_len + 1);
p = fname_copy + fname_len - xc;
for (retries = 0; retries < MKHTEMP_RETRY_MAX; retries++) {
r = mkhtemp_try_create(dirfd,
st_dir_first, fname_copy,
p, xc, fd, st, type);
if (r == 0)
continue;
if (r < 0)
goto err;
/* success: copy final name back */
memcpy(template + template_len - fname_len,
fname_copy, fname_len);
errno = saved_errno;
goto success;
}
errno = EEXIST;
err:
xclose(fd);
free_and_set_null(&fname_copy);
return with_fallback_errno(EIO);
success:
free_and_set_null(&fname_copy);
reset_caller_errno(0);
return *fd;
}
int
mkhtemp_try_create(int dirfd,
struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
int *fd,
struct stat *st,
int type)
{
struct stat st_open;
int saved_errno = errno;
int rval = -1;
char *rstr = NULL;
int file_created = 0;
int dir_created = 0;
errno = 0;
if (if_err(fd == NULL || st == NULL || p ==NULL || fname_copy ==NULL ||
st_dir_first == NULL, EFAULT) ||
if_err(*fd >= 0, EEXIST))
goto err;
/* TODO: potential infinite loop under entropy failure.
* if attacker has control of rand - TODO: maybe add timeout
*/
memcpy(p, rstr = rchars(xc), xc);
free_and_set_null(&rstr);
if (if_err_sys(fd_verify_dir_identity(dirfd, st_dir_first) < 0))
goto err;
if (type == MKHTEMP_FILE) {
#if defined(__linux__) && \
(!defined(USE_OPENAT) || ((USE_OPENAT) < 1))
/* try O_TMPFILE fast path */
if (mkhtemp_tmpfile_linux(dirfd,
st_dir_first, fname_copy,
p, xc, fd, st) >= 0) {
errno = saved_errno;
rval = 1;
goto out;
}
#endif
*fd = openat_on_eintr(dirfd, fname_copy,
O_RDWR | O_CREAT | O_EXCL |
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, 0600);
/* O_CREAT and O_EXCL guarantees creation upon success
*/
if (*fd >= 0)
file_created = 1;
} else { /* dir: MKHTEMP_DIR */
if (mkdirat_on_eintr(dirfd, fname_copy, 0700) < 0)
goto err;
/* ^ NOTE: opening the directory here
will never set errno=EEXIST,
since we're not creating it */
dir_created = 1;
/* do it again (mitigate directory race) */
if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
if ((*fd = openat_on_eintr(dirfd, fname_copy,
O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) < 0)
goto err;
if (if_err_sys(fstat(*fd, &st_open) < 0) ||
if_err(!S_ISDIR(st_open.st_mode), ENOTDIR))
goto err;
/* NOTE: pointless to check nlink here (only just opened) */
if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
}
/* NOTE: openat_on_eintr and mkdirat_on_eintr
* already handled EINTR/EAGAIN looping
*/
if (*fd < 0) {
if (errno == EEXIST) {
rval = 0;
goto out;
}
goto err;
}
if (fstat(*fd, &st_open) < 0)
goto err;
if (type == MKHTEMP_FILE) {
if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
if (secure_file(fd, st, &st_open,
O_APPEND, 1, 1, 0600) < 0) /* WARNING: only once */
goto err;
} else { /* dir: MKHTEMP_DIR */
if (fd_verify_identity(*fd, &st_open, st_dir_first) < 0)
goto err;
if (if_err(!S_ISDIR(st_open.st_mode), ENOTDIR) ||
if_err_sys(is_owner(&st_open) < 0) ||
if_err(st_open.st_mode & (S_IWGRP | S_IWOTH), EPERM))
goto err;
}
rval = 1;
out:
reset_caller_errno(0);
return rval;
err:
xclose(fd);
if (file_created)
(void) unlinkat(dirfd, fname_copy, 0);
if (dir_created)
(void) unlinkat(dirfd, fname_copy, AT_REMOVEDIR);
return with_fallback_errno(EPERM);
}
/* linux has its own special hardening
available specifically for tmpfiles,
which eliminates many race conditions.
we still use openat() on bsd, which is
still ok with our other mitigations
*/
#if defined(__linux__) && \
(!defined(USE_OPENAT) || ((USE_OPENAT) < 1))
int
mkhtemp_tmpfile_linux(int dirfd,
struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
int *fd,
struct stat *st)
{
int saved_errno = errno;
int tmpfd = -1;
size_t retries;
int linked = 0;
char *rstr = NULL;
errno = 0;
if (if_err(fd == NULL || st == NULL ||
fname_copy == NULL || p == NULL ||
st_dir_first == NULL, EFAULT))
goto err;
/* create unnamed tmpfile */
tmpfd = openat_on_eintr(dirfd, ".",
O_TMPFILE | O_RDWR | O_CLOEXEC, 0600);
if (tmpfd < 0)
goto err;
if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
for (retries = 0; retries < MKHTEMP_RETRY_MAX; retries++) {
memcpy(p, rstr = rchars(xc), xc);
free_and_set_null(&rstr);
if (fd_verify_dir_identity(dirfd,
st_dir_first) < 0)
goto err;
if (linkat(tmpfd, "", dirfd,
fname_copy, AT_EMPTY_PATH) == -1) {
if (errno == EEXIST)
continue; /* retry on collision */
else
goto err;
}
linked = 1; /* file created */
/* TODO: potential fd leak here.
* probably should only set *fd on successful
* return from this function (see below)
*/
if (fd_verify_dir_identity(dirfd, st_dir_first) < 0 ||
fstat(*fd = tmpfd, st) < 0 ||
secure_file(fd, st, st, O_APPEND, 1, 1, 0600) < 0)
goto err;
goto out;
}
if (!errno)
errno = EEXIST;
err:
if (linked)
(void) unlinkat(dirfd, fname_copy, 0);
xclose(&tmpfd);
return with_fallback_errno(EIO);
out:
reset_caller_errno(0);
return 0;
}
#endif
/* WARNING: **ONCE** per file.
*
* some of these checks will trip up
* if you do them twice; all of them
* only need to be done once anyway.
*/
int secure_file(int *fd,
struct stat *st,
struct stat *expected,
int bad_flags,
int check_seek,
int do_lock,
mode_t mode)
{
int flags = -1;
struct stat st_now;
int saved_errno = errno;
errno = 0;
if (if_err(fd == NULL || st == NULL, EFAULT) ||
if_err(*fd < 0, EBADF))
goto err_demons;
if ((flags = fcntl(*fd, F_GETFL)) == -1)
goto err_demons;
if (if_err(bad_flags > 0 && (flags & bad_flags), EPERM))
goto err_demons;
if (expected != NULL) {
if (fd_verify_regular(*fd, expected, st) < 0)
goto err_demons;
} else if (if_err_sys(fstat(*fd, &st_now) == -1) ||
if_err(!S_ISREG(st_now.st_mode), EBADF)) {
goto err_demons; /***********/
} else /* ( >:3 ) */
*st = st_now; /* /| |\ */ /* don't let him out */
/* / \ */
if (check_seek) { /***********/
if (lseek(*fd, 0, SEEK_CUR) == (off_t)-1)
goto err_demons;
} /* don't release the demon! */
if (if_err(st->st_nlink != 1, ELOOP) ||
if_err(st->st_uid != geteuid() && geteuid() != 0, EPERM) ||
if_err_sys(is_owner(st) < 0) ||
if_err(st->st_mode & (S_IWGRP | S_IWOTH), EPERM))
goto err_demons;
if (do_lock) {
if (lock_file(*fd, flags) == -1)
goto err_demons;
/* TODO: why would this be NULL? audit
* to find out. we should always verify! */
if (expected != NULL)
if (fd_verify_identity(*fd, expected, &st_now) < 0)
goto err_demons;
}
if (fchmod(*fd, mode) == -1)
goto err_demons;
reset_caller_errno(0);
return 0;
err_demons:
return with_fallback_errno(EIO);
}
int
fd_verify_regular(int fd,
const struct stat *expected,
struct stat *out)
{
int saved_errno = errno;
errno = 0;
if (if_err_sys(fd_verify_identity(fd, expected, out) < 0) ||
if_err(!S_ISREG(out->st_mode), EBADF)) {
return with_fallback_errno(EIO);
} else {
reset_caller_errno(0);
return 0; /* regular file */
}
}
int
fd_verify_identity(int fd,
const struct stat *expected,
struct stat *out)
{
struct stat st_now;
int saved_errno = errno;
errno = 0;
if( if_err(fd < 0 || expected == NULL, EFAULT) ||
if_err_sys(fstat(fd, &st_now)) ||
if_err(st_now.st_dev != expected->st_dev ||
st_now.st_ino != expected->st_ino, ESTALE))
return with_fallback_errno(EIO);
if (out != NULL)
*out = st_now;
reset_caller_errno(0);
return 0;
}
int
fd_verify_dir_identity(int fd,
const struct stat *expected)
{
struct stat st_now;
int saved_errno = errno;
errno = 0;
if (if_err(fd < 0 || expected == NULL, EFAULT) ||
if_err_sys(fstat(fd, &st_now) < 0) ||
if_err(st_now.st_dev != expected->st_dev, ESTALE) ||
if_err(st_now.st_ino != expected->st_ino, ESTALE) ||
if_err(!S_ISDIR(st_now.st_mode), ENOTDIR))
goto err;
reset_caller_errno(0);
return 0;
err:
return with_fallback_errno(EIO);
}
int
is_owner(struct stat *st)
{
int saved_errno = errno;
errno = 0;
if (if_err(st == NULL, EFAULT) ||
if_err(st->st_uid != geteuid() /* someone else's file */
#if defined(ALLOW_ROOT_OVERRIDE) && ((ALLOW_ROOT_OVERRIDE) > 0)
&& geteuid() != 0 /* override for root */
#endif
, EPERM)) return with_fallback_errno(EIO);
reset_caller_errno(0);
return 0;
}
int
lock_file(int fd, int flags)
{
struct flock fl;
int saved_errno = errno;
int fcntl_rval = -1;
errno = 0;
if (if_err(fd < 0, EBADF) ||
if_err(flags < 0, EINVAL))
goto err_lock_file;
memset(&fl, 0, sizeof(fl));
if ((flags & O_ACCMODE) == O_RDONLY)
fl.l_type = F_RDLCK;
else
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
if ((fcntl_rval = fcntl(fd, F_SETLK, &fl)) == -1)
goto err_lock_file;
reset_caller_errno(0);
return 0;
err_lock_file:
return with_fallback_errno(EIO);
}
-116
View File
@@ -1,116 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*
* Non-randomisation-related numerical functions.
* For rand functions, see: rand.c
*/
#ifdef __OpenBSD__
#include <sys/param.h>
#endif
#include <sys/types.h>
#include <errno.h>
#if !((defined(__OpenBSD__) && (OpenBSD) >= 201) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__APPLE__))
#include <fcntl.h> /* if not arc4random: /dev/urandom */
#endif
#include <ctype.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "../include/common.h"
unsigned short
hextonum(char ch_s)
{
unsigned char ch;
ch = (unsigned char)ch_s;
if ((unsigned int)(ch - '0') <= 9)
return ch - '0';
ch |= 0x20;
if ((unsigned int)(ch - 'a') <= 5)
return ch - 'a' + 10;
if (ch == '?' || ch == 'x') /* random */
return (short)rsize(16); /* <-- with rejection sampling! */
return 16;
}
/* basically hexdump -C */
/*
TODO: optimise this
write a full util for hexdump
how to optimise:
don't call print tens of thousands of times!
convert the numbers manually, and cache everything
in a BUFSIZ sized buffer, with everything properly
aligned. i worked out that i could fit 79 rows
in a 8KB buffer (1264 bytes of numbers represented
as strings in hex)
this depends on the OS, and would be calculated at
runtime.
then:
don't use printf. just write it to stdout (basically
a simple cat implementation)
*/
void
spew_hex(const void *data, size_t len)
{
const unsigned char *buf = (const unsigned char *)data;
unsigned char c;
size_t i;
size_t j;
if (buf == NULL ||
len == 0)
return;
for (i = 0; i < len; i += 16) {
if (len <= 4294967296) /* below 4GB */
printf("%08zx ", i);
else
printf("%16zu ", i);
for (j = 0; j < 16; j++) {
if (i + j < len)
printf("%02x ", buf[i + j]);
else
printf(" ");
if (j == 7)
printf(" ");
}
printf(" |");
for (j = 0; j < 16 && i + j < len; j++) {
c = buf[i + j];
printf("%c", isprint(c) ? c : '.');
}
printf("|\n");
}
printf("%08zx\n", len);
}
void
check_bin(size_t a, const char *a_name)
{
if (a > 1)
exitf("%s must be 0 or 1, but is %lu",
a_name, (size_t)a);
}
-200
View File
@@ -1,200 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*
* Random number generation
*/
#if defined(USE_ARC4) && \
((USE_ARC4) > 0)
#define _DEFAULT_SOURCE 1 /* for arc4random on *linux* */
/* (not needed on bsd - on bsd,
it is used automatically unless
overridden with USE_URANDOM */
#elif defined(USE_URANDOM) && \
((USE_URANDOM) > 0)
#include <fcntl.h> /* if not arc4random: /dev/urandom */
#elif defined(__linux__) && \
!(defined(USE_ARC4) && ((USE_ARC4) > 0))
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <sys/syscall.h>
#include <sys/random.h>
#endif
#ifdef __OpenBSD__
#include <sys/param.h>
#endif
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "../include/common.h"
/* Regarding Linux getrandom/urandom:
*
* For maximum security guarantee, we *only*
* use getrandom via syscall, or /dev/urandom;
* use of urandom is ill advised. This is why
* we use the syscall, in case the libc version
* of getrandom() might defer to /dev/urandom
*
* We *abort* on error, for both /dev/urandom
* and getrandom(), because the BSD arc4random
* never returns with error; therefore, for the
* most parity in terms of behaviour, we abort,
* because otherwise the function would have two
* return modes: always successful (BSD), or only
* sometimes (Linux). The BSD arc4random could
* theoretically abort; it is extremely unlikely
* there, and just so on Linux, hence this design.
*
* This is important, because cryptographic code
* for example must not rely on weak randomness.
* We must therefore treat broken randomness as
* though the world is broken, and burn accordingly.
*
* Similarly, any invalid input (NULL, zero bytes
* requested) are treated as fatal errors; again,
* cryptographic code must be reliable. If your
* code erroneously requested zero bytes, you might
* then end up with a non-randomised buffer, where
* you likely intended otherwise.
*
* In other words: call rset() correctly, or your
* program dies, and rset will behave correctly,
* or your program dies.
*/
/* random string generator, with
* rejection sampling. NOTE: only
* uses ASCII-safe characters, for
* printing on a unix terminal
*
* you still shouldn't use this for
* password generation; open diceware
* passphrases are better for that
*
* NOTE: the generated strings must
* ALSO be safe for file/directory names
* on unix-like os e.g. linux/bsd
*/
char *
rchars(size_t n) /* emulates spkmodem-decode */
{
static char ch[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
char *s = NULL;
size_t i;
smalloc(&s, n + 1);
for (i = 0; i < n; i++)
s[i] = ch[rsize(sizeof(ch) - 1)];
*(s + n) = '\0';
return s;
}
size_t
rsize(size_t n)
{
size_t rval = SIZE_MAX;
if (!n)
exitf("rsize: division by zero");
/* rejection sampling (clamp rand to eliminate modulo bias) */
for (; rval >= SIZE_MAX - (SIZE_MAX % n); rset(&rval, sizeof(rval)));
return rval % n;
}
void *
rmalloc(size_t n)
{
void *buf = NULL;
rset(vmalloc(&buf, n), n);
return buf; /* basically malloc() but with rand */
}
void
rset(void *buf, size_t n)
{
int saved_errno = errno;
errno = 0;
if (if_err(buf == NULL, EFAULT))
goto err;
if (n == 0)
exitf("rset: zero-byte request");
/* on linux, getrandom is recommended,
but you can pass -DUSE_ARC4=1 to use arc4random.
useful for portability testing from linux.
*/
#if (defined(USE_ARC4) && ((USE_ARC4) > 0)) || \
((defined(__OpenBSD__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__APPLE__) || \
defined(__DragonFly__)) && !(defined(USE_URANDOM) && \
((USE_URANDOM) > 0)))
arc4random_buf(buf, n);
#else
size_t off = 0;
retry_rand: {
#if defined(USE_URANDOM) && \
((USE_URANDOM) > 0)
ssize_t rval;
int fd = -1;
open_file_on_eintr("/dev/urandom", &fd, O_RDONLY, 0400, NULL);
while (rw_retry(saved_errno,
rval = rw(fd, (unsigned char *)buf + off, n - off, 0, IO_READ)));
#elif defined(__linux__)
long rval;
while (sys_retry(saved_errno,
rval = syscall(SYS_getrandom,
(unsigned char *)buf + off, n - off, 0)));
#else
#error Unsupported operating system (possibly unsecure randomisation)
#endif
if (rval < 0 || /* syscall fehler */
rval == 0) { /* prevent infinite loop on fatal err */
#if defined(USE_URANDOM) && \
((USE_URANDOM) > 0)
xclose(&fd);
#endif
goto err;
}
if ((off += (size_t)rval) < n)
goto retry_rand;
#if defined(USE_URANDOM) && \
((USE_URANDOM) > 0)
xclose(&fd);
#endif
}
#endif
reset_caller_errno(0);
return;
err:
(void) with_fallback_errno(ECANCELED);
exitf("Randomisierungsfehler");
exit(EXIT_FAILURE);
}
-164
View File
@@ -1,164 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
*
* State machine (singleton) for nvmutil data.
*/
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../include/common.h"
struct xstate *
xstart(int argc, char *argv[])
{
static int first_run = 1;
static char *dir = NULL;
static char *base = NULL;
char *realdir = NULL;
char *tmpdir = NULL;
char *tmpbase_local = NULL;
static struct xstate us = {
{
/* be careful when modifying xstate. you
* must set everything precisely */
{
CMD_DUMP, "dump", cmd_helper_dump, ARGC_3,
ARG_NOPART,
SKIP_CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
NVM_SIZE, O_RDONLY
}, {
CMD_SETMAC, "setmac", cmd_helper_setmac, ARGC_3,
ARG_NOPART,
CHECKSUM_READ, CHECKSUM_WRITE,
NVM_SIZE, O_RDWR
}, {
CMD_SWAP, "swap", cmd_helper_swap, ARGC_3,
ARG_NOPART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDWR
}, {
CMD_COPY, "copy", cmd_helper_copy, ARGC_4,
ARG_PART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDWR
}, {
CMD_CAT, "cat", cmd_helper_cat, ARGC_3,
ARG_NOPART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDONLY
}, {
CMD_CAT16, "cat16", cmd_helper_cat16, ARGC_3,
ARG_NOPART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDONLY
}, {
CMD_CAT128, "cat128", cmd_helper_cat128, ARGC_3,
ARG_NOPART,
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
GBE_PART_SIZE, O_RDONLY
}
},
/* ->mac */
{NULL, "xx:xx:xx:xx:xx:xx", {0, 0, 0}}, /* .str, .rmac, .mac_buf */
/* .f */
{0},
/* ->i (index to cmd[]) */
0,
/* .no_cmd (set 0 when a command is found) */
1,
/* .cat (cat helpers set this) */
-1
};
if (!first_run)
return &us;
if (argc < 3)
exitf("xstart: Too few arguments");
if (argv == NULL)
exitf("xstart: NULL argv");
first_run = 0;
us.f.buf = us.f.real_buf;
us.f.fname = argv[1];
us.f.tmp_fd = -1;
us.f.tname = NULL;
if ((realdir = realpath(us.f.fname, NULL)) == NULL)
exitf("xstart: can't get realpath of %s",
us.f.fname);
if (fs_dirname_basename(realdir, &dir, &base, 0) < 0)
exitf("xstart: don't know CWD of %s",
us.f.fname);
sdup(base, PATH_MAX, &us.f.base);
us.f.dirfd = fs_open(dir,
O_RDONLY | O_DIRECTORY);
if (us.f.dirfd < 0)
exitf("%s: open dir", dir);
if (new_tmpfile(&us.f.tmp_fd, &us.f.tname, dir, ".gbe.XXXXXXXXXX") < 0)
exitf("%s", us.f.tname);
if (fs_dirname_basename(us.f.tname,
&tmpdir, &tmpbase_local, 0) < 0)
exitf("tmp basename");
sdup(tmpbase_local, PATH_MAX, &us.f.tmpbase);
free_and_set_null(&tmpdir);
if (us.f.tname == NULL)
exitf("x->f.tname null");
if (*us.f.tname == '\0')
exitf("x->f.tname empty");
if (fstat(us.f.tmp_fd, &us.f.tmp_st) < 0)
exitf("%s: stat", us.f.tname);
memset(us.f.real_buf, 0, sizeof(us.f.real_buf));
memset(us.f.bufcmp, 0, sizeof(us.f.bufcmp));
/* for good measure */
memset(us.f.pad, 0, sizeof(us.f.pad));
return &us;
}
struct xstate *
xstatus(void)
{
struct xstate *x = xstart(0, NULL);
if (x == NULL)
exitf("NULL pointer to xstate");
return x;
}
-643
View File
@@ -1,643 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*
* String functions
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <stdint.h>
#include "../include/common.h"
/* for null detection inside
* word-optimised string functions
*/
#define ff ((size_t)-1 / 0xFF)
#define high ((ff) * 0x80)
/* NOTE:
* do not assume that a match means
* both words have null at the same
* location. see how this is handled
* e.g. in scmp.
*/
#define zeroes(x) (((x) - (ff)) & ~(x) & (high))
size_t
page_remain(const void *p)
{
/* calling sysconf repeatedly
* is folly. cache it (static)
*/
static size_t pagesz = 0;
if (!pagesz)
pagesz = (size_t)pagesize();
return pagesz - ((uintptr_t)p & (pagesz - 1));
}
long
pagesize(void)
{
static long rval = 0;
static int set = 0;
int saved_errno = 0;
if (!set) {
if ((rval = sysconf(_SC_PAGESIZE)) < 0)
exitf("could not determine page size");
set = 1;
}
reset_caller_errno(0);
return rval;
}
void
free_and_set_null(char **buf)
{
if (buf == NULL)
exitf(
"null ptr (to ptr for freeing) in free_and_set_null");
if (*buf == NULL)
return;
free(*buf);
*buf = NULL;
}
/* safe(ish) malloc.
use this and free_and_set_null()
in your program, to reduce the
chance of use after frees!
if you use these functions in the
intended way, you will greatly reduce
the number of bugs in your code
*/
char *
smalloc(char **buf, size_t size)
{
return (char *)vmalloc((void **)buf, size);
}
void *
vmalloc(void **buf, size_t size)
{
int saved_errno = errno;
void *rval = NULL;
errno = 0;
if (size >= SIZE_MAX - 1)
exitf("integer overflow in vmalloc");
if (buf == NULL)
exitf("Bad pointer passed to vmalloc");
/* lots of programs will
* re-initialise a buffer
* that was allocated, without
* freeing or NULLing it. this
* is here intentionally, to
* force the programmer to behave
*/
if (*buf != NULL)
exitf("Non-null pointer given to vmalloc");
if (!size)
exitf(
"Tried to vmalloc(0) and that is very bad. Fix it now");
if ((rval = malloc(size)) == NULL)
exitf("malloc fail in vmalloc");
reset_caller_errno(0);
return *buf = rval;
}
/* strict word-based strcmp */
int
scmp(const char *a,
const char *b,
size_t maxlen,
int *rval)
{
size_t i = 0;
size_t j;
size_t wa;
size_t wb;
int saved_errno = errno;
errno = 0;
if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT))
goto err;
for ( ; ((uintptr_t)(a + i) % sizeof(size_t)) != 0; i++) {
if (if_err(i >= maxlen, EOVERFLOW))
goto err;
else if (!ccmp(a, b, i, rval))
goto out;
}
for ( ; i + sizeof(size_t) <= maxlen;
i += sizeof(size_t)) {
/* prevent crossing page boundary on word check */
if (page_remain(a + i) < sizeof(size_t) ||
page_remain(b + i) < sizeof(size_t))
break;
memcpy(&wa, a + i, sizeof(size_t));
memcpy(&wb, b + i, sizeof(size_t));
if (wa != wb)
for (j = 0; j < sizeof(size_t); j++)
if (!ccmp(a, b, i + j, rval))
goto out;
if (!zeroes(wa))
continue;
*rval = 0;
goto out;
}
for ( ; i < maxlen; i++)
if (!ccmp(a, b, i, rval))
goto out;
err:
(void) with_fallback_errno(EFAULT);
if (rval != NULL)
*rval = -1;
exitf("scmp");
return -1;
out:
reset_caller_errno(0);
return *rval;
}
int ccmp(const char *a, const char *b,
size_t i, int *rval)
{
unsigned char ac;
unsigned char bc;
if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT))
exitf("ccmp");
ac = (unsigned char)a[i];
bc = (unsigned char)b[i];
if (ac != bc) {
*rval = ac - bc;
return 0;
} else if (ac == '\0') {
*rval = 0;
return 0;
}
return 1;
}
/* strict word-based strlen */
size_t
slen(const char *s,
size_t maxlen,
size_t *rval)
{
int saved_errno = errno;
size_t i = 0;
size_t w;
size_t j;
errno = 0;
if (if_err(s == NULL || rval == NULL, EFAULT))
goto err;
for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) {
if (if_err(i >= maxlen, EOVERFLOW))
goto err;
if (s[i] == '\0') {
*rval = i;
goto out;
}
}
for ( ; i + sizeof(size_t) <= maxlen;
i += sizeof(size_t)) {
memcpy(&w, s + i, sizeof(size_t));
if (!zeroes(w))
continue;
for (j = 0; j < sizeof(size_t); j++) {
if (s[i + j] == '\0') {
*rval = i + j;
goto out;
}
}
}
for ( ; i < maxlen; i++) {
if (s[i] == '\0') {
*rval = i;
goto out;
}
}
err:
(void) with_fallback_errno(EFAULT);
if (rval != NULL)
*rval = 0;
exitf("slen"); /* abort */
return 0; /* gcc15 is happy */
out:
reset_caller_errno(0);
return *rval;
}
int
dup_pair(char **dir, const char *d,
char **base, const char *b)
{
char *dtmp = NULL;
char *btmp = NULL;
if (d && sdup(d, PATH_MAX, &dtmp) == NULL)
return -1;
if (b && sdup(b, PATH_MAX, &btmp) == NULL) {
free(dtmp);
return -1;
}
*dir = dtmp;
*base = btmp;
return 0;
}
/* strict word-based strdup */
char *
sdup(const char *s,
size_t max, char **dest)
{
size_t j;
size_t w;
size_t i = 0;
char *out = NULL;
int saved_errno = errno;
errno = 0;
if (if_err(dest == NULL || *dest != NULL || s == NULL, EFAULT))
goto err;
out = smalloc(dest, max);
for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) {
if (if_err(i >= max, EOVERFLOW))
goto err;
out[i] = s[i];
if (s[i] == '\0') {
*dest = out;
goto out;
}
}
for ( ; i + sizeof(size_t) <= max; i += sizeof(size_t)) {
if (page_remain(s + i) < sizeof(size_t))
break;
memcpy(&w, s + i, sizeof(size_t));
if (!zeroes(w)) {
memcpy(out + i, &w, sizeof(size_t));
continue;
}
for (j = 0; j < sizeof(size_t); j++) {
out[i + j] = s[i + j];
if (s[i + j] == '\0') {
*dest = out;
goto out;
}
}
}
for ( ; i < max; i++) {
out[i] = s[i];
if (s[i] == '\0') {
*dest = out;
goto out;
}
}
err:
free_and_set_null(&out);
if (dest != NULL)
*dest = NULL;
(void) with_fallback_errno(EFAULT);
exitf("sdup");
return NULL;
out:
reset_caller_errno(0);
return *dest;
}
/* concatenate N number of strings */
char *
scatn(ssize_t sc, const char **sv,
size_t max, char **rval)
{
int saved_errno = errno;
char *final = NULL;
char *rcur = NULL;
char *rtmp = NULL;
ssize_t i;
errno = 0;
if (if_err(sc < 2, EINVAL) ||
if_err(sv == NULL, EFAULT) ||
if_err(rval == NULL || *rval != NULL, EFAULT))
goto err;
for (i = 0; i < sc; i++) {
if (if_err(sv[i] == NULL, EFAULT))
goto err;
else if (i == 0) {
(void) sdup(sv[0], max, &final);
continue;
}
rtmp = NULL;
scat(final, sv[i], max, &rtmp);
free_and_set_null(&final);
final = rtmp;
rtmp = NULL;
}
reset_caller_errno(0);
*rval = final;
return *rval;
err:
free_and_set_null(&rcur);
free_and_set_null(&rtmp);
free_and_set_null(&final);
(void) with_fallback_errno(EFAULT);
exitf("scatn");
return NULL;
}
/* strict strcat */
char *
scat(const char *s1, const char *s2,
size_t n, char **dest)
{
size_t size1;
size_t size2;
char *rval = NULL;
int saved_errno = errno;
errno = 0;
if (if_err(dest == NULL || *dest != NULL, EFAULT))
goto err;
slen(s1, n, &size1);
slen(s2, n, &size2);
if (if_err(size1
> SIZE_MAX - size2 - 1, EOVERFLOW))
goto err;
smalloc(&rval, size1 + size2 + 1);
memcpy(rval, s1, size1);
memcpy(rval + size1, s2, size2);
*(rval + size1 + size2) = '\0';
reset_caller_errno(0);
*dest = rval;
return *dest;
err:
(void) with_fallback_errno(EINVAL);
if (dest != NULL)
*dest = NULL;
exitf("scat");
return NULL;
}
/* strict split/de-cat - off is where
2nd buffer will start from */
void
dcat(const char *s, size_t n,
size_t off, char **dest1,
char **dest2)
{
size_t size;
char *rval1 = NULL;
char *rval2 = NULL;
int saved_errno = errno;
errno = 0;
if (if_err(dest1 == NULL || dest2 == NULL, EFAULT))
goto err;
if (if_err(slen(s, n, &size) >= SIZE_MAX - 1, EOVERFLOW) ||
if_err(off >= size, EOVERFLOW))
goto err;
memcpy(smalloc(&rval1, off + 1),
s, off);
*(rval1 + off) = '\0';
memcpy(smalloc(&rval2, size - off +1),
s + off, size - off);
*(rval2 + size - off) = '\0';
*dest1 = rval1;
*dest2 = rval2;
reset_caller_errno(0);
return;
err:
*dest1 = *dest2 = NULL;
free_and_set_null(&rval1);
free_and_set_null(&rval2);
(void) with_fallback_errno(EINVAL);
exitf("dcat");
}
/* because no libc reimagination is complete
* without a reimplementation of memcmp. and
* no safe one is complete without null checks.
*/
int
vcmp(const void *s1, const void *s2, size_t n)
{
int saved_errno = errno;
size_t i = 0;
size_t a;
size_t b;
const unsigned char *x;
const unsigned char *y;
errno = 0;
if (if_err(s1 == NULL || s2 == NULL, EFAULT))
exitf("vcmp: null input");
x = s1;
y = s2;
for ( ; i + sizeof(size_t) <= n; i += sizeof(size_t)) {
memcpy(&a, x + i, sizeof(size_t));
memcpy(&b, y + i, sizeof(size_t));
if (a != b)
break;
}
for ( ; i < n; i++)
if (x[i] != y[i])
return (int)x[i] - (int)y[i];
reset_caller_errno(0);
return 0;
}
/* on functions that return with errno,
* i sometimes have a default fallback,
* which is set if errno wasn't changed,
* under error condition.
*/
int
with_fallback_errno(int fallback)
{
if (!errno)
errno = fallback;
return -1;
}
/* the one for nvmutil state is in state.c */
/* this one just exits */
void
exitf(const char *msg, ...)
{
va_list args;
int saved_errno = errno;
func_t err_cleanup = errhook(NULL);
err_cleanup();
reset_caller_errno(0);
saved_errno = errno;
if (!errno)
saved_errno = errno = ECANCELED;
fprintf(stderr, "%s: ", lbgetprogname());
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
errno = saved_errno;
fprintf(stderr, ": %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
/* the err function will
* call this upon exit, and
* cleanup will be performed
* e.g. you might want to
* close some files, depending
* on your program.
* see: exitf()
*/
func_t errhook(func_t ptr)
{
static int set = 0;
static func_t hook = NULL;
if (!set) {
set = 1;
if (ptr == NULL)
hook = no_op;
else
hook = ptr;
}
return hook;
}
void
no_op(void)
{
return;
}
const char *
lbgetprogname(void)
{
char *name = lbsetprogname(NULL);
char *p = NULL;
if (name)
p = strrchr(name, '/');
if (p)
return p + 1;
else if (name)
return name;
else
return "libreboot-utils";
}
/* singleton. if string not null,
sets the string. after set,
will not set anymore. either
way, returns the string
*/
char *
lbsetprogname(char *argv0)
{
static char *progname = NULL;
static int set = 0;
if (!set) {
if (argv0 == NULL)
return "libreboot-utils";
(void) sdup(argv0, PATH_MAX, &progname);
set = 1;
}
return progname;
}
-30
View File
@@ -1,30 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com>
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*/
#include <errno.h>
#include <stdio.h>
#include "../include/common.h"
void
usage(void)
{
const char *util = lbgetprogname();
fprintf(stderr,
"Modify Intel GbE NVM images e.g. set MAC\n"
"USAGE:\n"
"\t%s FILE dump\n"
"\t%s FILE setmac [MAC]\n"
"\t%s FILE swap\n"
"\t%s FILE copy 0|1\n"
"\t%s FILE cat\n"
"\t%s FILE cat16\n"
"\t%s FILE cat128\n",
util, util, util, util,
util, util, util);
exitf("Too few arguments");
}
-68
View File
@@ -1,68 +0,0 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
*
* Manipulate Intel GbE NVM words, which are 16-bit little
* endian in the files (MAC address words are big endian).
*/
#include <sys/types.h>
#include <errno.h>
#include <stddef.h>
#include "../include/common.h"
unsigned short
nvm_word(size_t pos16, size_t p)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
size_t pos;
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
return (unsigned short)f->buf[pos] |
((unsigned short)f->buf[pos + 1] << 8);
}
void
set_nvm_word(size_t pos16, size_t p, unsigned short val16)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
size_t pos;
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
f->buf[pos] = (unsigned char)(val16 & 0xff);
f->buf[pos + 1] = (unsigned char)(val16 >> 8);
set_part_modified(p);
}
void
set_part_modified(size_t p)
{
struct xstate *x = xstatus();
struct xfile *f = &x->f;
check_bin(p, "part number");
f->part_modified[p] = 1;
}
void
check_nvm_bound(size_t c, size_t p)
{
/* Block out of bound NVM access
*/
check_bin(p, "part number");
if (c >= NVM_WORDS)
exitf("check_nvm_bound: out of bounds %lu",
(size_t)c);
}
-74
View File
@@ -1,74 +0,0 @@
/* SPDX-License-Identifier: MIT ( >:3 )
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org> /| |\
Something something non-determinism / \ */
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "include/common.h"
static void
exit_cleanup(void);
int
main(int argc, char **argv)
{
#ifndef __linux__
#error This code is currently buggy on BSD systems. Only use on Linux.
#endif
int same = 0;
char *buf;
size_t size = BUFSIZ;
(void) argc, (void) argv;
(void) errhook(exit_cleanup);
(void) lbsetprogname(argv[0]);
#ifdef __OpenBSD__
/* https://man.openbsd.org/pledge.2 */
if (pledge("stdio", NULL) == -1)
exitf("pledge");
#endif
buf = rmalloc(size);
if (!vcmp(buf, buf + (size >> 1), size >> 1))
same = 1;
if (argc < 2) /* no spew */
spew_hex(buf, size);
free_and_set_null(&buf);
fprintf(stderr, "\n%s\n", same ? "You win!" : "You lose!");
return same ? EXIT_SUCCESS : EXIT_FAILURE;
}
static void
exit_cleanup(void)
{
#if defined(__OpenBSD__)
fprintf(stderr, "OpenBSD wins\n");
#elif defined(__FreeBSD__)
fprintf(stderr, "FreeBSD wins\n");
#elif defined(__NetBSD__)
fprintf(stderr, "NetBSD wins\n");
#elif defined(__APPLE__)
fprintf(stderr, "MacOS wins\n");
#elif defined(__DragonFly__)
fprintf(stderr, "DragonFly BSD wins\n");
#elif defined(__linux__)
#if defined(__GLIBC__)
fprintf(stderr, "GNU/Linux wins\n");
#elif defined(__MUSL__)
fprintf(stderr, "Rich Felker wins\n");
#else
fprintf(stderr, "Linux wins\n");
#endif
#else
fprintf(stderr, "Your operating system wins\n");
#endif
return;
}
-152
View File
@@ -1,152 +0,0 @@
/* SPDX-License-Identifier: MIT ( >:3 )
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org> /| |\
* / \
* Hardened mktemp (mkhtemp!)
*
* WORK IN PROGRESS (proof of concept), or, v0.0000001
* DO NOT PUT THIS IN YOUR LINUX DISTRO YET.
*
* In other words: for reference only -- PATCHES WELCOME!
*
* I will remove this notice when the code is mature, and
* probably contact several of your projects myself.
*
* See README. This is an ongoing project; no proper docs
* yet, and no manpage (yet!) - the code is documentation,
* while the specification that it implements evolves.
*/
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "include/common.h"
static void
exit_cleanup(void);
int
main(int argc, char *argv[])
{
#ifndef __linux__
#error This code is currently buggy on BSD systems. Only use on Linux.
#endif
size_t len;
size_t tlen;
size_t xc = 0;
char *tmpdir = NULL;
char *template = NULL;
char *p;
char *s = NULL;
char *rp;
char resolved[PATH_MAX];
char c;
int fd = -1;
int type = MKHTEMP_FILE;
(void) errhook(exit_cleanup);
(void) lbsetprogname(argv[0]);
#ifdef __OpenBSD__
/* https://man.openbsd.org/pledge.2 */
if (pledge("stdio flock rpath wpath cpath fattr", NULL) == -1)
exitf("pledge");
#endif
while ((c =
getopt(argc, argv, "qdp:")) != -1) {
switch (c) {
case 'd':
type = MKHTEMP_DIR;
break;
case 'p':
tmpdir = optarg;
break;
case 'q': /* don't print errors */
/* (exit status unchanged) */
break;
default:
goto err_usage;
}
}
if (optind < argc)
template = argv[optind];
if (optind + 1 < argc)
goto err_usage;
/* custom template e.g. foo.XXXXXXXXXXXXXXXXXXXXX */
if (template != NULL) {
for (p = template + slen(template, PATH_MAX, &tlen);
p > template && *--p == 'X'; xc++);
if (xc < 3) /* the gnu mktemp errs on less than 3 */
exitf(
"template must have 3 X or more on end (12+ advised");
}
/* user supplied -p PATH - WARNING:
* this permits symlinks, but only here,
* not in the library, so they are resolved
* here first, and *only here*. the mkhtemp
* library blocks them. be careful
* when using -p
*/
if (tmpdir != NULL) {
rp = realpath(tmpdir, resolved);
if (rp == NULL)
exitf("%s", tmpdir);
tmpdir = resolved;
}
if (new_tmp_common(&fd, &s, type,
tmpdir, template) < 0)
exitf("%s", s);
#ifdef __OpenBSD__
if (pledge("stdio", NULL) == -1)
exitf("pledge");
#endif
if (s == NULL)
exitf("bad string initialisation");
if (*s == '\0')
exitf("empty string initialisation");
slen(s, PATH_MAX, &len); /* Nullterminierung prüfen */
/* for good measure. (bonus: also re-checks length overflow) */
printf("%s\n", s);
return EXIT_SUCCESS;
err_usage:
exitf(
"usage: %s [-d] [-p dir] [template]\n", lbgetprogname());
}
static void
exit_cleanup(void)
{
return;
}
-134
View File
@@ -1,134 +0,0 @@
/* SPDX-License-Identifier: MIT ( >:3 )
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org> /| |\
* / \
* This tool lets you modify Intel GbE NVM (Gigabit Ethernet
* Non-Volatile Memory) images, e.g. change the MAC address.
* These images configure your Intel Gigabit Ethernet adapter.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "include/common.h"
static void
exit_cleanup(void);
int
main(int argc, char *argv[])
{
#ifndef __linux__
#error This code is currently buggy on BSD systems. Only use on Linux.
#endif
struct xstate *x;
struct commands *cmd;
struct xfile *f;
size_t c;
(void) lbsetprogname(argv[0]);
if (argc < 3)
usage();
(void) errhook(exit_cleanup);
#ifdef __OpenBSD
/* https://man.openbsd.org/pledge.2 */
/* https://man.openbsd.org/unveil.2 */
if (pledge("stdio flock rpath wpath cpath unveil", NULL) == -1)
exitf("pledge");
if (unveil("/dev/urandom", "r") == -1)
exitf("unveil");
#endif
#ifndef S_ISREG
exitf(
"Can't determine file types (S_ISREG undefined)");
#endif
#if ((CHAR_BIT) != 8)
exitf("Unsupported char size");
#endif
if ((x = xstart(argc, argv)) == NULL)
exitf("NULL state on init");
/* parse user command */
/* TODO: CHECK ACCESSES VIA xstatus() */
set_cmd(argc, argv);
set_cmd_args(argc, argv);
cmd = &x->cmd[x->i];
f = &x->f;
#ifdef __OpenBSD__
if ((cmd->flags & O_ACCMODE) == O_RDONLY) {
if (unveil(f->fname, "r") == -1)
exitf("unveil");
} else {
if (unveil(f->fname, "rwc") == -1)
exitf("unveil");
}
if (unveil(f->tname, "rwc") == -1)
exitf("unveil");
if (unveil(NULL, NULL) == -1)
exitf("unveil");
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
exitf("pledge");
#endif
if (cmd->run == NULL)
exitf("Command not set");
sanitize_command_list();
open_gbe_file();
copy_gbe();
read_checksums();
cmd->run();
for (c = 0; c < items(x->cmd); c++)
x->cmd[c].run = cmd_helper_err;
if ((cmd->flags & O_ACCMODE) == O_RDWR)
write_to_gbe_bin();
exit_cleanup();
if (f->io_err_gbe_bin)
exitf("%s: error writing final file");
free_and_set_null(&f->tname);
return EXIT_SUCCESS;
}
static void
exit_cleanup(void)
{
struct xstate *x;
struct xfile *f;
x = xstatus();
if (x == NULL)
return;
f = &x->f;
/* close fds if still open */
xclose(&f->tmp_fd);
xclose(&f->gbe_fd);
/* unlink tmpfile if it exists */
if (f->tname != NULL) {
(void) unlink(f->tname);
free_and_set_null(&f->tname);
}
}