@@ -4,13 +4,45 @@ use crate::virtdev::qemu_fw_cfg::{FwCfgSelector, QemuFwCfgBuilder};
4
4
use bitflags:: bitflags;
5
5
use byteorder:: { ByteOrder , LittleEndian } ;
6
6
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
+
7
29
// This blob is taken from QEMU. See:
8
30
// https://github.com/qemu/qemu/blob/887adde81d1f1f3897f1688d37ec6851b4fdad86/pc-bios/optionrom/linuxboot_dma.c
9
31
pub const LINUXBOOT_DMA_ROM : & ' static [ u8 ] =
10
32
include_bytes ! ( "blob/linuxboot_dma.bin" ) ;
11
33
12
34
bitflags ! {
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 {
14
46
const KERNEL_64 = 1 << 0 ;
15
47
const CAN_BE_LOADED_ABOVE_4G = 1 << 1 ;
16
48
const EFI_HANDOVER_32 = 1 << 2 ;
@@ -56,19 +88,19 @@ pub fn load_linux(
56
88
) ) ) ;
57
89
}
58
90
59
- let magic = LittleEndian :: read_u32 ( & kernel[ 0x202 .. 0x202 + 4 ] ) ;
91
+ let magic = LittleEndian :: read_u32 ( & kernel[ offsets :: HEADER_MAGIC ] ) ;
60
92
61
93
// HdrS
62
- if magic != 0x53726448 {
94
+ if magic != HEADER_MAGIC_VALUE {
63
95
return Err ( Error :: InvalidValue ( format ! (
64
96
"Invalid kernel image (bad magic = 0x{:x})" ,
65
97
magic
66
98
) ) ) ;
67
99
}
68
100
69
- let protocol = LittleEndian :: read_u16 ( & kernel[ 0x206 .. 0x206 + 2 ] ) ;
101
+ let protocol = LittleEndian :: read_u16 ( & kernel[ offsets :: BOOTP_VERSION ] ) ;
70
102
let ( real_addr, cmdline_addr, prot_addr) =
71
- if protocol < 0x200 || ( kernel[ 0x211 ] & 0x01 ) == 0 {
103
+ if protocol < 0x200 || ( kernel[ offsets :: LOAD_FLAGS ] & LoadFlags :: LOADED_HIGH . bits ( ) ) == 0 {
72
104
( 0x90000 , 0x9a000 - cmdline. len ( ) as i32 , 0x10000 )
73
105
} else if protocol < 0x202 {
74
106
( 0x90000 , 0x9a000 - cmdline. len ( ) as i32 , 0x100000 )
@@ -79,13 +111,13 @@ pub fn load_linux(
79
111
info ! ( "Protocol = 0x{:x}" , protocol) ;
80
112
81
113
let mut initrd_max = if protocol >= 0x20c
82
- && ( LittleEndian :: read_u32 ( & kernel[ 0x236 .. 0x236 + 4 ] )
114
+ && ( LittleEndian :: read_u16 ( & kernel[ offsets :: XLOAD_FLAGS ] )
83
115
& XLoadFlags :: CAN_BE_LOADED_ABOVE_4G . bits ( ) )
84
116
!= 0
85
117
{
86
118
0xffffffff
87
119
} else if protocol >= 0x203 {
88
- LittleEndian :: read_u32 ( & kernel[ 0x22c .. 0x22c + 4 ] )
120
+ LittleEndian :: read_u32 ( & kernel[ offsets :: INITRD_ADDR_MAX ] )
89
121
} else {
90
122
0x37ffffff
91
123
} ;
@@ -101,11 +133,12 @@ pub fn load_linux(
101
133
builder. add_i32 ( FwCfgSelector :: CMDLINE_SIZE , cmdline. len ( ) as i32 ) ;
102
134
103
135
if protocol >= 0x202 {
104
- LittleEndian :: write_i32 ( & mut kernel[ 0x228 .. 0x228 + 4 ] , cmdline_addr) ;
136
+ LittleEndian :: write_i32 ( & mut kernel[ offsets :: CMD_LINE_PTR ] , cmdline_addr) ;
105
137
} else {
106
- LittleEndian :: write_u16 ( & mut kernel[ 0x20 ..0x20 + 2 ] , 0xa33f ) ;
138
+ LittleEndian :: write_u16 ( & mut kernel[ offsets:: OLD_CMD_LINE_MAGIC ] ,
139
+ OLD_CMD_LINE_MAGIC_VALUE ) ;
107
140
LittleEndian :: write_i16 (
108
- & mut kernel[ 0x22 .. 0x22 + 2 ] ,
141
+ & mut kernel[ offsets :: OLD_CMD_LINE_OFFSET ] ,
109
142
( cmdline_addr - real_addr) as i16 ,
110
143
) ;
111
144
}
@@ -115,14 +148,14 @@ pub fn load_linux(
115
148
// loader type
116
149
// TODO: change this from QEMU probably
117
150
if protocol >= 0x200 {
118
- kernel[ 0x210 ] = 0xB0 ;
151
+ kernel[ offsets :: TYPE_OF_LOADER ] = QEMU_LOADER ;
119
152
}
120
153
121
154
// Heap
122
155
if protocol >= 0x201 {
123
- kernel[ 0x211 ] |= 0x80 ;
156
+ kernel[ offsets :: LOAD_FLAGS ] |= LoadFlags :: CAN_USE_HEAP . bits ( ) ;
124
157
LittleEndian :: write_i16 (
125
- & mut kernel[ 0x224 .. 0x224 + 2 ] ,
158
+ & mut kernel[ offsets :: HEAP_END_PTR ] ,
126
159
( cmdline_addr - real_addr - 0x200 ) as i16 ,
127
160
) ;
128
161
}
@@ -145,13 +178,13 @@ pub fn load_linux(
145
178
builder. add_i32 ( FwCfgSelector :: INITRD_ADDR , initrd_addr) ;
146
179
builder. add_i32 ( FwCfgSelector :: INITRD_SIZE , initramfs. len ( ) as i32 ) ;
147
180
builder. add_bytes ( FwCfgSelector :: INITRD_DATA , initramfs) ;
148
- LittleEndian :: write_i32 ( & mut kernel[ 0x218 .. 0x218 + 4 ] , initrd_addr) ;
181
+ LittleEndian :: write_i32 ( & mut kernel[ offsets :: RAMDISK_IMAGE ] , initrd_addr) ;
149
182
LittleEndian :: write_i32 (
150
- & mut kernel[ 0x21c .. 0x21c + 4 ] ,
183
+ & mut kernel[ offsets :: RAMDISK_SIZE ] ,
151
184
initramfs. len ( ) as i32 ,
152
185
) ;
153
186
154
- let setup_size = match kernel[ 0x1f1 ] {
187
+ let setup_size = match kernel[ offsets :: SETUP_SECTS ] {
155
188
// For legacy compat, setup size 0 is really 4 sectors
156
189
0 => 4 + 1 ,
157
190
size => size + 1 ,
0 commit comments