Skip to content

Commit 2c33c27

Browse files
Daniel Kipersuryasaimadhu
authored andcommitted
x86/boot: Introduce kernel_info
The relationships between the headers are analogous to the various data sections: setup_header = .data boot_params/setup_data = .bss What is missing from the above list? That's right: kernel_info = .rodata We have been (ab)using .data for things that could go into .rodata or .bss for a long time, for lack of alternatives and -- especially early on -- inertia. Also, the BIOS stub is responsible for creating boot_params, so it isn't available to a BIOS-based loader (setup_data is, though). setup_header is permanently limited to 144 bytes due to the reach of the 2-byte jump field, which doubles as a length field for the structure, combined with the size of the "hole" in struct boot_params that a protected-mode loader or the BIOS stub has to copy it into. It is currently 119 bytes long, which leaves us with 25 very precious bytes. This isn't something that can be fixed without revising the boot protocol entirely, breaking backwards compatibility. boot_params proper is limited to 4096 bytes, but can be arbitrarily extended by adding setup_data entries. It cannot be used to communicate properties of the kernel image, because it is .bss and has no image-provided content. kernel_info solves this by providing an extensible place for information about the kernel image. It is readonly, because the kernel cannot rely on a bootloader copying its contents anywhere, but that is OK; if it becomes necessary it can still contain data items that an enabled bootloader would be expected to copy into a setup_data chunk. Do not bump setup_header version in arch/x86/boot/header.S because it will be followed by additional changes coming into the Linux/x86 boot protocol. Suggested-by: H. Peter Anvin (Intel) <[email protected]> Signed-off-by: Daniel Kiper <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Reviewed-by: Konrad Rzeszutek Wilk <[email protected]> Reviewed-by: Ross Philipson <[email protected]> Reviewed-by: H. Peter Anvin (Intel) <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: [email protected] Cc: Boris Ostrovsky <[email protected]> Cc: [email protected] Cc: [email protected] Cc: Ingo Molnar <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Juergen Gross <[email protected]> Cc: [email protected] Cc: [email protected] Cc: linux-efi <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: [email protected] Cc: [email protected] Cc: Thomas Gleixner <[email protected]> Cc: x86-ml <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent c311ed6 commit 2c33c27

File tree

7 files changed

+153
-3
lines changed

7 files changed

+153
-3
lines changed

Documentation/x86/boot.rst

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,25 @@ Protocol 2.12 (Kernel 3.8) Added the xloadflags field and extension fields
6868
Protocol 2.13 (Kernel 3.14) Support 32- and 64-bit flags being set in
6969
xloadflags to support booting a 64-bit kernel from 32-bit
7070
EFI
71+
72+
Protocol 2.14: BURNT BY INCORRECT COMMIT ae7e1238e68f2a472a125673ab506d49158c1889
73+
(x86/boot: Add ACPI RSDP address to setup_header)
74+
DO NOT USE!!! ASSUME SAME AS 2.13.
75+
76+
Protocol 2.15: (Kernel 5.5) Added the kernel_info.
7177
============= ============================================================
7278

79+
.. note::
80+
The protocol version number should be changed only if the setup header
81+
is changed. There is no need to update the version number if boot_params
82+
or kernel_info are changed. Additionally, it is recommended to use
83+
xloadflags (in this case the protocol version number should not be
84+
updated either) or kernel_info to communicate supported Linux kernel
85+
features to the boot loader. Due to very limited space available in
86+
the original setup header every update to it should be considered
87+
with great care. Starting from the protocol 2.15 the primary way to
88+
communicate things to the boot loader is the kernel_info.
89+
7390

7491
Memory Layout
7592
=============
@@ -207,6 +224,7 @@ Offset/Size Proto Name Meaning
207224
0258/8 2.10+ pref_address Preferred loading address
208225
0260/4 2.10+ init_size Linear memory required during initialization
209226
0264/4 2.11+ handover_offset Offset of handover entry point
227+
0268/4 2.15+ kernel_info_offset Offset of the kernel_info
210228
=========== ======== ===================== ============================================
211229

212230
.. note::
@@ -855,6 +873,114 @@ Offset/size: 0x264/4
855873

856874
See EFI HANDOVER PROTOCOL below for more details.
857875

