1
- use anyhow:: { anyhow, Context } ;
1
+ use anyhow:: { anyhow, bail , Context } ;
2
2
use argh:: FromArgs ;
3
3
use bootloader:: disk_image:: create_disk_image;
4
4
use std:: {
5
- fs, io,
5
+ convert:: TryFrom ,
6
+ fs:: { self , File } ,
7
+ io:: { self , Seek } ,
6
8
path:: { Path , PathBuf } ,
7
9
process:: Command ,
8
10
str:: FromStr ,
@@ -129,55 +131,32 @@ fn main() -> anyhow::Result<()> {
129
131
130
132
assert_eq ! ( executables. len( ) , 1 ) ;
131
133
let executable_path = executables. pop ( ) . unwrap ( ) ;
132
- let executable_name = executable_path. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
133
- let kernel_name = args. kernel_binary . file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
134
+
135
+ let executable_name = executable_path
136
+ . file_stem ( )
137
+ . and_then ( |stem| stem. to_str ( ) )
138
+ . ok_or_else ( || {
139
+ anyhow ! (
140
+ "executable path `{}` has invalid file stem" ,
141
+ executable_path. display( )
142
+ )
143
+ } ) ?;
144
+ let kernel_name = args
145
+ . kernel_binary
146
+ . file_name ( )
147
+ . and_then ( |name| name. to_str ( ) )
148
+ . ok_or_else ( || {
149
+ anyhow ! (
150
+ "kernel binary path `{}` has invalid file name" ,
151
+ args. kernel_binary. display( )
152
+ )
153
+ } ) ?;
134
154
135
155
if let Some ( out_dir) = & args. out_dir {
136
156
let efi_file =
137
157
out_dir. join ( format ! ( "bootimage-{}-{}.efi" , executable_name, kernel_name) ) ;
138
- fs:: copy ( & executable_path, & efi_file) . context ( "failed to copy efi file to out dir" ) ?;
139
-
140
- let efi_size = fs:: metadata ( & efi_file)
141
- . context ( "failed to read metadata of efi file" ) ?
142
- . len ( ) ;
143
-
144
- // create fat partition
145
- {
146
- const MB : u64 = 1024 * 1024 ;
147
-
148
- let fat_path = efi_file. with_extension ( "fat" ) ;
149
- dbg ! ( & fat_path) ;
150
- let fat_file = fs:: OpenOptions :: new ( )
151
- . read ( true )
152
- . write ( true )
153
- . create ( true )
154
- . truncate ( true )
155
- . open ( & fat_path)
156
- . context ( "Failed to create UEFI FAT file" ) ?;
157
- let efi_size_rounded = ( ( efi_size - 1 ) / MB + 1 ) * MB ;
158
- fat_file
159
- . set_len ( dbg ! ( efi_size_rounded) )
160
- . context ( "failed to set UEFI FAT file length" ) ?;
161
-
162
- // create new FAT partition
163
- fatfs:: format_volume ( & fat_file, fatfs:: FormatVolumeOptions :: new ( ) )
164
- . context ( "Failed to format UEFI FAT file" ) ?;
165
-
166
- // copy EFI file to FAT filesystem
167
- let partition = fatfs:: FileSystem :: new ( & fat_file, fatfs:: FsOptions :: new ( ) )
168
- . context ( "Failed to open FAT file system of UEFI FAT file" ) ?;
169
- let root_dir = partition. root_dir ( ) ;
170
- root_dir. create_dir ( "efi" ) ?;
171
- root_dir. create_dir ( "efi/boot" ) ?;
172
- let mut bootx64 = root_dir. create_file ( "efi/boot/bootx64.efi" ) ?;
173
- bootx64. truncate ( ) ?;
174
- io:: copy ( & mut fs:: File :: open ( & executable_path) ?, & mut bootx64) ?;
175
- }
176
-
177
- // create gpt disk
178
- {
179
- //todo!()
180
- }
158
+ create_uefi_disk_image ( & executable_path, & efi_file)
159
+ . context ( "failed to create UEFI disk image" ) ?;
181
160
}
182
161
}
183
162
@@ -228,7 +207,7 @@ fn main() -> anyhow::Result<()> {
228
207
let mut output_bin_path = executable_path
229
208
. parent ( )
230
209
. unwrap ( )
231
- . join ( format ! ( "bootimage-{}-{}.bin " , executable_name, kernel_name) ) ;
210
+ . join ( format ! ( "bootimage-{}-{}.img " , executable_name, kernel_name) ) ;
232
211
233
212
create_disk_image ( & executable_path, & output_bin_path)
234
213
. context ( "Failed to create bootable disk image" ) ?;
@@ -254,6 +233,132 @@ fn main() -> anyhow::Result<()> {
254
233
Ok ( ( ) )
255
234
}
256
235
236
+ fn create_uefi_disk_image ( executable_path : & Path , efi_file : & Path ) -> anyhow:: Result < ( ) > {
237
+ fs:: copy ( & executable_path, & efi_file) . context ( "failed to copy efi file to out dir" ) ?;
238
+
239
+ let efi_size = fs:: metadata ( & efi_file)
240
+ . context ( "failed to read metadata of efi file" ) ?
241
+ . len ( ) ;
242
+
243
+ // create fat partition
244
+ let fat_file_path = {
245
+ const MB : u64 = 1024 * 1024 ;
246
+
247
+ let fat_path = efi_file. with_extension ( "fat" ) ;
248
+ let fat_file = fs:: OpenOptions :: new ( )
249
+ . read ( true )
250
+ . write ( true )
251
+ . create ( true )
252
+ . truncate ( true )
253
+ . open ( & fat_path)
254
+ . context ( "Failed to create UEFI FAT file" ) ?;
255
+ let efi_size_rounded = ( ( efi_size - 1 ) / MB + 1 ) * MB ;
256
+ fat_file
257
+ . set_len ( efi_size_rounded)
258
+ . context ( "failed to set UEFI FAT file length" ) ?;
259
+
260
+ // create new FAT partition
261
+ let format_options = fatfs:: FormatVolumeOptions :: new ( ) . volume_label ( * b"FOOO " ) ;
262
+ fatfs:: format_volume ( & fat_file, format_options)
263
+ . context ( "Failed to format UEFI FAT file" ) ?;
264
+
265
+ // copy EFI file to FAT filesystem
266
+ let partition = fatfs:: FileSystem :: new ( & fat_file, fatfs:: FsOptions :: new ( ) )
267
+ . context ( "Failed to open FAT file system of UEFI FAT file" ) ?;
268
+ let root_dir = partition. root_dir ( ) ;
269
+ root_dir. create_dir ( "efi" ) ?;
270
+ root_dir. create_dir ( "efi/boot" ) ?;
271
+ let mut bootx64 = root_dir. create_file ( "efi/boot/bootx64.efi" ) ?;
272
+ bootx64. truncate ( ) ?;
273
+ io:: copy ( & mut fs:: File :: open ( & executable_path) ?, & mut bootx64) ?;
274
+
275
+ fat_path
276
+ } ;
277
+
278
+ // create gpt disk
279
+ {
280
+ let image_path = efi_file. with_extension ( "img" ) ;
281
+ let mut image = fs:: OpenOptions :: new ( )
282
+ . create ( true )
283
+ . truncate ( true )
284
+ . read ( true )
285
+ . write ( true )
286
+ . open ( & image_path)
287
+ . context ( "failed to create UEFI disk image" ) ?;
288
+
289
+ let partition_size: u64 = fs:: metadata ( & fat_file_path)
290
+ . context ( "failed to read metadata of UEFI FAT partition" ) ?
291
+ . len ( ) ;
292
+ let image_size = partition_size + 1024 * 64 ;
293
+ image
294
+ . set_len ( image_size)
295
+ . context ( "failed to set length of UEFI disk image" ) ?;
296
+
297
+ // Create a protective MBR at LBA0
298
+ let mbr = gpt:: mbr:: ProtectiveMBR :: with_lb_size (
299
+ u32:: try_from ( ( image_size / 512 ) - 1 ) . unwrap_or ( 0xFF_FF_FF_FF ) ,
300
+ ) ;
301
+ mbr. overwrite_lba0 ( & mut image)
302
+ . context ( "failed to write protective MBR" ) ?;
303
+
304
+ // create new GPT in image file
305
+ let block_size = gpt:: disk:: LogicalBlockSize :: Lb512 ;
306
+ let block_size_bytes: u64 = block_size. into ( ) ;
307
+ let mut disk = gpt:: GptConfig :: new ( )
308
+ . writable ( true )
309
+ . initialized ( false )
310
+ . logical_block_size ( block_size)
311
+ . create_from_device ( Box :: new ( & mut image) , None )
312
+ . context ( "failed to open UEFI disk image" ) ?;
313
+ disk. update_partitions ( Default :: default ( ) )
314
+ . context ( "failed to initialize GPT partition table" ) ?;
315
+
316
+ // add add EFI system partition
317
+ let partition_id = disk
318
+ . add_partition ( "boot" , partition_size, gpt:: partition_types:: EFI , 0 )
319
+ . context ( "failed to add boot partition" ) ?;
320
+
321
+ let partition = disk
322
+ . partitions ( )
323
+ . get ( & partition_id)
324
+ . ok_or_else ( || anyhow ! ( "Partition doesn't exist after adding it" ) ) ?;
325
+ let created_partition_size: u64 =
326
+ ( partition. last_lba - partition. first_lba + 1u64 ) * block_size_bytes;
327
+ if created_partition_size != partition_size {
328
+ bail ! (
329
+ "Created partition has invalid size (size is {:?}, expected {})" ,
330
+ created_partition_size,
331
+ partition_size
332
+ ) ;
333
+ }
334
+ let start_offset = partition
335
+ . bytes_start ( block_size)
336
+ . context ( "failed to retrieve partition start offset" ) ?;
337
+
338
+ // Write the partition table
339
+ disk. write ( )
340
+ . context ( "failed to write GPT partition table to UEFI image file" ) ?;
341
+
342
+ image
343
+ . seek ( io:: SeekFrom :: Start ( start_offset) )
344
+ . context ( "failed to seek to boot partiiton start" ) ?;
345
+ let bytes_written = io:: copy (
346
+ & mut File :: open ( & fat_file_path) . context ( "failed to open fat image" ) ?,
347
+ & mut image,
348
+ )
349
+ . context ( "failed to write boot partition content" ) ?;
350
+ if bytes_written != partition_size {
351
+ bail ! (
352
+ "Invalid number of partition bytes written (expected {}, got {})" ,
353
+ partition_size,
354
+ bytes_written
355
+ ) ;
356
+ }
357
+ }
358
+
359
+ Ok ( ( ) )
360
+ }
361
+
257
362
fn bios_run ( bin_path : & Path ) -> anyhow:: Result < Option < ExitCode > > {
258
363
let mut qemu = Command :: new ( "qemu-system-x86_64" ) ;
259
364
qemu. arg ( "-drive" )
0 commit comments