|  | 
|  | 1 | +use crate::{HeaderTagFlag, HeaderTagType, StructAsBytes}; | 
|  | 2 | +use core::mem::size_of; | 
|  | 3 | + | 
|  | 4 | +/// Possible flags for [`ConsoleHeaderTag`]. | 
|  | 5 | +#[repr(u32)] | 
|  | 6 | +#[derive(Copy, Clone, Debug)] | 
|  | 7 | +pub enum ConsoleHeaderTagFlags { | 
|  | 8 | +    /// Console required. | 
|  | 9 | +    ConsoleRequired = 0, | 
|  | 10 | +    /// EGA text support. | 
|  | 11 | +    EgaTextSupported = 1, | 
|  | 12 | +} | 
|  | 13 | + | 
|  | 14 | +/// Tells that a console must be available in MBI. | 
|  | 15 | +/// Only relevant for legacy BIOS. | 
|  | 16 | +#[derive(Copy, Clone, Debug)] | 
|  | 17 | +#[repr(C, packed(8))] | 
|  | 18 | +pub struct ConsoleHeaderTag { | 
|  | 19 | +    typ: HeaderTagType, | 
|  | 20 | +    flags: HeaderTagFlag, | 
|  | 21 | +    size: u32, | 
|  | 22 | +    console_flags: ConsoleHeaderTagFlags, | 
|  | 23 | +} | 
|  | 24 | + | 
|  | 25 | +impl ConsoleHeaderTag { | 
|  | 26 | +    pub const fn new(flags: HeaderTagFlag, console_flags: ConsoleHeaderTagFlags) -> Self { | 
|  | 27 | +        ConsoleHeaderTag { | 
|  | 28 | +            typ: HeaderTagType::ConsoleFlags, | 
|  | 29 | +            flags, | 
|  | 30 | +            size: size_of::<Self>() as u32, | 
|  | 31 | +            console_flags, | 
|  | 32 | +        } | 
|  | 33 | +    } | 
|  | 34 | + | 
|  | 35 | +    pub const fn typ(&self) -> HeaderTagType { | 
|  | 36 | +        self.typ | 
|  | 37 | +    } | 
|  | 38 | +    pub const fn flags(&self) -> HeaderTagFlag { | 
|  | 39 | +        self.flags | 
|  | 40 | +    } | 
|  | 41 | +    pub const fn size(&self) -> u32 { | 
|  | 42 | +        self.size | 
|  | 43 | +    } | 
|  | 44 | +    pub const fn console_flags(&self) -> ConsoleHeaderTagFlags { | 
|  | 45 | +        self.console_flags | 
|  | 46 | +    } | 
|  | 47 | +} | 
|  | 48 | + | 
|  | 49 | +impl StructAsBytes for ConsoleHeaderTag {} | 
|  | 50 | + | 
|  | 51 | +#[cfg(test)] | 
|  | 52 | +mod tests { | 
|  | 53 | +    use crate::{ConsoleHeaderTag, ConsoleHeaderTagFlags, HeaderTagFlag, HeaderTagType}; | 
|  | 54 | +    use std::mem::size_of_val; | 
|  | 55 | + | 
|  | 56 | +    /// Checks if rust aligns the type correctly and still "pack" all properties. | 
|  | 57 | +    /// This test is necessary, because Rust doesn't support "packed" together with "align()" yet. | 
|  | 58 | +    /// It seems like "packed(N)" does the right thing tho. | 
|  | 59 | +    /// | 
|  | 60 | +    /// This test is representative for all header tags, because all use the "packed(8)" attribute. | 
|  | 61 | +    #[test] | 
|  | 62 | +    fn test_alignment_and_size() { | 
|  | 63 | +        let tag = ConsoleHeaderTag::new( | 
|  | 64 | +            HeaderTagFlag::Required, | 
|  | 65 | +            ConsoleHeaderTagFlags::ConsoleRequired, | 
|  | 66 | +        ); | 
|  | 67 | +        let ptr = get_ptr!(tag, ConsoleHeaderTag); | 
|  | 68 | +        let is_aligned = ptr % 8 == 0; | 
|  | 69 | +        assert!(is_aligned); | 
|  | 70 | +        // 2x u16, 2x u32 | 
|  | 71 | +        assert_eq!(2 + 2 + 4 + 4, size_of_val(&tag)); | 
|  | 72 | + | 
|  | 73 | +        assert_eq!(ptr + 0, get_field_ptr!(tag, typ, HeaderTagType)); | 
|  | 74 | +        assert_eq!(ptr + 2, get_field_ptr!(tag, flags, HeaderTagFlag)); | 
|  | 75 | +        assert_eq!(ptr + 4, get_field_ptr!(tag, size, u32)); | 
|  | 76 | +        assert_eq!( | 
|  | 77 | +            ptr + 8, | 
|  | 78 | +            get_field_ptr!(tag, console_flags, ConsoleHeaderTagFlags) | 
|  | 79 | +        ); | 
|  | 80 | +    } | 
|  | 81 | +} | 
0 commit comments