876+
============ ==================
877+
Field name: kernel_info_offset
878+
Type: read
879+
Offset/size: 0x268/4
880+
Protocol: 2.15+
881+
============ ==================
882+
883+
This field is the offset from the beginning of the kernel image to the
884+
kernel_info. The kernel_info structure is embedded in the Linux image
885+
in the uncompressed protected mode region.
886+
887+
888+
The kernel_info
889+
===============
890+
891+
The relationships between the headers are analogous to the various data
892+
sections:
893+
894+
setup_header = .data
895+
boot_params/setup_data = .bss
896+
897+
What is missing from the above list? That's right:
898+
899+
kernel_info = .rodata
900+
901+
We have been (ab)using .data for things that could go into .rodata or .bss for
902+
a long time, for lack of alternatives and -- especially early on -- inertia.
903+
Also, the BIOS stub is responsible for creating boot_params, so it isn't
904+
available to a BIOS-based loader (setup_data is, though).
905+
906+
setup_header is permanently limited to 144 bytes due to the reach of the
907+
2-byte jump field, which doubles as a length field for the structure, combined
908+
with the size of the "hole" in struct boot_params that a protected-mode loader
909+
or the BIOS stub has to copy it into. It is currently 119 bytes long, which
910+
leaves us with 25 very precious bytes. This isn't something that can be fixed
911+
without revising the boot protocol entirely, breaking backwards compatibility.
912+
913+
boot_params proper is limited to 4096 bytes, but can be arbitrarily extended
914+
by adding setup_data entries. It cannot be used to communicate properties of
915+
the kernel image, because it is .bss and has no image-provided content.
916+
917+
kernel_info solves this by providing an extensible place for information about
918+
the kernel image. It is readonly, because the kernel cannot rely on a
919+
bootloader copying its contents anywhere, but that is OK; if it becomes
920+
necessary it can still contain data items that an enabled bootloader would be
921+
expected to copy into a setup_data chunk.
922+
923+
All kernel_info data should be part of this structure. Fixed size data have to
924+
be put before kernel_info_var_len_data label. Variable size data have to be put
925+
after kernel_info_var_len_data label. Each chunk of variable size data has to
926+
be prefixed with header/magic and its size, e.g.:
927+
928+
kernel_info:
929+
.ascii "LToP" /* Header, Linux top (structure). */
930+
.long kernel_info_var_len_data - kernel_info
931+
.long kernel_info_end - kernel_info
932+
.long 0x01234567 /* Some fixed size data for the bootloaders. */
933+
kernel_info_var_len_data:
934+
example_struct: /* Some variable size data for the bootloaders. */
935+
.ascii "0123" /* Header/Magic. */
936+
.long example_struct_end - example_struct
937+
.ascii "Struct"
938+
.long 0x89012345
939+
example_struct_end:
940+
example_strings: /* Some variable size data for the bootloaders. */
941+
.ascii "ABCD" /* Header/Magic. */
942+
.long example_strings_end - example_strings
943+
.asciz "String_0"
944+
.asciz "String_1"
945+
example_strings_end:
946+
kernel_info_end:
947+
948+
This way the kernel_info is self-contained blob.
949+
950+
.. note::
951+
Each variable size data header/magic can be any 4-character string,
952+
without \0 at the end of the string, which does not collide with
953+
existing variable length data headers/magics.
954+
955+
956+
Details of the kernel_info Fields
957+
=================================
958+
959+
============ ========
960+
Field name: header
961+
Offset/size: 0x0000/4
962+
============ ========
963+
964+
Contains the magic number "LToP" (0x506f544c).
965+
966+
============ ========
967+
Field name: size
968+
Offset/size: 0x0004/4
969+
============ ========
970+
971+
This field contains the size of the kernel_info including kernel_info.header.
972+
It does not count kernel_info.kernel_info_var_len_data size. This field should be
973+
used by the bootloaders to detect supported fixed size fields in the kernel_info
974+
and beginning of kernel_info.kernel_info_var_len_data.
975+
976+
============ ========
977+
Field name: size_total
978+
Offset/size: 0x0008/4
979+
============ ========
980+
981+
This field contains the size of the kernel_info including kernel_info.header
982+
and kernel_info.kernel_info_var_len_data.
983+
858984

859985
The Image Checksum
860986
==================

arch/x86/boot/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
8787

8888
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
8989

90-
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
90+
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
9191

9292
quiet_cmd_zoffset = ZOFFSET $@
9393
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@

arch/x86/boot/compressed/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ $(obj)/../voffset.h: vmlinux FORCE
7272

7373
$(obj)/misc.o: $(obj)/../voffset.h
7474

75-
vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
76-
$(obj)/string.o $(obj)/cmdline.o $(obj)/error.o \
75+
vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/kernel_info.o $(obj)/head_$(BITS).o \
76+
$(obj)/misc.o $(obj)/string.o $(obj)/cmdline.o $(obj)/error.o \
7777
$(obj)/piggy.o $(obj)/cpuflags.o
7878

7979
vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
.section ".rodata.kernel_info", "a"
4+
5+
.global kernel_info
6+
7+
kernel_info:
8+
/* Header, Linux top (structure). */
9+
.ascii "LToP"
10+
/* Size. */
11+
.long kernel_info_var_len_data - kernel_info
12+
/* Size total. */
13+
.long kernel_info_end - kernel_info
14+
15+
kernel_info_var_len_data:
16+
/* Empty for time being... */
17+
kernel_info_end:

arch/x86/boot/header.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
567567

568568
init_size: .long INIT_SIZE # kernel initialization size
569569
handover_offset: .long 0 # Filled in by build.c
570+
kernel_info_offset: .long 0 # Filled in by build.c
570571

571572
# End of setup header #####################################################
572573

arch/x86/boot/tools/build.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ u8 buf[SETUP_SECT_MAX*512];
5656
unsigned long efi32_stub_entry;
5757
unsigned long efi64_stub_entry;
5858
unsigned long efi_pe_entry;
59+
unsigned long kernel_info;
5960
unsigned long startup_64;
6061

6162
/*----------------------------------------------------------------------*/
@@ -321,6 +322,7 @@ static void parse_zoffset(char *fname)
321322
PARSE_ZOFS(p, efi32_stub_entry);
322323
PARSE_ZOFS(p, efi64_stub_entry);
323324
PARSE_ZOFS(p, efi_pe_entry);
325+
PARSE_ZOFS(p, kernel_info);
324326
PARSE_ZOFS(p, startup_64);
325327

326328
p = strchr(p, '\n');
@@ -410,6 +412,9 @@ int main(int argc, char ** argv)
410412

411413
efi_stub_entry_update();
412414

415+
/* Update kernel_info offset. */
416+
put_unaligned_le32(kernel_info, &buf[0x268]);
417+
413418
crc = partial_crc32(buf, i, crc);
414419
if (fwrite(buf, 1, i, dest) != i)
415420
die("Writing setup failed");

arch/x86/include/uapi/asm/bootparam.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ struct setup_header {
8888
__u64 pref_address;
8989
__u32 init_size;
9090
__u32 handover_offset;
91+
__u32 kernel_info_offset;
9192
} __attribute__((packed));
9293

9394
struct sys_desc_table {

0 commit comments

Comments
 (0)