@@ -4,13 +4,45 @@ use crate::virtdev::qemu_fw_cfg::{FwCfgSelector, QemuFwCfgBuilder};
44use bitflags:: bitflags;
55use byteorder:: { ByteOrder , LittleEndian } ;
66
7+ // These come mostly from https://www.kernel.org/doc/Documentation/x86/boot.txt
8+ mod offsets {
9+ use core:: ops:: Range ;
10+ pub const OLD_CMD_LINE_MAGIC : Range < usize > = 0x20 ..0x22 ;
11+ pub const SETUP_SECTS : usize = 0x1f1 ;
12+ pub const OLD_CMD_LINE_OFFSET : Range < usize > = 0x22 ..0x24 ;
13+ pub const HEADER_MAGIC : Range < usize > = 0x202 ..0x206 ;
14+ pub const BOOTP_VERSION : Range < usize > = 0x206 ..0x208 ;
15+ pub const TYPE_OF_LOADER : usize = 0x210 ;
16+ pub const LOAD_FLAGS : usize = 0x211 ;
17+ pub const RAMDISK_IMAGE : Range < usize > = 0x218 ..0x21c ;
18+ pub const RAMDISK_SIZE : Range < usize > = 0x21c ..0x220 ;
19+ pub const HEAP_END_PTR : Range < usize > = 0x224 ..0x226 ;
20+ pub const CMD_LINE_PTR : Range < usize > = 0x228 ..0x22c ;
21+ pub const INITRD_ADDR_MAX : Range < usize > = 0x22c ..0x230 ;
22+ pub const XLOAD_FLAGS : Range < usize > = 0x236 ..0x238 ;
23+ }
24+
25+ const HEADER_MAGIC_VALUE : u32 = 0x53726448 ; // "HdrS"
26+ const OLD_CMD_LINE_MAGIC_VALUE : u16 = 0xa33f ;
27+ const QEMU_LOADER : u8 = 0xb0 ;
28+
729// This blob is taken from QEMU. See:
830// https://github.com/qemu/qemu/blob/887adde81d1f1f3897f1688d37ec6851b4fdad86/pc-bios/optionrom/linuxboot_dma.c
931pub const LINUXBOOT_DMA_ROM : & ' static [ u8 ] =
1032 include_bytes ! ( "blob/linuxboot_dma.bin" ) ;
1133
1234bitflags ! {
13- pub struct XLoadFlags : u32 {
35+ pub struct LoadFlags : u8 {
36+ const LOADED_HIGH = 1 << 0 ;
37+ const KASLR = 1 << 1 ;
38+ const QUIET = 1 << 5 ;
39+ const KEEP_SEGMENTS = 1 << 6 ;
40+ const CAN_USE_HEAP = 1 << 7 ;
41+ }
42+ }
43+
44+ bitflags ! {
45+ pub struct XLoadFlags : u16 {
1446 const KERNEL_64 = 1 << 0 ;
1547 const CAN_BE_LOADED_ABOVE_4G = 1 << 1 ;
1648 const EFI_HANDOVER_32 = 1 << 2 ;
@@ -56,36 +88,37 @@ pub fn load_linux(
5688 ) ) ) ;
5789 }
5890
59- let magic = LittleEndian :: read_u32 ( & kernel[ 0x202 .. 0x202 + 4 ] ) ;
91+ let magic = LittleEndian :: read_u32 ( & kernel[ offsets :: HEADER_MAGIC ] ) ;
6092
6193 // HdrS
62- if magic != 0x53726448 {
94+ if magic != HEADER_MAGIC_VALUE {
6395 return Err ( Error :: InvalidValue ( format ! (
6496 "Invalid kernel image (bad magic = 0x{:x})" ,
6597 magic
6698 ) ) ) ;
6799 }
68100
69- let protocol = LittleEndian :: read_u16 ( & kernel[ 0x206 ..0x206 + 2 ] ) ;
70- let ( real_addr, cmdline_addr, prot_addr) =
71- if protocol < 0x200 || ( kernel[ 0x211 ] & 0x01 ) == 0 {
72- ( 0x90000 , 0x9a000 - cmdline. len ( ) as i32 , 0x10000 )
73- } else if protocol < 0x202 {
74- ( 0x90000 , 0x9a000 - cmdline. len ( ) as i32 , 0x100000 )
75- } else {
76- ( 0x10000 , 0x20000 , 0x100000 )
77- } ;
101+ let protocol = LittleEndian :: read_u16 ( & kernel[ offsets:: BOOTP_VERSION ] ) ;
102+ let ( real_addr, cmdline_addr, prot_addr) = if protocol < 0x200
103+ || ( kernel[ offsets:: LOAD_FLAGS ] & LoadFlags :: LOADED_HIGH . bits ( ) ) == 0
104+ {
105+ ( 0x90000 , 0x9a000 - cmdline. len ( ) as i32 , 0x10000 )
106+ } else if protocol < 0x202 {
107+ ( 0x90000 , 0x9a000 - cmdline. len ( ) as i32 , 0x100000 )
108+ } else {
109+ ( 0x10000 , 0x20000 , 0x100000 )
110+ } ;
78111
79112 info ! ( "Protocol = 0x{:x}" , protocol) ;
80113
81114 let mut initrd_max = if protocol >= 0x20c
82- && ( LittleEndian :: read_u32 ( & kernel[ 0x236 .. 0x236 + 4 ] )
115+ && ( LittleEndian :: read_u16 ( & kernel[ offsets :: XLOAD_FLAGS ] )
83116 & XLoadFlags :: CAN_BE_LOADED_ABOVE_4G . bits ( ) )
84117 != 0
85118 {
86119 0xffffffff
87120 } else if protocol >= 0x203 {
88- LittleEndian :: read_u32 ( & kernel[ 0x22c .. 0x22c + 4 ] )
121+ LittleEndian :: read_u32 ( & kernel[ offsets :: INITRD_ADDR_MAX ] )
89122 } else {
90123 0x37ffffff
91124 } ;
@@ -101,11 +134,17 @@ pub fn load_linux(
101134 builder. add_i32 ( FwCfgSelector :: CMDLINE_SIZE , cmdline. len ( ) as i32 ) ;
102135
103136 if protocol >= 0x202 {
104- LittleEndian :: write_i32 ( & mut kernel[ 0x228 ..0x228 + 4 ] , cmdline_addr) ;
137+ LittleEndian :: write_i32 (
138+ & mut kernel[ offsets:: CMD_LINE_PTR ] ,
139+ cmdline_addr,
140+ ) ;
105141 } else {
106- LittleEndian :: write_u16 ( & mut kernel[ 0x20 ..0x20 + 2 ] , 0xa33f ) ;
142+ LittleEndian :: write_u16 (
143+ & mut kernel[ offsets:: OLD_CMD_LINE_MAGIC ] ,
144+ OLD_CMD_LINE_MAGIC_VALUE ,
145+ ) ;
107146 LittleEndian :: write_i16 (
108- & mut kernel[ 0x22 .. 0x22 + 2 ] ,
147+ & mut kernel[ offsets :: OLD_CMD_LINE_OFFSET ] ,
109148 ( cmdline_addr - real_addr) as i16 ,
110149 ) ;
111150 }
@@ -115,14 +154,14 @@ pub fn load_linux(
115154 // loader type
116155 // TODO: change this from QEMU probably
117156 if protocol >= 0x200 {
118- kernel[ 0x210 ] = 0xB0 ;
157+ kernel[ offsets :: TYPE_OF_LOADER ] = QEMU_LOADER ;
119158 }
120159
121160 // Heap
122161 if protocol >= 0x201 {
123- kernel[ 0x211 ] |= 0x80 ;
162+ kernel[ offsets :: LOAD_FLAGS ] |= LoadFlags :: CAN_USE_HEAP . bits ( ) ;
124163 LittleEndian :: write_i16 (
125- & mut kernel[ 0x224 .. 0x224 + 2 ] ,
164+ & mut kernel[ offsets :: HEAP_END_PTR ] ,
126165 ( cmdline_addr - real_addr - 0x200 ) as i16 ,
127166 ) ;
128167 }
@@ -145,13 +184,13 @@ pub fn load_linux(
145184 builder. add_i32 ( FwCfgSelector :: INITRD_ADDR , initrd_addr) ;
146185 builder. add_i32 ( FwCfgSelector :: INITRD_SIZE , initramfs. len ( ) as i32 ) ;
147186 builder. add_bytes ( FwCfgSelector :: INITRD_DATA , initramfs) ;
148- LittleEndian :: write_i32 ( & mut kernel[ 0x218 .. 0x218 + 4 ] , initrd_addr) ;
187+ LittleEndian :: write_i32 ( & mut kernel[ offsets :: RAMDISK_IMAGE ] , initrd_addr) ;
149188 LittleEndian :: write_i32 (
150- & mut kernel[ 0x21c .. 0x21c + 4 ] ,
189+ & mut kernel[ offsets :: RAMDISK_SIZE ] ,
151190 initramfs. len ( ) as i32 ,
152191 ) ;
153192
154- let setup_size = match kernel[ 0x1f1 ] {
193+ let setup_size = match kernel[ offsets :: SETUP_SECTS ] {
155194 // For legacy compat, setup size 0 is really 4 sectors
156195 0 => 4 + 1 ,
157196 size => size + 1 ,
0 commit comments