1use crate::importer::BootPageAcceptance;
7use crate::importer::ImageLoad;
8use crate::importer::SegmentRegister;
9use crate::importer::X86Register;
10use hvdef::HV_PAGE_SIZE;
11use thiserror::Error;
12
13const STARTUP_IMAGE_TOP_PAGES: u64 = 0x100000 / HV_PAGE_SIZE; const STARTUP_IMAGE_MAX_PAGES: u64 = 0x20000 / HV_PAGE_SIZE; const IMAGE_SIZE: u64 = 0x40000; const FOUR_GB: u64 = 0x100000000;
17
18#[derive(Debug, Error)]
19pub enum Error {
20 #[error("failed to read firmware")]
21 Firmware(#[source] std::io::Error),
22 #[error("Firmware size invalid")]
23 InvalidImageSize,
24 #[error("Max ram below 4GB invalid")]
25 InvalidMaxRamBelow4gb,
26 #[error("Importer error")]
27 Importer(#[source] anyhow::Error),
28}
29
30pub fn load(
35 importer: &mut dyn ImageLoad<X86Register>,
36 image: Option<&[u8]>,
37 max_ram_below_4gb: Option<u64>,
38) -> Result<(), Error> {
39 if let Some(image) = image {
40 if (image.len() as u64) != IMAGE_SIZE {
41 return Err(Error::InvalidImageSize);
42 }
43
44 let Some(max_ram_below_4gb) = max_ram_below_4gb else {
45 return Err(Error::InvalidMaxRamBelow4gb);
46 };
47
48 if (max_ram_below_4gb % HV_PAGE_SIZE != 0)
49 || (max_ram_below_4gb == 0)
50 || (max_ram_below_4gb > FOUR_GB)
51 {
52 return Err(Error::InvalidMaxRamBelow4gb);
53 }
54
55 let image_page_count = image.len() as u64 / HV_PAGE_SIZE;
56 let max_page_below_4gb = max_ram_below_4gb / HV_PAGE_SIZE;
57 let page_base = max_page_below_4gb - image_page_count;
58 tracing::trace!(
59 image_page_count,
60 max_page_below_4gb,
61 page_base,
62 "pcat pre-import",
63 );
64
65 importer
66 .import_pages(
67 page_base,
68 image_page_count,
69 "pcat-image",
70 BootPageAcceptance::Exclusive,
71 image,
72 )
73 .map_err(Error::Importer)?;
74
75 tracing::trace!("max below 4gb bios import complete");
76
77 let image_page_count = image_page_count.min(STARTUP_IMAGE_MAX_PAGES);
78 let page_base = STARTUP_IMAGE_TOP_PAGES - image_page_count;
79 let start = image.len() - ((image_page_count * HV_PAGE_SIZE) as usize);
80
81 tracing::trace!(image_page_count, page_base, "pcat import",);
82
83 importer
84 .import_pages(
85 page_base,
86 image_page_count,
87 "pcat-top-pages",
88 BootPageAcceptance::Exclusive,
89 &image[start..],
90 )
91 .map_err(Error::Importer)?;
92
93 tracing::trace!("below 1mb bios import complete");
94 }
95
96 let mut import_reg = |register| {
98 importer
99 .import_vp_register(register)
100 .map_err(Error::Importer)
101 };
102 import_reg(X86Register::MtrrDefType(0xc00))?;
103 import_reg(X86Register::MtrrFix64k00000(0x0606060606060606))?;
104 import_reg(X86Register::MtrrFix16k80000(0x0606060606060606))?;
105 import_reg(X86Register::MtrrFix4kE0000(0x0606060606060606))?;
106 import_reg(X86Register::MtrrFix4kE8000(0x0606060606060606))?;
107 import_reg(X86Register::MtrrFix4kF0000(0x0606060606060606))?;
108 import_reg(X86Register::MtrrFix4kF8000(0x0606060606060606))?;
109
110 import_reg(X86Register::Cs(SegmentRegister {
114 base: 0xF0000,
115 limit: 0xFFFF,
116 selector: 0xF000,
117 attributes: 0x9B,
118 }))?;
119
120 Ok(())
121}