|
@@ -1,5 +1,6 @@
|
|
|
use crate::tag_type::{Tag, TagIter, TagType};
|
|
|
use core::fmt::{Debug, Formatter};
|
|
|
+use core::str::Utf8Error;
|
|
|
|
|
|
/// This tag indicates to the kernel what boot module was loaded along with
|
|
|
/// the kernel image, and where it can be found.
|
|
@@ -10,25 +11,24 @@ pub struct ModuleTag {
|
|
|
size: u32,
|
|
|
mod_start: u32,
|
|
|
mod_end: u32,
|
|
|
- /// Begin of the command line string.
|
|
|
+ /// Null-terminated UTF-8 string
|
|
|
cmdline_str: u8,
|
|
|
}
|
|
|
|
|
|
impl ModuleTag {
|
|
|
- // The multiboot specification defines the module str as valid utf-8 (zero terminated string),
|
|
|
- // therefore this function produces defined behavior
|
|
|
- /// Get the cmdline of the module. If the GRUB configuration contains
|
|
|
- /// `module2 /foobar/some_boot_module --test cmdline-option`, then this method
|
|
|
+ /// Returns the cmdline of the module.
|
|
|
+ /// This is an null-terminated UTF-8 string. If this returns `Err` then perhaps the memory
|
|
|
+ /// is invalid or the bootloader doesn't follow the spec.
|
|
|
+ ///
|
|
|
+ /// For example: If the GRUB configuration contains
|
|
|
+ /// `module2 /foobar/some_boot_module --test cmdline-option` then this method
|
|
|
/// will return `--test cmdline-option`.
|
|
|
- pub fn cmdline(&self) -> &str {
|
|
|
+ pub fn cmdline(&self) -> Result<&str, Utf8Error> {
|
|
|
use core::{mem, slice, str};
|
|
|
+ // strlen without null byte
|
|
|
let strlen = self.size as usize - mem::size_of::<ModuleTag>();
|
|
|
- unsafe {
|
|
|
- str::from_utf8_unchecked(slice::from_raw_parts(
|
|
|
- &self.cmdline_str as *const u8,
|
|
|
- strlen,
|
|
|
- ))
|
|
|
- }
|
|
|
+ let bytes = unsafe { slice::from_raw_parts((&self.cmdline_str) as *const u8, strlen) };
|
|
|
+ str::from_utf8(bytes)
|
|
|
}
|
|
|
|
|
|
/// Start address of the module.
|
|
@@ -89,3 +89,39 @@ impl<'a> Debug for ModuleIter<'a> {
|
|
|
list.finish()
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod tests {
|
|
|
+ use crate::TagType;
|
|
|
+
|
|
|
+ const MSG: &str = "hello";
|
|
|
+
|
|
|
+ /// Returns the tag structure in bytes in native endian format.
|
|
|
+ fn get_bytes() -> std::vec::Vec<u8> {
|
|
|
+ // size is: 4 bytes for tag + 4 bytes for size + length of null-terminated string
|
|
|
+ // 4 bytes mod_start + 4 bytes mod_end
|
|
|
+ let size = (4 + 4 + 4 + 4 + MSG.as_bytes().len() + 1) as u32;
|
|
|
+ [
|
|
|
+ &((TagType::Module as u32).to_ne_bytes()),
|
|
|
+ &size.to_ne_bytes(),
|
|
|
+ &0_u32.to_ne_bytes(),
|
|
|
+ &0_u32.to_ne_bytes(),
|
|
|
+ MSG.as_bytes(),
|
|
|
+ // Null Byte
|
|
|
+ &[0],
|
|
|
+ ]
|
|
|
+ .iter()
|
|
|
+ .flat_map(|bytes| bytes.iter())
|
|
|
+ .copied()
|
|
|
+ .collect()
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Tests to parse a string with a terminating null byte from the tag (as the spec defines).
|
|
|
+ #[test]
|
|
|
+ fn test_parse_str() {
|
|
|
+ let tag = get_bytes();
|
|
|
+ let tag = unsafe { tag.as_ptr().cast::<super::ModuleTag>().as_ref().unwrap() };
|
|
|
+ assert_eq!({ tag.typ }, TagType::Module);
|
|
|
+ assert_eq!(tag.cmdline().expect("must be valid UTF-8"), MSG);
|
|
|
+ }
|
|
|
+}
|