11use crate :: tag_type:: { Tag , TagIter , TagType } ;
22use core:: fmt:: { Debug , Formatter } ;
3+ use core:: str:: Utf8Error ;
34
45/// This tag indicates to the kernel what boot module was loaded along with
56/// the kernel image, and where it can be found.
@@ -10,25 +11,24 @@ pub struct ModuleTag {
1011 size : u32 ,
1112 mod_start : u32 ,
1213 mod_end : u32 ,
13- /// Begin of the command line string.
14+ /// Null-terminated UTF-8 string
1415 cmdline_str : u8 ,
1516}
1617
1718impl ModuleTag {
18- // The multiboot specification defines the module str as valid utf-8 (zero terminated string),
19- // therefore this function produces defined behavior
20- /// Get the cmdline of the module. If the GRUB configuration contains
21- /// `module2 /foobar/some_boot_module --test cmdline-option`, then this method
19+ /// Returns the cmdline of the module.
20+ /// This is an null-terminated UTF-8 string. If this returns `Err` then perhaps the memory
21+ /// is invalid or the bootloader doesn't follow the spec.
22+ ///
23+ /// For example: If the GRUB configuration contains
24+ /// `module2 /foobar/some_boot_module --test cmdline-option` then this method
2225 /// will return `--test cmdline-option`.
23- pub fn cmdline ( & self ) -> & str {
26+ pub fn cmdline ( & self ) -> Result < & str , Utf8Error > {
2427 use core:: { mem, slice, str} ;
28+ // strlen without null byte
2529 let strlen = self . size as usize - mem:: size_of :: < ModuleTag > ( ) ;
26- unsafe {
27- str:: from_utf8_unchecked ( slice:: from_raw_parts (
28- & self . cmdline_str as * const u8 ,
29- strlen,
30- ) )
31- }
30+ let bytes = unsafe { slice:: from_raw_parts ( ( & self . cmdline_str ) as * const u8 , strlen) } ;
31+ str:: from_utf8 ( bytes)
3232 }
3333
3434 /// Start address of the module.
@@ -89,3 +89,39 @@ impl<'a> Debug for ModuleIter<'a> {
8989 list. finish ( )
9090 }
9191}
92+
93+ #[ cfg( test) ]
94+ mod tests {
95+ use crate :: TagType ;
96+
97+ const MSG : & str = "hello" ;
98+
99+ /// Returns the tag structure in bytes in native endian format.
100+ fn get_bytes ( ) -> std:: vec:: Vec < u8 > {
101+ // size is: 4 bytes for tag + 4 bytes for size + length of null-terminated string
102+ // 4 bytes mod_start + 4 bytes mod_end
103+ let size = ( 4 + 4 + 4 + 4 + MSG . as_bytes ( ) . len ( ) + 1 ) as u32 ;
104+ [
105+ & ( ( TagType :: Module as u32 ) . to_ne_bytes ( ) ) ,
106+ & size. to_ne_bytes ( ) ,
107+ & 0_u32 . to_ne_bytes ( ) ,
108+ & 0_u32 . to_ne_bytes ( ) ,
109+ MSG . as_bytes ( ) ,
110+ // Null Byte
111+ & [ 0 ] ,
112+ ]
113+ . iter ( )
114+ . flat_map ( |bytes| bytes. iter ( ) )
115+ . copied ( )
116+ . collect ( )
117+ }
118+
119+ /// Tests to parse a string with a terminating null byte from the tag (as the spec defines).
120+ #[ test]
121+ fn test_parse_str ( ) {
122+ let tag = get_bytes ( ) ;
123+ let tag = unsafe { tag. as_ptr ( ) . cast :: < super :: ModuleTag > ( ) . as_ref ( ) . unwrap ( ) } ;
124+ assert_eq ! ( { tag. typ } , TagType :: Module ) ;
125+ assert_eq ! ( tag. cmdline( ) . expect( "must be valid UTF-8" ) , MSG ) ;
126+ }
127+ }
0 commit comments