@@ -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,36 +88,37 @@ 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 ] ) ;
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
+ } ;
78
111
79
112
info ! ( "Protocol = 0x{:x}" , protocol) ;
80
113
81
114
let mut initrd_max = if protocol >= 0x20c
82
- && ( LittleEndian :: read_u32 ( & kernel[ 0x236 .. 0x236 + 4 ] )
115
+ && ( LittleEndian :: read_u16 ( & kernel[ offsets :: XLOAD_FLAGS ] )
83
116
& XLoadFlags :: CAN_BE_LOADED_ABOVE_4G . bits ( ) )
84
117
!= 0
85
118
{
86
119
0xffffffff
87
120
} else if protocol >= 0x203 {
88
- LittleEndian :: read_u32 ( & kernel[ 0x22c .. 0x22c + 4 ] )
121
+ LittleEndian :: read_u32 ( & kernel[ offsets :: INITRD_ADDR_MAX ] )
89
122
} else {
90
123
0x37ffffff
91
124
} ;
@@ -101,11 +134,17 @@ pub fn load_linux(
101
134
builder. add_i32 ( FwCfgSelector :: CMDLINE_SIZE , cmdline. len ( ) as i32 ) ;
102
135
103
136
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
+ ) ;
105
141
} 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
+ ) ;
107
146
LittleEndian :: write_i16 (
108
- & mut kernel[ 0x22 .. 0x22 + 2 ] ,
147
+ & mut kernel[ offsets :: OLD_CMD_LINE_OFFSET ] ,
109
148
( cmdline_addr - real_addr) as i16 ,
110
149
) ;
111
150
}
@@ -115,14 +154,14 @@ pub fn load_linux(
115
154
// loader type
116
155
// TODO: change this from QEMU probably
117
156
if protocol >= 0x200 {
118
- kernel[ 0x210 ] = 0xB0 ;
157
+ kernel[ offsets :: TYPE_OF_LOADER ] = QEMU_LOADER ;
119
158
}
120
159
121
160
// Heap
122
161
if protocol >= 0x201 {
123
- kernel[ 0x211 ] |= 0x80 ;
162
+ kernel[ offsets :: LOAD_FLAGS ] |= LoadFlags :: CAN_USE_HEAP . bits ( ) ;
124
163
LittleEndian :: write_i16 (
125
- & mut kernel[ 0x224 .. 0x224 + 2 ] ,
164
+ & mut kernel[ offsets :: HEAP_END_PTR ] ,
126
165
( cmdline_addr - real_addr - 0x200 ) as i16 ,
127
166
) ;
128
167
}
@@ -145,13 +184,13 @@ pub fn load_linux(
145
184
builder. add_i32 ( FwCfgSelector :: INITRD_ADDR , initrd_addr) ;
146
185
builder. add_i32 ( FwCfgSelector :: INITRD_SIZE , initramfs. len ( ) as i32 ) ;
147
186
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) ;
149
188
LittleEndian :: write_i32 (
150
- & mut kernel[ 0x21c .. 0x21c + 4 ] ,
189
+ & mut kernel[ offsets :: RAMDISK_SIZE ] ,
151
190
initramfs. len ( ) as i32 ,
152
191
) ;
153
192
154
- let setup_size = match kernel[ 0x1f1 ] {
193
+ let setup_size = match kernel[ offsets :: SETUP_SECTS ] {
155
194
// For legacy compat, setup size 0 is really 4 sectors
156
195
0 => 4 + 1 ,
157
196
size => size + 1 ,
0 commit comments