td_shim_interface/td_uefi_pi/
hob.rs

1// Copyright © 2019 Intel Corporation
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Functions to access UEFI-PI defined `Hand-Off Block` (HOB) list.
16
17use core::mem::size_of;
18use scroll::Pread;
19
20use crate::pi::hob::*;
21
22const SIZE_4G: u64 = 0x100000000u64;
23
24/// Validate and align to next HOB header position.
25pub fn align_to_next_hob_offset(cap: usize, offset: usize, length: u16) -> Option<usize> {
26    if length == 0 || length > (u16::MAX - 7) {
27        None
28    } else {
29        let offset = offset.checked_add((length as usize + 7) / 8 * 8)?;
30        if offset < cap {
31            Some(offset)
32        } else {
33            None
34        }
35    }
36}
37
38/// Seek to next available HOB entry in the buffer.
39pub fn seek_to_next_hob(hob_list: &'_ [u8]) -> Option<&'_ [u8]> {
40    let header: Header = hob_list.pread(0).ok()?;
41    let offset = align_to_next_hob_offset(hob_list.len(), 0, header.length)?;
42
43    Some(&hob_list[offset..])
44}
45
46// Check hob length equal efi_end_of_hob_list of HandoffInfoTable
47pub fn check_hob_length(hob: &[u8], hob_length: usize) -> Option<&[u8]> {
48    let phit: HandoffInfoTable = hob.pread(0).ok()?;
49    let end: u64 = phit.efi_end_of_hob_list;
50    if phit.header.r#type == HOB_TYPE_HANDOFF
51        && phit.header.length as usize >= size_of::<HandoffInfoTable>()
52    {
53        if hob_length as u64 == end.checked_sub(hob.as_ptr() as u64)? {
54            Some(&hob[0..hob_length])
55        } else {
56            None
57        }
58    } else {
59        None
60    }
61}
62
63// Check the integrity of HOB list that is got from untrusted input
64// and return the HOB slice with real HOB length
65pub fn check_hob_integrity(hob_list: &[u8]) -> Option<&[u8]> {
66    let mut offset = 0;
67    let hob_list_len = hob_list.len();
68
69    // A valid HOB should have an HandoffInfoTable at least
70    if hob_list_len < size_of::<HandoffInfoTable>() {
71        return None;
72    }
73    speculation_barrier();
74
75    loop {
76        let hob = &hob_list[offset..];
77        if offset.checked_add(size_of::<Header>())? > hob_list_len {
78            return None;
79        }
80        speculation_barrier();
81
82        let header: Header = hob.pread(0).ok()?;
83
84        // A valid HOB should has non-zero length and zero reserved field,
85        if header.length == 0 || header.length as usize > hob.len() || header.reserved != 0 {
86            return None;
87        }
88        speculation_barrier();
89
90        match header.r#type {
91            HOB_TYPE_HANDOFF => {
92                if header.length as usize != size_of::<HandoffInfoTable>()
93                    || offset + size_of::<HandoffInfoTable>() > hob_list_len
94                {
95                    return None;
96                }
97                let phit_hob: HandoffInfoTable = hob.pread(0).ok()?;
98
99                // This address must be 4-KB aligned to meet page restrictions
100                if phit_hob.efi_memory_top % 0x1000 != 0 {
101                    log::info!(
102                        "PHIT HOB does not hold a 4-KB aligned EFI memory top address: {:x}\n",
103                        phit_hob.efi_memory_top
104                    );
105                    return None;
106                }
107            }
108            HOB_TYPE_END_OF_HOB_LIST => {
109                let hob_length = offset + size_of::<Header>();
110
111                return check_hob_length(hob_list, hob_length);
112            }
113            HOB_TYPE_RESOURCE_DESCRIPTOR => {
114                if header.length as usize != size_of::<ResourceDescription>() {
115                    return None;
116                }
117                let resource_hob: ResourceDescription = hob.pread(0).ok()?;
118                if resource_hob.resource_type >= RESOURCE_MAX_MEMORY_TYPE
119                    || resource_hob.resource_attribute & (!RESOURCE_ATTRIBUTE_ALL) != 0
120                {
121                    log::info!("Invalid resource type or attributes:\n");
122                    resource_hob.dump();
123                    return None;
124                }
125
126                resource_hob
127                    .physical_start
128                    .checked_add(resource_hob.resource_length)?;
129            }
130            HOB_TYPE_MEMORY_ALLOCATION => {
131                if header.length as usize != size_of::<MemoryAllocation>() {
132                    return None;
133                }
134            }
135            HOB_TYPE_FV => {
136                if header.length as usize != size_of::<FirmwareVolume>() {
137                    return None;
138                }
139            }
140            HOB_TYPE_FV2 => {
141                if header.length as usize != size_of::<FirmwareVolume2>() {
142                    return None;
143                }
144            }
145            HOB_TYPE_FV3 => {
146                if header.length as usize != size_of::<FirmwareVolume3>() {
147                    return None;
148                }
149            }
150            HOB_TYPE_CPU => {
151                if header.length as usize != size_of::<Cpu>()
152                    || offset + size_of::<Cpu>() > hob_list_len
153                {
154                    return None;
155                }
156
157                let cpu_hob: Cpu = hob.pread(0).ok()?;
158                // Reserved field is expected to be zero
159                if cpu_hob.reserved != [0u8; 6] {
160                    return None;
161                }
162            }
163            HOB_TYPE_GUID_EXTENSION => {
164                // GUID Extension HOB has variable length
165            }
166            // Unsupported types
167            _ => return None,
168        }
169        offset = align_to_next_hob_offset(hob_list_len, offset, header.length)?;
170        speculation_barrier();
171    }
172}
173
174/// Dump the HOB list.
175pub fn dump_hob(hob_list: &[u8]) -> Option<()> {
176    let mut offset = 0;
177
178    loop {
179        let hob = &hob_list[offset..];
180        let header: Header = hob.pread(0).ok()?;
181
182        match header.r#type {
183            HOB_TYPE_HANDOFF => {
184                let phit_hob: HandoffInfoTable = hob.pread(0).ok()?;
185                phit_hob.dump();
186            }
187            HOB_TYPE_RESOURCE_DESCRIPTOR => {
188                let resource_hob: ResourceDescription = hob.pread(0).ok()?;
189                resource_hob.dump();
190            }
191            HOB_TYPE_MEMORY_ALLOCATION => {
192                let allocation_hob: MemoryAllocation = hob.pread(0).ok()?;
193                allocation_hob.dump();
194            }
195            HOB_TYPE_FV => {
196                let fv_hob: FirmwareVolume = hob.pread(0).ok()?;
197                fv_hob.dump();
198            }
199            HOB_TYPE_CPU => {
200                let cpu_hob: Cpu = hob.pread(0).ok()?;
201                cpu_hob.dump();
202            }
203            HOB_TYPE_END_OF_HOB_LIST => return Some(()),
204            _ => header.dump(),
205        }
206
207        offset = align_to_next_hob_offset(hob_list.len(), offset, header.length)?;
208    }
209}
210
211/// Find Top of Lower Memory, which is the highest system memory address below 4G.
212///
213/// The low memory will be used for data storage (stack/heap/pagetable/eventlog/...)
214pub fn get_system_memory_size_below_4gb(hob_list: &[u8]) -> Option<u64> {
215    let mut low_mem_top = 0u64; // TOLUD (top of low usable dram)
216    let mut offset = 0;
217
218    loop {
219        let hob = &hob_list[offset..];
220        let header: Header = hob.pread(0).ok()?;
221
222        match header.r#type {
223            HOB_TYPE_RESOURCE_DESCRIPTOR => {
224                let resource_hob: ResourceDescription = hob.pread(0).ok()?;
225                if resource_hob.resource_type == RESOURCE_SYSTEM_MEMORY {
226                    let end = resource_hob
227                        .physical_start
228                        .checked_add(resource_hob.resource_length)?;
229                    if end < SIZE_4G && end > low_mem_top {
230                        low_mem_top = end;
231                    }
232                }
233            }
234            HOB_TYPE_END_OF_HOB_LIST => break,
235            _ => {}
236        }
237
238        offset = align_to_next_hob_offset(hob_list.len(), offset, header.length)?;
239    }
240
241    Some(low_mem_top)
242}
243
244/// Find Top of Memory, which is the highest system memory address below 4G.
245pub fn get_total_memory_top(hob_list: &[u8]) -> Option<u64> {
246    let mut mem_top = 0; // TOM (top of memory)
247    let mut offset = 0;
248
249    loop {
250        let hob = &hob_list[offset..];
251        let header: Header = hob.pread(0).ok()?;
252
253        match header.r#type {
254            HOB_TYPE_RESOURCE_DESCRIPTOR => {
255                let resource_hob: ResourceDescription = hob.pread(0).ok()?;
256                // TODO: why is RESOURCE_MEMORY_MAPPED_IO included for memory?
257                if resource_hob.resource_type == RESOURCE_SYSTEM_MEMORY
258                    || resource_hob.resource_type == RESOURCE_MEMORY_MAPPED_IO
259                {
260                    let end = resource_hob
261                        .physical_start
262                        .checked_add(resource_hob.resource_length)?;
263                    if end > mem_top {
264                        mem_top = end;
265                    }
266                }
267            }
268            HOB_TYPE_END_OF_HOB_LIST => break,
269            _ => {}
270        }
271        offset = align_to_next_hob_offset(hob_list.len(), offset, header.length)?;
272    }
273
274    Some(mem_top)
275}
276
277pub fn get_fv(hob_list: &[u8]) -> Option<FirmwareVolume> {
278    let mut offset = 0;
279
280    loop {
281        let hob = &hob_list[offset..];
282        let header: Header = hob.pread(0).ok()?;
283        match header.r#type {
284            HOB_TYPE_FV => {
285                let fv_hob: FirmwareVolume = hob.pread(0).ok()?;
286                return Some(fv_hob);
287            }
288            HOB_TYPE_END_OF_HOB_LIST => break,
289            _ => {}
290        }
291        offset = align_to_next_hob_offset(hob_list.len(), offset, header.length)?;
292    }
293
294    None
295}
296
297/// Find a GUID HOB entry matching `guid`.
298pub fn get_next_extension_guid_hob<'a>(hob_list: &'a [u8], guid: &[u8]) -> Option<&'a [u8]> {
299    let mut offset = 0;
300
301    loop {
302        let hob = &hob_list[offset..];
303        let header: Header = hob.pread(0).ok()?;
304
305        match header.r#type {
306            HOB_TYPE_GUID_EXTENSION => {
307                let guid_hob: GuidExtension = hob.pread(0).ok()?;
308                if guid_hob.name == guid {
309                    return Some(hob);
310                }
311            }
312            HOB_TYPE_END_OF_HOB_LIST => break,
313            _ => {}
314        }
315        offset = align_to_next_hob_offset(hob_list.len(), offset, header.length)?;
316    }
317    None
318}
319
320/// Get content of a GUID HOB entry.
321pub fn get_guid_data(hob_list: &[u8]) -> Option<&[u8]> {
322    let guid_hob: GuidExtension = hob_list.pread(0).ok()?;
323    let offset = size_of::<GuidExtension>();
324    let end = guid_hob.header.length as usize;
325
326    if end >= offset && end <= hob_list.len() {
327        Some(&hob_list[offset..end])
328    } else {
329        None
330    }
331}
332
333#[cfg(test)]
334mod tests {
335    use super::*;
336    use crate::pi::guid::Guid;
337    use core::ptr::slice_from_raw_parts;
338
339    #[test]
340    fn test_align_to_next_hob() {
341        assert!(align_to_next_hob_offset(usize::MAX, 0, 0).is_none());
342        assert!(align_to_next_hob_offset(8, 8, 1).is_none());
343        assert_eq!(align_to_next_hob_offset(usize::MAX, 8, 1), Some(16));
344        assert_eq!(align_to_next_hob_offset(usize::MAX, 8, 9), Some(24));
345        assert_eq!(
346            align_to_next_hob_offset(usize::MAX, 0, u16::MAX - 8),
347            Some(u16::MAX as usize - 7)
348        );
349        assert_eq!(
350            align_to_next_hob_offset(usize::MAX, 0, u16::MAX - 7),
351            Some(u16::MAX as usize - 7)
352        );
353        assert_eq!(
354            align_to_next_hob_offset(usize::MAX, 8, u16::MAX - 7),
355            Some(u16::MAX as usize + 1)
356        );
357        assert!(align_to_next_hob_offset(usize::MAX, 0, u16::MAX - 6).is_none());
358        assert!(align_to_next_hob_offset(usize::MAX, 8, u16::MAX).is_none());
359    }
360
361    #[test]
362    fn test_dump_hob() {
363        assert!(dump_hob(&[]).is_none());
364        assert!(dump_hob(&[0u8]).is_none());
365
366        let memory_allocation_hob_header = Header {
367            r#type: HOB_TYPE_MEMORY_ALLOCATION,
368            length: size_of::<MemoryAllocation>() as u16,
369            reserved: 0x0,
370        };
371        let memory_allocation_header = MemoryAllocationHeader {
372            name: [0; 16],
373            memory_base_address: 0x0,
374            memory_length: 0x0,
375            memory_type: 0x0,
376            reserved: [0; 4],
377        };
378        let _ = memory_allocation_header.as_bytes();
379        let hob = MemoryAllocation {
380            header: memory_allocation_hob_header,
381            alloc_descriptor: memory_allocation_header,
382        };
383        assert!(dump_hob(hob.as_bytes()).is_none());
384
385        let fv_hob_header = Header {
386            r#type: HOB_TYPE_FV,
387            length: size_of::<FirmwareVolume>() as u16,
388            reserved: 0x0,
389        };
390        let hob = FirmwareVolume {
391            header: fv_hob_header,
392            base_address: 0x0,
393            length: 0x0,
394        };
395        assert!(dump_hob(hob.as_bytes()).is_none());
396
397        let cpu_hob_header = Header {
398            r#type: HOB_TYPE_CPU,
399            length: size_of::<Cpu>() as u16,
400            reserved: 0x0,
401        };
402        let hob = Cpu {
403            header: cpu_hob_header,
404            size_of_memory_space: 0x0,
405            size_of_io_space: 0x0,
406            reserved: [0; 6],
407        };
408        assert!(dump_hob(hob.as_bytes()).is_none());
409    }
410
411    #[test]
412    fn test_check_hob_length() {
413        let hob_header = Header {
414            r#type: HOB_TYPE_HANDOFF,
415            length: size_of::<HandoffInfoTable>() as u16,
416            reserved: 0x0,
417        };
418
419        let mut hob = HandoffInfoTable {
420            header: hob_header,
421            version: 0,
422            boot_mode: 0,
423            efi_memory_top: 0,
424            efi_memory_bottom: 0,
425            efi_free_memory_top: 0,
426            efi_free_memory_bottom: 0,
427            efi_end_of_hob_list: 0,
428        };
429        hob.efi_end_of_hob_list =
430            size_of::<HandoffInfoTable>() as u64 + hob.as_bytes().as_ptr() as u64;
431        assert!(check_hob_length(hob.as_bytes(), size_of::<HandoffInfoTable>() as usize).is_some());
432        // hob.efi_end_of_hob_list less than hob ptr
433        hob.efi_end_of_hob_list = hob.as_bytes().as_ptr() as u64 - 1;
434        assert!(check_hob_length(hob.as_bytes(), size_of::<HandoffInfoTable>() as usize).is_none());
435        // hob_length + hob prt greater than u64::MAX
436        hob.efi_end_of_hob_list =
437            size_of::<HandoffInfoTable>() as u64 + hob.as_bytes().as_ptr() as u64;
438        assert!(check_hob_length(hob.as_bytes(), u64::MAX as usize).is_none());
439
440        // first header type is not HOB_TYPE_HANDOFF
441        let hob_header = Header {
442            r#type: HOB_TYPE_MEMORY_ALLOCATION,
443            length: size_of::<HandoffInfoTable>() as u16,
444            reserved: 0x0,
445        };
446        let mut hob = HandoffInfoTable {
447            header: hob_header,
448            version: 0,
449            boot_mode: 0,
450            efi_memory_top: 0,
451            efi_memory_bottom: 0,
452            efi_free_memory_top: 0,
453            efi_free_memory_bottom: 0,
454            efi_end_of_hob_list: 0,
455        };
456        hob.efi_end_of_hob_list =
457            size_of::<HandoffInfoTable>() as u64 + hob.as_bytes().as_ptr() as u64;
458        assert!(check_hob_length(hob.as_bytes(), size_of::<HandoffInfoTable>() as usize).is_none());
459
460        // length less than HandoffInfoTable size
461        let hob_header = Header {
462            r#type: HOB_TYPE_HANDOFF,
463            length: size_of::<HandoffInfoTable>() as u16 - 1,
464            reserved: 0x0,
465        };
466        let mut hob = HandoffInfoTable {
467            header: hob_header,
468            version: 0,
469            boot_mode: 0,
470            efi_memory_top: 0,
471            efi_memory_bottom: 0,
472            efi_free_memory_top: 0,
473            efi_free_memory_bottom: 0,
474            efi_end_of_hob_list: 0,
475        };
476        hob.efi_end_of_hob_list =
477            size_of::<HandoffInfoTable>() as u64 + hob.as_bytes().as_ptr() as u64;
478        assert!(check_hob_length(hob.as_bytes(), size_of::<HandoffInfoTable>() as usize).is_none());
479    }
480
481    #[test]
482    fn test_check_hob_integrity() {
483        const EFI_END_OF_HOB_LIST_OFFSET: usize = 48;
484        let hob = &include_bytes!("../../fuzz/seeds/hob_parser/hob_buffer")[..];
485        let mut test_hob = hob.to_vec();
486        let ptr = test_hob.as_ptr() as u64;
487        if test_hob.len() >= size_of::<HandoffInfoTable>() {
488            test_hob[EFI_END_OF_HOB_LIST_OFFSET..size_of::<HandoffInfoTable>()]
489                .copy_from_slice(&u64::to_le_bytes(ptr + hob.len() as u64)[..]);
490        }
491
492        assert!(check_hob_integrity(&test_hob).is_some());
493        assert!(dump_hob(&test_hob).is_some());
494    }
495
496    #[test]
497    fn test_get_total_memory_top() {
498        let hob = &include_bytes!("../../fuzz/seeds/hob_parser/hob_buffer")[..];
499
500        assert!(get_total_memory_top(hob).is_some());
501    }
502
503    #[test]
504    fn test_seek_to_next_hob() {
505        let hob = &include_bytes!("../../fuzz/seeds/hob_parser/hob_buffer")[..];
506
507        assert!(seek_to_next_hob(hob).is_some());
508    }
509
510    #[test]
511    fn test_get_system_memory_size_below_4gb() {
512        assert!(get_system_memory_size_below_4gb(&[]).is_none());
513
514        let mut buf = [0u8; 1024];
515        let res = ResourceDescription {
516            header: Header {
517                r#type: HOB_TYPE_RESOURCE_DESCRIPTOR,
518                length: size_of::<ResourceDescription>() as u16,
519                reserved: 0,
520            },
521            owner: [0u8; 16],
522            resource_type: RESOURCE_SYSTEM_MEMORY,
523            resource_attribute: 0,
524            physical_start: 0,
525            resource_length: 0x200_0000,
526        };
527        let buf1 = unsafe {
528            &*slice_from_raw_parts(
529                &res as *const ResourceDescription as *const u8,
530                size_of::<ResourceDescription>(),
531            )
532        };
533        buf[..size_of::<ResourceDescription>()].copy_from_slice(buf1);
534        let res = ResourceDescription {
535            header: Header {
536                r#type: HOB_TYPE_RESOURCE_DESCRIPTOR,
537                length: size_of::<ResourceDescription>() as u16,
538                reserved: 0,
539            },
540            owner: [0u8; 16],
541            resource_type: RESOURCE_SYSTEM_MEMORY,
542            resource_attribute: 0,
543            physical_start: 0x1000_0000,
544            resource_length: 0x200_0000,
545        };
546        let buf1 = unsafe {
547            &*slice_from_raw_parts(
548                &res as *const ResourceDescription as *const u8,
549                size_of::<ResourceDescription>(),
550            )
551        };
552        buf[size_of::<ResourceDescription>()..2 * size_of::<ResourceDescription>()]
553            .copy_from_slice(buf1);
554        let end = Header {
555            r#type: HOB_TYPE_END_OF_HOB_LIST,
556            length: 0,
557            reserved: 0,
558        };
559        let buf2 = unsafe {
560            &*slice_from_raw_parts(&end as *const Header as *const u8, size_of::<Header>())
561        };
562        buf[2 * size_of::<ResourceDescription>()
563            ..2 * size_of::<ResourceDescription>() + size_of::<Header>()]
564            .copy_from_slice(buf2);
565        assert_eq!(get_system_memory_size_below_4gb(&buf), Some(0x1200_0000));
566
567        let res = ResourceDescription {
568            header: Header {
569                r#type: HOB_TYPE_RESOURCE_DESCRIPTOR,
570                length: 0,
571                reserved: 0,
572            },
573            owner: [0u8; 16],
574            resource_type: RESOURCE_SYSTEM_MEMORY,
575            resource_attribute: 0,
576            physical_start: 0,
577            resource_length: 0x200_0000,
578        };
579        let buf1 = unsafe {
580            &*slice_from_raw_parts(
581                &res as *const ResourceDescription as *const u8,
582                size_of::<ResourceDescription>(),
583            )
584        };
585        buf[..size_of::<ResourceDescription>()].copy_from_slice(buf1);
586        assert!(get_system_memory_size_below_4gb(&buf).is_none());
587    }
588
589    #[test]
590    fn test_get_fv() {
591        assert!(get_fv(&[]).is_none());
592
593        let mut buf = [0u8; 1024];
594        let res = FirmwareVolume {
595            header: Header {
596                r#type: HOB_TYPE_FV,
597                length: size_of::<FirmwareVolume>() as u16,
598                reserved: 0,
599            },
600            base_address: 0x1000000,
601            length: 0,
602        };
603        let buf1 = unsafe {
604            &*slice_from_raw_parts(
605                &res as *const FirmwareVolume as *const u8,
606                size_of::<FirmwareVolume>(),
607            )
608        };
609        buf[..size_of::<FirmwareVolume>()].copy_from_slice(buf1);
610        let end = Header {
611            r#type: HOB_TYPE_END_OF_HOB_LIST,
612            length: 0,
613            reserved: 0,
614        };
615        let buf2 = unsafe {
616            &*slice_from_raw_parts(&end as *const Header as *const u8, size_of::<Header>())
617        };
618        buf[size_of::<FirmwareVolume>()..size_of::<FirmwareVolume>() + size_of::<Header>()]
619            .copy_from_slice(buf2);
620        assert!(get_fv(&buf).is_some());
621
622        let res = FirmwareVolume {
623            header: Header {
624                r#type: HOB_TYPE_FV2,
625                length: u16::MAX,
626                reserved: 0,
627            },
628            base_address: 0x1000000,
629            length: 0,
630        };
631        let buf1 = unsafe {
632            &*slice_from_raw_parts(
633                &res as *const FirmwareVolume as *const u8,
634                size_of::<FirmwareVolume>(),
635            )
636        };
637        buf[..size_of::<FirmwareVolume>()].copy_from_slice(buf1);
638        assert!(get_fv(&buf).is_none());
639    }
640
641    #[test]
642    fn test_get_guid() {
643        let guid = Guid::from_bytes(&[0u8; 16]);
644        assert!(get_next_extension_guid_hob(&[], guid.as_bytes()).is_none());
645
646        let mut buf = [0xaau8; 128];
647        let res = GuidExtension {
648            header: Header {
649                r#type: HOB_TYPE_GUID_EXTENSION,
650                length: size_of::<GuidExtension>() as u16 + 16,
651                reserved: 0,
652            },
653            name: [0xa5u8; 16],
654        };
655        let buf1 = unsafe {
656            &*slice_from_raw_parts(
657                &res as *const GuidExtension as *const u8,
658                size_of::<GuidExtension>(),
659            )
660        };
661        assert_eq!(buf1, res.as_bytes());
662        buf[..size_of::<GuidExtension>()].copy_from_slice(buf1);
663        let end = Header {
664            r#type: HOB_TYPE_END_OF_HOB_LIST,
665            length: 0,
666            reserved: 0,
667        };
668        let buf2 = unsafe {
669            &*slice_from_raw_parts(&end as *const Header as *const u8, size_of::<Header>())
670        };
671        buf[size_of::<GuidExtension>() + 16..size_of::<GuidExtension>() + 16 + size_of::<Header>()]
672            .copy_from_slice(buf2);
673        let guid = get_next_extension_guid_hob(&buf, &[0xa5u8; 16]).unwrap();
674        let data = get_guid_data(guid).unwrap();
675        assert_eq!(data, &[0xaa; 16]);
676    }
677}
678
679// To protect against speculative attacks, place the LFENCE instruction after the range
680// check and branch, but before any code that consumes the checked value.
681fn speculation_barrier() {
682    unsafe { core::arch::asm!("lfence") }
683}