@@ -2,7 +2,7 @@ use anyhow::{anyhow, Context};
22use argh:: FromArgs ;
33use bootloader:: disk_image:: create_disk_image;
44use std:: {
5- fs,
5+ fs, io ,
66 path:: { Path , PathBuf } ,
77 process:: Command ,
88 str:: FromStr ,
@@ -66,14 +66,30 @@ impl FromStr for Firmware {
6666 }
6767}
6868
69+ impl Firmware {
70+ fn uefi ( & self ) -> bool {
71+ match self {
72+ Firmware :: Bios => false ,
73+ Firmware :: Uefi | Firmware :: All => true ,
74+ }
75+ }
76+
77+ fn bios ( & self ) -> bool {
78+ match self {
79+ Firmware :: Bios | Firmware :: All => true ,
80+ Firmware :: Uefi => false ,
81+ }
82+ }
83+ }
84+
6985/// Firmware must be one of `uefi`, `bios`, or `all`.
7086#[ derive( Debug , displaydoc:: Display , Eq , PartialEq , Copy , Clone ) ]
7187struct FirmwareParseError ;
7288
7389fn main ( ) -> anyhow:: Result < ( ) > {
7490 let args: BuildArguments = argh:: from_env ( ) ;
7591
76- if args. firmware == Firmware :: Uefi || args . firmware == Firmware :: All {
92+ if args. firmware . uefi ( ) {
7793 let build_or_run = if args. run { "run" } else { "build" } ;
7894 let mut cmd = Command :: new ( env ! ( "CARGO" ) ) ;
7995 cmd. arg ( build_or_run) . arg ( "--bin" ) . arg ( "uefi" ) ;
@@ -91,9 +107,81 @@ fn main() -> anyhow::Result<()> {
91107 cmd. env ( "KERNEL" , & args. kernel_binary ) ;
92108 cmd. env ( "KERNEL_MANIFEST" , & args. kernel_manifest ) ;
93109 assert ! ( cmd. status( ) ?. success( ) ) ;
110+
111+ // Retrieve binary paths
112+ cmd. arg ( "--message-format" ) . arg ( "json" ) ;
113+ let output = cmd
114+ . output ( )
115+ . context ( "failed to execute kernel build with json output" ) ?;
116+ if !output. status . success ( ) {
117+ return Err ( anyhow ! ( "{}" , String :: from_utf8_lossy( & output. stderr) ) ) ;
118+ }
119+ let mut executables = Vec :: new ( ) ;
120+ for line in String :: from_utf8 ( output. stdout )
121+ . context ( "build JSON output is not valid UTF-8" ) ?
122+ . lines ( )
123+ {
124+ let mut artifact = json:: parse ( line) . context ( "build JSON output is not valid JSON" ) ?;
125+ if let Some ( executable) = artifact[ "executable" ] . take_string ( ) {
126+ executables. push ( PathBuf :: from ( executable) ) ;
127+ }
128+ }
129+
130+ assert_eq ! ( executables. len( ) , 1 ) ;
131+ 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+ if let Some ( out_dir) = & args. out_dir {
136+ let efi_file =
137+ 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+ }
181+ }
94182 }
95183
96- if args. firmware == Firmware :: Bios || args . firmware == Firmware :: All {
184+ if args. firmware . bios ( ) {
97185 let mut cmd = Command :: new ( env ! ( "CARGO" ) ) ;
98186 cmd. arg ( "build" ) . arg ( "--bin" ) . arg ( "bios" ) ;
99187 cmd. arg ( "--profile" ) . arg ( "release" ) ;
0 commit comments