* Merge bootsect.S and setup.S into header.S
Currently, Memtest86+ provides two (three counting mbr.S) different
headers: bootsect.S and header.S that together with setup.S are used
to build the final binaries:
- bootsect.S for booting from the legacy BIOS, used in memtest.bin.
- header.S for booting from the UEFI, used in memtest.efi.
Both support loading by an intermediate bootloader. Also, both are
derived from the Linux kernel, but from a very different chapter in its
evolution. FDD loading was removed a very long time ago, many, many
years before adding PE/COFF headers for UEFI. Also, the PE/COFF headers
are large (even larger for x86-64) and take a lot of very limited space,
leaving almost no headroom for the actual code.
This commit merges bootsect.S and setup.S into header.S adding BIOS
(FDD) loading support, which should eventually enable to maintain a single,
all-in-one binary that can be booted either by an intermediate bootloader
(such as GRUB or LILO), UEFI and BIOS. Easier and less confusing for users,
as I have continued to see cases when people assume memtest.bin is needed
for non-UEFI systems, even if never intended for FDD loading.
To ensure we have enough space for both the boot code (limited to 512B
including Linux boot header and address of the New EXE header) and
UEFI headers, the PE/COFF headers got moved into the ".setup" section
of the code where *currently* we have 1024B total and about 90B free.
Should more space be needed in the future, we can grow that section or
perhaps even better - move PE/COFF into its own section that will not
even need to be loaded.
Overall, the code got copied from bootsect.S and setup.S with very, very
minimal changes, most importantly:
- Dedicated routine for printing strings (print_string) got added and
lives in the ".bootsect" section.
- Print "Loading " message almost immediately after BIOS loads and
calls code from the .bootsect" section, even before setting up
the custom FDD parameter table. The sooner the better.
- Set DX to 0x0000, as the code depends on its value. While the BIOS is
expected to set DL register to the boot drive number which is 0 for FDD,
to my knowledge there is no guarantee for DH to have any particular
value. Also, when executing "MZ" signature as x86 instructions,
the original value of DX becomes instantly and irrevocably lost. This
is fine as we only support booting from FDD anyway.
- Print "Memtest86+" and its version after loading the ".setup" section.
We can get the string from mt86plus_version (kernel_version), no need
to duplicate in the boot sector where we are very space limited and as
a bonus we can provide the version information.
As diffstat shows a lot of code changed and added, it may be easier use
the following commands:
diff -Nur bootsect.S header.S
diff -Nur setup.S header.S
While there are several more changes and fixes I would like to make in the
boot code (some of them were already included in the earlier RFC version
[1] before we got UEFI signing support added) for now I tried this to be as
least disruptive as possible and avoid unnecessary code changes to make
the review easier.
[1] https://github.com/memtest86plus/memtest86plus/pull/136
* Bye bye memtest.bin and memtest.efi, long live mt86plus
With the efi binary providing the BIOS floppy loading functionality,
there is no need to support separate memtest.bin file any longer.
Remove memtest.bin from {build32,build64}/Makefile, replace memtest.bin
amd memtest.efi with mt86plus eveywhere to avoid confusion with
other memtests.
Also, unify build32/Makefile and build64/Makefile by removing
unnecessary differences between them, like extra spaces or
different OBJS order.
Finally, update README.md, HOW_TO_DEBUG_WITH_GDB.md and other
places that had a reference to memtest.{bin,efi}. Note that for
debug_memtest.sh, mt86plus.efi is used.
We have a .setup section in the EFI image that contains the remainder of
the Linux boot header and the real-mode setup code to support booting via
an intermediate bootloader. This sits between the PE header and the .text
section. We don't want the EFI loader to load this section, so simply
increase the SizeOfHeader field in the PE header to cover it.
When the reloc and sbat sections were added by PR #34, three bugs were
introduced:
1. The virtual address and size fields in the PE headers were set to the
same values as the raw address and size fields. This is incorrect, because
the sections in the image file are aligned on 512 byte boundaries, but when
loaded into memory they need to be aligned on 4096 byte boundaries.
2. The value programmed into the SizeOfImage field was too large, as it
double-counted the region before the start of the .text section.
3. The value programmed into the SizeOfImage field no longer included the bss
size. That potentially allowed the EFI loader to load the image immediately
before a reserved region of memory without leaving enough space for the bss
section.
This commit fixes those bugs by calculating both file and virtual memory
offsets & sizes in the ld script. Note that we can't add a bss section to the
EFI image because many EFI loaders fail to load images that have uninitialised
data sections. Instead the text region size in virtual memory is increased
to include the bss size.
This fixes issue #243. It also eliminates the gaps between sections
observed in issue #202.
This patch adds a new section, ".sbat", which allows for the revocation
of signed binaries given a numeric value representing the set of bugs
which allow for arbitrary code execution, and therefore a Secure Boot
breakout, in a given family of binaries.
In this case, the class is defined as "memtest86+", and the current set
of bugs is 1. This doesn't imply that we're aware of bugs currently,
merely that when we change it to 2, any bugs that /have/ been discovered
have been fixed.
Documentation for how SBAT works can be found at the following URLs:
https://github.com/rhboot/shim/blob/main/SBAT.mdhttps://github.com/rhboot/shim/blob/main/SBAT.example.md
Signed-off-by: Peter Jones <pjones@redhat.com>
In the past, we've seen some problems with some EFI loaders refusing to
load a binary that has both a .text section with the VMA set and no
relocations, when the VMA set to load is already allocated for some
other purpose.
This patch adds a dummy absolute relocation from 0 to 0, so the loader
can always feel like it has done something useful.
Signed-off-by: Peter Jones <pjones@redhat.com>
SizeOfImage is defined as:
The size (in bytes) of the image, including all headers, as the image
is loaded in memory. It must be a multiple of SectionAlignment.
SizeOfHeaders likewise is defined as:
The combined size of an MS-DOS stub, PE header, and section headers
rounded up to a multiple of FileAlignment.
Currently SizeOfImage represents .bss and .text, but it doesn't include
.header or .setup, nor any sections we'll add later, and there's nothing
enforcing that it matches SectionAlignment. Additionally, since .bss is
being set up in our running code and /not/ by the loader, the current
value is dangerously high, as in the event there is an error in the
section table, it could potentially lead the loader to mark memory
allocated at runtime holding user-supplied data by any EFI binary loaded
before us as executable.
This patch adds a new symbol, _img_end, which is after .text and is
rounded up to 4kB (which is also what SectionAlignment is set to). It
also adds a local label, anchored with ".org 512", and uses that to set
SizeOfHeaders - this will ensure the build fails without outputting and
invalid binary if the headers take too much space.
Signed-off-by: Peter Jones <pjones@redhat.com>
When using a legacy BIOS, the memory regions used by the BIOS are well
defined. This is not the case when using a UEFI BIOS. So include the
stack area in the BSS so the loader knows how much memory to allocate,
and check we have space to relocate the program to either low or high
memory.
There are still some assumptions in the USB driver code that need to
be fixed.