@@ -8,6 +8,8 @@ fn main() {
8
8
9
9
#[ cfg( feature = "binary" ) ]
10
10
mod binary {
11
+ use std:: fmt;
12
+
11
13
pub fn main ( ) {
12
14
use llvm_tools_build as llvm_tools;
13
15
use std:: {
@@ -193,7 +195,7 @@ mod binary {
193
195
}
194
196
195
197
// Parse configuration from the kernel's Cargo.toml
196
- let config = match env:: var ( "KERNEL_MANIFEST" ) {
198
+ let config: Config = match env:: var ( "KERNEL_MANIFEST" ) {
197
199
Err ( env:: VarError :: NotPresent ) => {
198
200
panic ! ( "The KERNEL_MANIFEST environment variable must be set for building the bootloader.\n \n \
199
201
Please use `cargo builder` for building.") ;
@@ -213,13 +215,14 @@ mod binary {
213
215
. parse :: < Value > ( )
214
216
. expect ( "failed to parse kernel's Cargo.toml" ) ;
215
217
216
- let table = manifest
218
+ let config_table = manifest
217
219
. get ( "package" )
218
220
. and_then ( |table| table. get ( "metadata" ) )
219
221
. and_then ( |table| table. get ( "bootloader" ) )
220
- . and_then ( |table| table. as_table ( ) ) ;
222
+ . cloned ( )
223
+ . unwrap_or_else ( || toml:: Value :: Table ( toml:: map:: Map :: new ( ) ) ) ;
221
224
222
- table . map ( |t| Config :: parse ( t ) ) . unwrap_or_default ( )
225
+ config_table . try_into ( ) . expect ( "failed to parse config" )
223
226
}
224
227
} ;
225
228
@@ -244,105 +247,92 @@ mod binary {
244
247
println ! ( "cargo:rerun-if-changed=build.rs" ) ;
245
248
}
246
249
247
- include ! ( "src/config.rs" ) ;
250
+ fn val_true ( ) -> bool {
251
+ true
252
+ }
248
253
249
- impl Config {
250
- fn parse ( table : & toml:: value:: Table ) -> Self {
251
- use std:: convert:: TryFrom ;
252
- use toml:: Value ;
254
+ /// Must be always identical with the struct in `src/config.rs`
255
+ ///
256
+ /// This copy is needed because we can't derive Deserialize in the `src/config.rs`
257
+ /// module itself, since cargo currently unifies dependencies (the `toml` crate enables
258
+ /// serde's standard feature).
259
+ #[ derive( Debug , serde:: Deserialize ) ]
260
+ #[ serde( rename_all = "kebab-case" , deny_unknown_fields) ]
261
+ struct Config {
262
+ #[ serde( default ) ]
263
+ pub map_physical_memory : bool ,
264
+ #[ serde( default ) ]
265
+ pub map_page_table_recursively : bool ,
266
+ #[ serde( default = "val_true" ) ]
267
+ pub map_framebuffer : bool ,
268
+ pub kernel_stack_size : Option < AlignedAddress > ,
269
+ pub physical_memory_offset : Option < AlignedAddress > ,
270
+ pub recursive_index : Option < u16 > ,
271
+ pub kernel_stack_address : Option < AlignedAddress > ,
272
+ pub boot_info_address : Option < AlignedAddress > ,
273
+ pub framebuffer_address : Option < AlignedAddress > ,
274
+ }
253
275
254
- let mut config = Self :: default ( ) ;
276
+ struct AlignedAddress ( u64 ) ;
255
277
256
- for ( key, value) in table {
257
- match ( key. as_str ( ) , value. clone ( ) ) {
258
- ( "map-physical-memory" , Value :: Boolean ( b) ) => {
259
- config. map_physical_memory = b;
260
- }
261
- ( "map-page-table-recursively" , Value :: Boolean ( b) ) => {
262
- config. map_page_table_recursively = b;
263
- }
264
- ( "map-framebuffer" , Value :: Boolean ( b) ) => {
265
- config. map_framebuffer = b;
266
- }
267
- ( "kernel-stack-size" , Value :: Integer ( i) ) => {
268
- if i <= 0 {
269
- panic ! ( "`kernel-stack-size` in kernel manifest must be positive" ) ;
270
- } else {
271
- config. kernel_stack_size = Some ( i as u64 ) ;
272
- }
273
- }
278
+ impl fmt:: Debug for AlignedAddress {
279
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
280
+ write ! ( f, "{}" , self . 0 )
281
+ }
282
+ }
274
283
275
- ( "recursive-page-table-index" , Value :: Integer ( i) ) => {
276
- let index = match u16:: try_from ( i) {
277
- Ok ( index) if index < 512 => index,
278
- _other => panic ! (
279
- "`recursive-page-table-index` must be a number between 0 and 512"
280
- ) ,
281
- } ;
282
- config. recursive_index = Some ( index) ;
283
- }
284
+ impl < ' de > serde:: Deserialize < ' de > for AlignedAddress {
285
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
286
+ where
287
+ D : serde:: Deserializer < ' de > ,
288
+ {
289
+ deserializer. deserialize_str ( AlignedAddressVisitor )
290
+ }
291
+ }
284
292
285
- ( "physical-memory-offset" , Value :: Integer ( i) )
286
- | ( "kernel-stack-address" , Value :: Integer ( i) )
287
- | ( "boot-info-address" , Value :: Integer ( i) )
288
- | ( "framebuffer-address" , Value :: Integer ( i) ) => {
289
- panic ! (
290
- "`{0}` in the kernel manifest must be given as a string, \
291
- as toml does not support unsigned 64-bit integers (try `{0} = \" {1}\" `)",
292
- key. as_str( ) ,
293
- i
294
- ) ;
295
- }
296
- ( "physical-memory-offset" , Value :: String ( s) ) => {
297
- config. physical_memory_offset =
298
- Some ( Self :: parse_aligned_addr ( key. as_str ( ) , & s) ) ;
299
- }
300
- ( "kernel-stack-address" , Value :: String ( s) ) => {
301
- config. kernel_stack_address =
302
- Some ( Self :: parse_aligned_addr ( key. as_str ( ) , & s) ) ;
303
- }
304
- ( "boot-info-address" , Value :: String ( s) ) => {
305
- config. boot_info_address = Some ( Self :: parse_aligned_addr ( key. as_str ( ) , & s) ) ;
306
- }
307
- ( "framebuffer-address" , Value :: String ( s) ) => {
308
- config. framebuffer_address =
309
- Some ( Self :: parse_aligned_addr ( key. as_str ( ) , & s) ) ;
310
- }
293
+ /// Helper struct for implementing the `optional_version_deserialize` function.
294
+ struct AlignedAddressVisitor ;
311
295
312
- ( s, _) => {
313
- let help = if s. contains ( "_" ) {
314
- "\n keys use `-` instead of `_`"
315
- } else {
316
- ""
317
- } ;
318
- panic ! ( "unknown bootloader configuration key '{}'{}" , s, help) ;
319
- }
320
- }
321
- }
296
+ impl serde:: de:: Visitor < ' _ > for AlignedAddressVisitor {
297
+ type Value = AlignedAddress ;
298
+
299
+ fn expecting ( & self , formatter : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
300
+ write ! (
301
+ formatter,
302
+ "a page-aligned memory address, either as integer or as decimal or hexadecimal \
303
+ string (e.g. \" 0xffff0000\" ); large addresses must be given as string because \
304
+ TOML does not support unsigned 64-bit integers"
305
+ )
306
+ }
322
307
323
- config
308
+ fn visit_u64 < E > ( self , num : u64 ) -> Result < Self :: Value , E >
309
+ where
310
+ E : serde:: de:: Error ,
311
+ {
312
+ if num % 0x1000 == 0 {
313
+ Ok ( AlignedAddress ( num) )
314
+ } else {
315
+ Err ( serde:: de:: Error :: invalid_value (
316
+ serde:: de:: Unexpected :: Unsigned ( num) ,
317
+ & self ,
318
+ ) )
319
+ }
324
320
}
325
321
326
- fn parse_aligned_addr ( key : & str , value : & str ) -> u64 {
322
+ fn visit_str < E > ( self , value : & str ) -> Result < Self :: Value , E >
323
+ where
324
+ E : serde:: de:: Error ,
325
+ {
327
326
let num = if value. starts_with ( "0x" ) {
328
327
u64:: from_str_radix ( & value[ 2 ..] , 16 )
329
328
} else {
330
329
u64:: from_str_radix ( & value, 10 )
331
- } ;
332
-
333
- let num = num. expect ( & format ! (
334
- "`{}` in the kernel manifest must be an integer (is `{}`)" ,
335
- key, value
336
- ) ) ;
337
-
338
- if num % 0x1000 != 0 {
339
- panic ! (
340
- "`{}` in the kernel manifest must be aligned to 4KiB (is `{}`)" ,
341
- key, value
342
- ) ;
343
- } else {
344
- num
345
330
}
331
+ . map_err ( |_err| {
332
+ serde:: de:: Error :: invalid_value ( serde:: de:: Unexpected :: Str ( value) , & self )
333
+ } ) ?;
334
+
335
+ self . visit_u64 ( num)
346
336
}
347
337
}
348
338
}
0 commit comments