uefi/hii/
ifr.rs

1use core::mem;
2
3use super::{FormId, QuestionId, StringId, VarStoreId};
4use crate::guid::Guid;
5
6#[derive(Clone, Copy, Debug, PartialEq)]
7#[repr(u8)]
8pub enum IfrTypeKind {
9    U8 = 0x00,
10    U16 = 0x01,
11    U32 = 0x02,
12    U64 = 0x03,
13    Bool = 0x04,
14    Time = 0x05,
15    Date = 0x06,
16    String = 0x07,
17    Other = 0x08,
18    Undefined = 0x09,
19    Action = 0x0A,
20    Buffer = 0x0B,
21    Ref = 0x0C,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq)]
25#[repr(C)]
26pub struct HiiTime {
27    pub Hour: u8,
28    pub Minute: u8,
29    pub Second: u8,
30}
31
32#[derive(Clone, Copy, Debug, PartialEq)]
33#[repr(C)]
34pub struct HiiDate {
35    pub Year: u16,
36    pub Month: u8,
37    pub Day: u8,
38}
39
40#[derive(Clone, Copy, Debug, PartialEq)]
41#[repr(C, packed)] // Fails to have correct size with repr(C)
42pub struct HiiRef {
43    pub QuestionId: QuestionId,
44    pub FormId: FormId,
45    pub FormSetGuid: Guid,
46    pub DevicePath: StringId,
47}
48
49#[derive(Clone, Copy)]
50#[repr(C, packed)] // Fails to have correct size with repr(C)
51pub union IfrTypeValue {
52    u8: u8,
53    u16: u16,
54    u32: u32,
55    u64: u64,
56    b: bool,
57    time: HiiTime,
58    date: HiiDate,
59    string: StringId,
60    reference: HiiRef,
61    // buffer: [u8]
62}
63
64impl IfrTypeValue {
65    pub unsafe fn to_enum(self, kind: IfrTypeKind) -> IfrTypeValueEnum {
66        match kind {
67            IfrTypeKind::U8 => IfrTypeValueEnum::U8(self.u8),
68            IfrTypeKind::U16 => IfrTypeValueEnum::U16(self.u16),
69            IfrTypeKind::U32 => IfrTypeValueEnum::U32(self.u32),
70            IfrTypeKind::U64 => IfrTypeValueEnum::U64(self.u64),
71            IfrTypeKind::Bool => IfrTypeValueEnum::Bool(self.b),
72            IfrTypeKind::Time => IfrTypeValueEnum::Time(self.time),
73            IfrTypeKind::Date => IfrTypeValueEnum::Date(self.date),
74            IfrTypeKind::String => IfrTypeValueEnum::String(self.string),
75            IfrTypeKind::Ref => IfrTypeValueEnum::Ref(self.reference),
76            _ => IfrTypeValueEnum::Other(kind, mem::transmute(self)),
77        }
78    }
79}
80
81#[derive(Clone, Copy, Debug, PartialEq)]
82pub enum IfrTypeValueEnum {
83    U8(u8),
84    U16(u16),
85    U32(u32),
86    U64(u64),
87    Bool(bool),
88    Time(HiiTime),
89    Date(HiiDate),
90    String(StringId),
91    Ref(HiiRef),
92    Other(IfrTypeKind, [u8; 22]),
93}
94
95impl IfrTypeValueEnum {
96    pub unsafe fn to_union(self) -> (IfrTypeKind, IfrTypeValue) {
97        match self {
98            IfrTypeValueEnum::U8(u8) => (IfrTypeKind::U8, IfrTypeValue { u8 }),
99            IfrTypeValueEnum::U16(u16) => (IfrTypeKind::U16, IfrTypeValue { u16 }),
100            IfrTypeValueEnum::U32(u32) => (IfrTypeKind::U32, IfrTypeValue { u32 }),
101            IfrTypeValueEnum::U64(u64) => (IfrTypeKind::U64, IfrTypeValue { u64 }),
102            IfrTypeValueEnum::Bool(b) => (IfrTypeKind::Bool, IfrTypeValue { b }),
103            IfrTypeValueEnum::Time(time) => (IfrTypeKind::Time, IfrTypeValue { time }),
104            IfrTypeValueEnum::Date(date) => (IfrTypeKind::Date, IfrTypeValue { date }),
105            IfrTypeValueEnum::String(string) => (IfrTypeKind::String, IfrTypeValue { string }),
106            IfrTypeValueEnum::Ref(reference) => (IfrTypeKind::Ref, IfrTypeValue { reference }),
107            IfrTypeValueEnum::Other(kind, data) => (kind, mem::transmute(data)),
108        }
109    }
110}
111
112#[repr(C)]
113pub struct HiiValue {
114    pub Kind: IfrTypeKind,
115    pub Buffer: *mut u8,
116    pub BufferLen: u16,
117    pub Value: IfrTypeValue,
118}
119
120#[derive(Clone, Copy, Debug)]
121#[repr(C)]
122pub struct IfrStatementHeader {
123    pub Prompt: StringId,
124    pub Help: StringId,
125}
126
127pub const IFR_FLAG_READ_ONLY: u8 = 0x01;
128pub const IFR_FLAG_CALLBACK: u8 = 0x04;
129pub const IFR_FLAG_RESET_REQUIRED: u8 = 0x10;
130pub const IFR_FLAG_RECONNECT_REQUIRED: u8 = 0x40;
131pub const IFR_FLAG_OPTIONS_ONLY: u8 = 0x80;
132
133#[derive(Clone, Copy, Debug)]
134#[repr(C, packed)] // Has incorrect size if not packed
135pub struct IfrQuestionHeader {
136    pub Header: IfrStatementHeader,
137    pub QuestionId: QuestionId,
138    pub VarStoreId: VarStoreId,
139    // union { VarName: StringId, VarOffset: u16 }
140    pub VarStoreInfo: u16,
141    pub Flags: u8,
142}
143
144#[derive(Clone, Copy, Debug)]
145#[repr(u8)]
146pub enum IfrOpCode {
147    Form = 0x01,
148    Subtitle = 0x02,
149    Text = 0x03,
150    Image = 0x04,
151    OneOf = 0x05,
152    Checkbox = 0x06,
153    Numeric = 0x07,
154    Password = 0x08,
155    OneOfOption = 0x09,
156    SuppressIf = 0x0A,
157    Locked = 0x0B,
158    Action = 0x0C,
159    ResetButton = 0x0D,
160    FormSet = 0x0E,
161    Ref = 0x0F,
162    NoSubmitIf = 0x10,
163    InconsistentIf = 0x11,
164    EqIdVal = 0x12,
165    EqIdId = 0x13,
166    EqIdValList = 0x14,
167    And = 0x15,
168    Or = 0x16,
169    Not = 0x17,
170    Rule = 0x18,
171    GrayOutIf = 0x19,
172    Date = 0x1A,
173    Time = 0x1B,
174    String = 0x1C,
175    Refresh = 0x1D,
176    DisableIf = 0x1E,
177    Animation = 0x1F,
178    ToLower = 0x20,
179    ToUpper = 0x21,
180    Map = 0x22,
181    OrderedList = 0x23,
182    VarStore = 0x24,
183    VarStoreNameValue = 0x25,
184    VarStoreEfi = 0x26,
185    VarStoreDevice = 0x27,
186    Version = 0x28,
187    End = 0x29,
188    Match = 0x2A,
189    Get = 0x2B,
190    Set = 0x2C,
191    Read = 0x2D,
192    Write = 0x2E,
193    Equal = 0x2F,
194    NotEqual = 0x30,
195    GreaterThan = 0x31,
196    GreaterEqual = 0x32,
197    LessThan = 0x33,
198    LessEqual = 0x34,
199    BitwiseAnd = 0x35,
200    BitwiseOr = 0x36,
201    BitwiseNot = 0x37,
202    ShiftLeft = 0x38,
203    ShiftRight = 0x39,
204    Add = 0x3A,
205    Subtract = 0x3B,
206    Multiply = 0x3C,
207    Divide = 0x3D,
208    Modulo = 0x3E,
209    RuleRef = 0x3F,
210    QuestionRef1 = 0x40,
211    QuestionRef2 = 0x41,
212    Uint8 = 0x42,
213    Uint16 = 0x43,
214    Uint32 = 0x44,
215    Uint64 = 0x45,
216    True = 0x46,
217    False = 0x47,
218    ToUint = 0x48,
219    ToString = 0x49,
220    ToBoolean = 0x4A,
221    Mid = 0x4B,
222    Find = 0x4C,
223    Token = 0x4D,
224    StringRef1 = 0x4E,
225    StringRef2 = 0x4F,
226    Conditional = 0x50,
227    QuestionRef3 = 0x51,
228    Zero = 0x52,
229    One = 0x53,
230    Ones = 0x54,
231    Undefined = 0x55,
232    Length = 0x56,
233    Dup = 0x57,
234    This = 0x58,
235    Span = 0x59,
236    Value = 0x5A,
237    Default = 0x5B,
238    DefaultStore = 0x5C,
239    FormMap = 0x5D,
240    Catenate = 0x5E,
241    Guid = 0x5F,
242    Security = 0x60,
243    ModelTag = 0x61,
244    RefreshId = 0x62,
245    WarningIf = 0x63,
246    Match2 = 0x64,
247}
248
249#[derive(Copy, Clone, Debug)]
250#[repr(C)]
251pub struct IfrOpHeader {
252    pub OpCode: IfrOpCode,
253    pub Length_Scope: u8,
254}
255
256impl IfrOpHeader {
257    pub fn Length(&self) -> u8 {
258        self.Length_Scope & 0x7F
259    }
260
261    pub fn Scope(&self) -> bool {
262        self.Length_Scope & 0x80 == 0x80
263    }
264
265    pub unsafe fn cast<T>(&self) -> Option<&T> {
266        if self.Length() as usize >= mem::size_of::<T>() {
267            Some(&*(self as *const Self as *const T))
268        } else {
269            None
270        }
271    }
272}
273
274macro_rules! unsafe_field {
275    ($struct: ident, $field:ident, $type:ty) => {
276        pub fn $field(&self) -> Option<&$type> {
277            unsafe {
278                let self_ptr = self as *const Self;
279                let unsafe_self = &*(self_ptr as *const $struct);
280                let field_ptr = &unsafe_self.$field as *const $type;
281                let length = field_ptr.add(1) as usize - self_ptr as usize;
282                if self.Header.Length() as usize >= length {
283                    Some(&*field_ptr)
284                } else {
285                    None
286                }
287            }
288        }
289    };
290}
291
292#[derive(Debug)]
293#[repr(C)]
294pub struct IfrAction {
295    pub Header: IfrOpHeader,
296    pub QuestionHeader: IfrQuestionHeader,
297}
298
299#[repr(C)]
300struct UnsafeIfrAction {
301    safe: IfrAction,
302    QuestionConfig: StringId,
303}
304
305impl IfrAction {
306    unsafe_field!(UnsafeIfrAction, QuestionConfig, StringId);
307}
308
309#[derive(Debug)]
310#[repr(C, packed)] // Has incorrect size if not packed
311pub struct IfrCheckbox {
312    pub Header: IfrOpHeader,
313    pub Question: IfrQuestionHeader,
314    pub Flags: u8,
315}
316
317#[derive(Debug)]
318#[repr(C)]
319pub struct IfrForm {
320    pub Header: IfrOpHeader,
321    pub FormId: FormId,
322    pub FormTitle: StringId,
323}
324
325#[derive(Debug)]
326#[repr(C, packed)] // Has incorrect size if not packed
327pub struct IfrNumeric {
328    pub Header: IfrOpHeader,
329    pub Question: IfrQuestionHeader,
330    pub Flags: u8,
331    //TODO: MinValue, MaxValue, Step
332}
333
334#[derive(Debug)]
335#[repr(C)]
336pub struct IfrOneOf {
337    pub Header: IfrOpHeader,
338    pub Question: IfrQuestionHeader,
339    pub Flags: u8,
340    //TODO: MinValue, MaxValue, Step
341}
342
343#[repr(C)]
344pub struct IfrOneOfOption {
345    pub Header: IfrOpHeader,
346    pub Option: StringId,
347    pub Flags: u8,
348    pub Kind: IfrTypeKind,
349    pub Value: IfrTypeValue,
350}
351
352#[derive(Debug)]
353#[repr(C)]
354pub struct IfrOrderedList {
355    pub Header: IfrOpHeader,
356    pub Question: IfrQuestionHeader,
357    pub MaxContainers: u8,
358    pub Flags: u8,
359}
360
361#[derive(Debug)]
362#[repr(C)]
363pub struct IfrRef {
364    pub Header: IfrOpHeader,
365    pub Question: IfrQuestionHeader,
366}
367
368#[repr(C)]
369struct UnsafeIfrRef {
370    safe: IfrRef,
371    FormId: FormId,
372    QuestionId: QuestionId,
373    FormSetId: Guid,
374    DevicePath: *const u16,
375}
376
377impl IfrRef {
378    unsafe_field!(UnsafeIfrRef, FormId, FormId);
379    unsafe_field!(UnsafeIfrRef, QuestionId, QuestionId);
380    unsafe_field!(UnsafeIfrRef, FormSetId, Guid);
381    unsafe_field!(UnsafeIfrRef, DevicePath, *const u16);
382}
383
384#[repr(C, packed)] // Has incorrect size if not packed
385pub struct IfrSubtitle {
386    pub Header: IfrOpHeader,
387    pub Statement: IfrStatementHeader,
388    pub Flags: u8,
389}
390
391#[derive(Debug)]
392#[repr(C)]
393pub struct IfrText {
394    pub Header: IfrOpHeader,
395    pub Statement: IfrStatementHeader,
396    pub TextTwo: StringId,
397}