firmware_pcat/
default_cmos_values.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Code to generate initial RTC CMOS ram state (as expected by the PCAT BIOS).
5//!
6//! NOTE: Technically speaking, this module isn't actually used by the
7//! `firmware_pcat` helper device itself. Rather - upper-level init code in the
8//! VMM stack must invoke [`default_cmos_values`] when initializing the CMOS RTC
9//! device.
10//!
11//! So, why not stuff this code into its own crate then?
12//!
13//! Well... we could... but spinning off a whole crate for this seems a bit
14//! overkill, given the fact that any VMM trying to use the PCAT helper device
15//! will also require initializing the RTC with this data.
16//!
17//! As such, it seems reasonable to couple two bits of functionality in one
18//! crate.
19
20use vm_topology::memory::MemoryLayout;
21
22const Q_RTC_SECONDS: u16 = 0;
23const Q_RTC_SECONDS_ALARM: u16 = 1;
24const Q_DATE: u16 = 2;
25const Q_TIME: u16 = 3;
26const Q_RTC_MINUTES: u16 = 4;
27const Q_RTC_MINUTES_ALARM: u16 = 5;
28const Q_RTC_HOURS: u16 = 6;
29const Q_RTC_HOURS_ALARM: u16 = 7;
30const Q_RTC_DAY_OF_WEEK: u16 = 8;
31const Q_RTC_DAY: u16 = 9;
32const Q_RTC_MONTH: u16 = 10;
33const Q_RTC_YEAR: u16 = 11;
34const Q_RTC_STATUS_A: u16 = 12;
35const Q_RTC_STATUS_B: u16 = 13;
36const Q_RTC_STATUS_C: u16 = 14;
37const Q_RTC_STATUS_D: u16 = 15;
38const Q_RTC_DIAG_STATUS: u16 = 16;
39const Q_RTC_SHUTDOWN_STATUS: u16 = 17;
40const Q_FLOPPY_B: u16 = 18;
41const Q_FLOPPY_A: u16 = 19;
42const Q_BOOT_FIRST_DEVICE: u16 = 20;
43const Q_PM_E_TYPE: u16 = 21;
44const Q_PS_E_TYPE: u16 = 22;
45const Q_PS_TYPE: u16 = 23;
46const Q_PM_TYPE: u16 = 24;
47const Q_SM_E_TYPE: u16 = 25;
48const Q_SS_E_TYPE: u16 = 26;
49const Q_FLOPPY_SEEK: u16 = 27;
50const Q_QUICK_BOOT: u16 = 28;
51const Q_ADDON_ROM_DISPLAY: u16 = 29;
52const Q_NUM_LOCK: u16 = 30;
53const Q_FLOPPY_PRESENT: u16 = 31;
54const Q_MATHCO_PRESENT: u16 = 32;
55const Q_KEYBOARD_PRESENT: u16 = 33;
56const Q_MOUSE_SUPPORT: u16 = 34;
57const Q_TYPEMATIC_RATE: u16 = 35;
58const Q_PARITY_ERROR: u16 = 36;
59const Q_FLOPPY_COUNT: u16 = 37;
60const Q_BASE_MEMORY_LSB: u16 = 38;
61const Q_BASE_MEMORY_MSB: u16 = 39;
62const Q_EXT_MEMORY_LSB: u16 = 40;
63const Q_EXT_MEMORY_MSB: u16 = 41;
64const Q_PM_EXT_TYPE: u16 = 42;
65const Q_PS_EXT_TYPE: u16 = 43;
66const Q_PM_CYL: u16 = 44;
67const Q_PM_HD: u16 = 45;
68const Q_PM_WPCOM: u16 = 46;
69const Q_PM_SPT: u16 = 47;
70const Q_PS_CYL: u16 = 48;
71const Q_PS_HD: u16 = 49;
72const Q_PS_WPCOM: u16 = 50;
73const Q_PS_SPT: u16 = 51;
74const Q_SM_TYPE: u16 = 52;
75const Q_SS_TYPE: u16 = 53;
76const Q_OS2_COMP_MODE: u16 = 54;
77const Q_WAIT_FOR_F1: u16 = 55;
78const Q_DISPLAY_HIT_DEL: u16 = 56;
79const Q_PCI_IDE_CONTROLLER: u16 = 57;
80const Q_PM_SMART: u16 = 58;
81const Q_PM_LBA_MODE: u16 = 59;
82const Q_PM_BLOCK_MODE: u16 = 60;
83const Q_PM_32BIT_XFER: u16 = 61;
84const Q_PM_PIO_MODE: u16 = 62;
85const Q_PM_EMULATION_TYPE: u16 = 63;
86const Q_PS_LBA_MODE: u16 = 64;
87const Q_PS_BLOCK_MODE: u16 = 65;
88const Q_PS_32BIT_XFER: u16 = 66;
89const Q_PS_PIO_MODE: u16 = 67;
90const Q_PS_SMART: u16 = 68;
91const Q_SM_LBA_MODE: u16 = 69;
92const Q_SM_BLOCK_MODE: u16 = 70;
93const Q_SM_32BIT_XFER: u16 = 71;
94const Q_SM_PIO_MODE: u16 = 72;
95const Q_PS_EMULATION_TYPE: u16 = 73;
96const Q_SS_LBA_MODE: u16 = 74;
97const Q_SS_BLOCK_MODE: u16 = 75;
98const Q_SS_32BIT_XFER: u16 = 76;
99const Q_SS_PIO_MODE: u16 = 77;
100const Q_SM_SMART: u16 = 78;
101const Q_CHECKSUM_MSB: u16 = 79;
102const Q_CHECKSUM_LSB: u16 = 80;
103const Q_POST_EXT_MEMORY_LSB: u16 = 81;
104const Q_POST_EXT_MEMORY_MSB: u16 = 82;
105const Q_CENTURY: u16 = 83;
106const Q_SCRATCH_33: u16 = 84;
107const Q_SCRATCH_34: u16 = 85;
108const Q_SCRATCH_35: u16 = 86;
109const Q_SCRATCH_36: u16 = 87;
110const Q_COLOR: u16 = 88;
111const Q_PM_DMA_MODE: u16 = 89;
112const Q_PS_DMA_MODE: u16 = 90;
113const Q_SM_DMA_MODE: u16 = 91;
114const Q_SM_EMULATION_TYPE: u16 = 92;
115const Q_SS_DMA_MODE: u16 = 93;
116const Q_SS_SMART: u16 = 94;
117const Q_SS_EMULATION_TYPE: u16 = 95;
118const Q_HDD_ACCESS_CONTROL: u16 = 96;
119const Q_ATA_DETECT_TIME_OUT: u16 = 97;
120const Q_ATA_80PIN_CABLE_DETECT: u16 = 98;
121const Q_PNP_AWARE_OS: u16 = 99;
122const Q_RESET_CONFIG_DATA: u16 = 100;
123const Q_PCI_LATENCY_TIMER: u16 = 101;
124const Q_PCI_VGA_IRQ: u16 = 102;
125const Q_PCI_PALETTE_SNOOP: u16 = 103;
126const Q_PCI_IDE_BUS_MASTER: u16 = 104;
127const Q_PCI_OFFBOARD_IDE: u16 = 105;
128const Q_PCI_OFFBOARD_IDE_PRI_IRQ: u16 = 106;
129const Q_IRQ3_USED_BY_ISA: u16 = 107;
130const Q_IRQ4_USED_BY_ISA: u16 = 108;
131const Q_PCI_OFFBOARD_IDE_SEC_IRQ: u16 = 109;
132const Q_IRQ5_USED_BY_ISA: u16 = 110;
133const Q_IRQ7_USED_BY_ISA: u16 = 111;
134const Q_IRQ9_USED_BY_ISA: u16 = 112;
135const Q_IRQ10_USED_BY_ISA: u16 = 113;
136const Q_IRQ11_USED_BY_ISA: u16 = 114;
137const Q_EXT_CMOS_CHECKSUM_MSB: u16 = 115;
138const Q_EXT_CMOS_CHECKSUM_LSB: u16 = 116;
139const Q_SM_CYL: u16 = 117;
140const Q_SM_HD: u16 = 118;
141const Q_SM_WPCOM: u16 = 119;
142const Q_SM_SPT: u16 = 120;
143const Q_SS_CYL: u16 = 121;
144const Q_SS_HD: u16 = 122;
145const Q_SS_WPCOM: u16 = 123;
146const Q_SS_SPT: u16 = 124;
147const Q_IRQ14_USED_BY_ISA: u16 = 125;
148const Q_IRQ15_USED_BY_ISA: u16 = 126;
149const Q_DMA0_USED_BY_ISA: u16 = 127;
150const Q_DMA1_USED_BY_ISA: u16 = 128;
151const Q_DMA3_USED_BY_ISA: u16 = 129;
152const Q_DMA5_USED_BY_ISA: u16 = 130;
153const Q_DMA6_USED_BY_ISA: u16 = 131;
154const Q_DMA7_USED_BY_ISA: u16 = 132;
155const Q_MEM_SIZE_USED_BY_ISA: u16 = 133;
156const Q_MEM_BASE_USED_BY_ISA: u16 = 134;
157const Q_FLOPPY_CONTROLLER: u16 = 135;
158const Q_COMB_IR_PIN_SELECT: u16 = 136;
159const Q_COMA_PORT: u16 = 137;
160const Q_COMB_PORT: u16 = 138;
161const Q_COMB_MODE: u16 = 139;
162const Q_COMB_DUPLEX_MODE: u16 = 140;
163const Q_IR_PORT: u16 = 141;
164const Q_IR_PORT_IRQ: u16 = 142;
165const Q_LPT_MODE: u16 = 143;
166const Q_LPT_PORT: u16 = 144;
167const Q_LPT_EPPVER: u16 = 145;
168const Q_LPT_ECP_DMA: u16 = 146;
169const Q_LPT_IRQ: u16 = 147;
170const Q_CPU_SERIAL: u16 = 148;
171const Q_BU_UPDATE: u16 = 149;
172const Q_CACHE_BUS_ECC: u16 = 150;
173const Q_INTERNAL_CACHE: u16 = 151;
174const Q_C0000_SHADOW: u16 = 152;
175const Q_C4000_SHADOW: u16 = 153;
176const Q_CPU_FREQ_STRAP: u16 = 154;
177const Q_C8000_SHADOW: u16 = 155;
178const Q_NB_SERR: u16 = 156;
179const Q_CC000_SHADOW: u16 = 157;
180const Q_D0000_SHADOW: u16 = 158;
181const Q_D4000_SHADOW: u16 = 159;
182const Q_D8000_SHADOW: u16 = 160;
183const Q_DC000_SHADOW: u16 = 161;
184const Q_NB_PERR: u16 = 162;
185const Q_NB_USWC_WRITE_POST: u16 = 163;
186const Q_NB_MLT: u16 = 164;
187const Q_NB_PCI1_TO_PCI0_ACCESS: u16 = 165;
188const Q_NB_MTT: u16 = 166;
189const Q_NB_APERTURE_ACCESS_GLOBAL: u16 = 167;
190const Q_NB_PCI0_TO_APERTURE_ACCESS: u16 = 168;
191const Q_NB_DATA_INTEGRITY_MODE: u16 = 169;
192const Q_NB_EDO_RASX_WAIT_STATE: u16 = 170;
193const Q_NB_DRAM_REFRESH_RATE: u16 = 171;
194const Q_NB_EDO_CASX_WAIT_STATE: u16 = 172;
195const Q_NB_SUSPEND_REFRESH: u16 = 173;
196const Q_NB_SDRAM_RAS_TO_CAS_DELAY: u16 = 174;
197const Q_NB_POWER_DOWN_SDRAM: u16 = 175;
198const Q_NB_SDRAM_RAS_PRECHARGE: u16 = 176;
199const Q_NB_SDRAM_PRECHARGE_CONTROL: u16 = 177;
200const Q_NB_ACPI_CONTROL: u16 = 178;
201const Q_NB_GATED_CLOCK: u16 = 179;
202const Q_NB_SEARCH_MDA: u16 = 180;
203const Q_NB_AGP_SYNC: u16 = 181;
204const Q_NB_APERTURE_SIZE: u16 = 182;
205const Q_NB_AGP_SNOOP: u16 = 183;
206const Q_NB_AMTT: u16 = 184;
207const Q_AGP_SERR: u16 = 185;
208const Q_NB_LPTT: u16 = 186;
209const Q_AGP_PARITY_ERROR_RESPONSE: u16 = 187;
210const Q_EXTERNAL_CACHE: u16 = 188;
211const Q_SBH_SERR: u16 = 189;
212const Q_8BIT_IO_RECOVERY: u16 = 190;
213const Q_16BIT_IO_RECOVERY: u16 = 191;
214const Q_SBH_USB_PASSIVE_RELEASE: u16 = 192;
215const Q_SBH_PASSIVE_RELEASE: u16 = 193;
216const Q_SBH_DELAYED_TRANSACTION: u16 = 194;
217const Q_SBH_ROUTING1_DMA_TYPEF: u16 = 195;
218const Q_SBH_ROUTING2_DMA_TYPEF: u16 = 196;
219const Q_SBH_DMA0_TYPE: u16 = 197;
220const Q_SBH_DMA1_TYPE: u16 = 198;
221const Q_SBH_DMA2_TYPE: u16 = 199;
222const Q_SBH_DMA3_TYPE: u16 = 200;
223const Q_SBH_DMA5_TYPE: u16 = 201;
224const Q_SBH_DMA6_TYPE: u16 = 202;
225const Q_SBH_DMA7_TYPE: u16 = 203;
226const Q_ACPI_OS: u16 = 204;
227const Q_ACPI_2: u16 = 205;
228const Q_ACPI_APIC_TBL: u16 = 206;
229const Q_ACPI_EXCH_BUF: u16 = 207;
230const Q_ACPI_HEADLESS_MODE: u16 = 208;
231const Q_LANGUAGE: u16 = 209;
232const Q_FLOPPY_SWAP: u16 = 210;
233const Q_I19_TRAP_ALLOW: u16 = 211;
234const Q_PCI_SLOT1_IRQ: u16 = 212;
235const Q_PCI_SLOT2_IRQ: u16 = 213;
236const Q_PCI_SLOT3_IRQ: u16 = 214;
237const Q_PCI_SLOT4_IRQ: u16 = 215;
238const Q_FIRST_BOOT_DRIVE: u16 = 216;
239const Q_SECOND_BOOT_DRIVE: u16 = 217;
240const Q_RD_FIRST_BOOT_DRIVE: u16 = 218;
241const Q_THIRD_BOOT_DRIVE: u16 = 219;
242const Q_FOURTH_BOOT_DRIVE: u16 = 220;
243const Q_RD_SECOND_BOOT_DRIVE: u16 = 221;
244const Q_FIFTH_BOOT_DRIVE: u16 = 222;
245const Q_SIXTH_BOOT_DRIVE: u16 = 223;
246const Q_RD_THIRD_BOOT_DRIVE: u16 = 224;
247const Q_SEVENTH_BOOT_DRIVE: u16 = 225;
248const Q_EIGHTH_BOOT_DRIVE: u16 = 226;
249const Q_RD_FOURTH_BOOT_DRIVE: u16 = 227;
250const Q_HD_FIRST_BOOT_DRIVE: u16 = 228;
251const Q_HD_SECOND_BOOT_DRIVE: u16 = 229;
252const Q_HD_THIRD_BOOT_DRIVE: u16 = 230;
253const Q_HD_FOURTH_BOOT_DRIVE: u16 = 231;
254const Q_HD_FIFTH_BOOT_DRIVE: u16 = 232;
255const Q_HD_SIXTH_BOOT_DRIVE: u16 = 233;
256const Q_HD_SEVENTH_BOOT_DRIVE: u16 = 234;
257const Q_HD_EIGHTH_BOOT_DRIVE: u16 = 235;
258const Q_HD_NINTH_BOOT_DRIVE: u16 = 236;
259const Q_HD_TENTH_BOOT_DRIVE: u16 = 237;
260const Q_HD_ELEVENTH_BOOT_DRIVE: u16 = 238;
261const Q_HD_TWELVETH_BOOT_DRIVE: u16 = 239;
262const Q_CD_FIRST_BOOT_DRIVE: u16 = 240;
263const Q_CD_SECOND_BOOT_DRIVE: u16 = 241;
264const Q_CD_THIRD_BOOT_DRIVE: u16 = 242;
265const Q_CD_FOURTH_BOOT_DRIVE: u16 = 243;
266const Q_SUPERVISOR_PASSWORD: u16 = 244;
267const Q_DENY_SETUP: u16 = 245;
268const Q_PASSWORD_CHECK: u16 = 246;
269const Q_VIRUS_PROTECTION: u16 = 247;
270const Q_USER_PASSWORD: u16 = 248;
271const VMBIOS_ENDTOKEN: u16 = 249;
272
273#[derive(Debug, Default, Copy, Clone)]
274struct VmBiosTokenEntry {
275    pub token: u16,
276    pub bit_offset: u16,
277    pub bit_size: u16,
278    pub default_value: u16,
279}
280
281impl VmBiosTokenEntry {
282    const fn new(
283        token: u16,
284        bit_offset: u16,
285        bit_size: u16,
286        default_value: u16,
287    ) -> VmBiosTokenEntry {
288        VmBiosTokenEntry {
289            token,
290            bit_offset,
291            bit_size,
292            default_value,
293        }
294    }
295}
296
297const S_VM_BIOS_TOKEN_TABLE: &[VmBiosTokenEntry] = &[
298    VmBiosTokenEntry::new(Q_RTC_SECONDS, 0x0000, 0x08, 0x0000),
299    VmBiosTokenEntry::new(Q_RTC_SECONDS_ALARM, 0x0008, 0x08, 0x0000),
300    VmBiosTokenEntry::new(Q_TIME, 0x0008, 0x00, 0x0000),
301    VmBiosTokenEntry::new(Q_DATE, 0x0008, 0x00, 0x0000),
302    VmBiosTokenEntry::new(Q_RTC_MINUTES, 0x0010, 0x08, 0x0000),
303    VmBiosTokenEntry::new(Q_RTC_MINUTES_ALARM, 0x0018, 0x08, 0x0000),
304    VmBiosTokenEntry::new(Q_RTC_HOURS, 0x0020, 0x08, 0x0000),
305    VmBiosTokenEntry::new(Q_RTC_HOURS_ALARM, 0x0028, 0x08, 0x0000),
306    VmBiosTokenEntry::new(Q_RTC_DAY_OF_WEEK, 0x0030, 0x08, 0x0000),
307    VmBiosTokenEntry::new(Q_RTC_DAY, 0x0038, 0x08, 0x0000),
308    VmBiosTokenEntry::new(Q_RTC_MONTH, 0x0040, 0x08, 0x0000),
309    VmBiosTokenEntry::new(Q_RTC_YEAR, 0x0048, 0x08, 0x0000),
310    VmBiosTokenEntry::new(Q_RTC_STATUS_A, 0x0050, 0x08, 0x0000),
311    VmBiosTokenEntry::new(Q_RTC_STATUS_B, 0x0058, 0x08, 0x0000),
312    VmBiosTokenEntry::new(Q_RTC_STATUS_C, 0x0060, 0x08, 0x0000),
313    VmBiosTokenEntry::new(Q_RTC_STATUS_D, 0x0068, 0x08, 0x0000),
314    VmBiosTokenEntry::new(Q_RTC_DIAG_STATUS, 0x0070, 0x08, 0x0000),
315    VmBiosTokenEntry::new(Q_RTC_SHUTDOWN_STATUS, 0x0078, 0x08, 0x0000),
316    VmBiosTokenEntry::new(Q_FLOPPY_B, 0x0080, 0x04, 0x0000),
317    VmBiosTokenEntry::new(Q_FLOPPY_A, 0x0084, 0x04, 0x0004),
318    VmBiosTokenEntry::new(Q_BOOT_FIRST_DEVICE, 0x0088, 0x04, 0x0000),
319    VmBiosTokenEntry::new(Q_PM_E_TYPE, 0x008c, 0x02, 0x0000),
320    VmBiosTokenEntry::new(Q_PS_E_TYPE, 0x008e, 0x02, 0x0000),
321    VmBiosTokenEntry::new(Q_PS_TYPE, 0x0090, 0x04, 0x0000),
322    VmBiosTokenEntry::new(Q_PM_TYPE, 0x0094, 0x04, 0x0000),
323    VmBiosTokenEntry::new(Q_SM_E_TYPE, 0x0098, 0x02, 0x0000),
324    VmBiosTokenEntry::new(Q_SS_E_TYPE, 0x009a, 0x02, 0x0000),
325    VmBiosTokenEntry::new(Q_FLOPPY_SEEK, 0x009c, 0x01, 0x0000),
326    VmBiosTokenEntry::new(Q_QUICK_BOOT, 0x009d, 0x01, 0x0001),
327    VmBiosTokenEntry::new(Q_ADDON_ROM_DISPLAY, 0x009e, 0x01, 0x0000),
328    VmBiosTokenEntry::new(Q_NUM_LOCK, 0x009f, 0x01, 0x0000),
329    VmBiosTokenEntry::new(Q_FLOPPY_PRESENT, 0x00a0, 0x01, 0x0000),
330    VmBiosTokenEntry::new(Q_MATHCO_PRESENT, 0x00a1, 0x01, 0x0000),
331    VmBiosTokenEntry::new(Q_KEYBOARD_PRESENT, 0x00a2, 0x01, 0x0001),
332    VmBiosTokenEntry::new(Q_MOUSE_SUPPORT, 0x00a3, 0x01, 0x0001),
333    VmBiosTokenEntry::new(Q_TYPEMATIC_RATE, 0x00a4, 0x01, 0x0001),
334    VmBiosTokenEntry::new(Q_PARITY_ERROR, 0x00a5, 0x01, 0x0000),
335    VmBiosTokenEntry::new(Q_FLOPPY_COUNT, 0x00a6, 0x02, 0x0000),
336    VmBiosTokenEntry::new(Q_BASE_MEMORY_LSB, 0x00a8, 0x08, 0x0000),
337    VmBiosTokenEntry::new(Q_BASE_MEMORY_MSB, 0x00b0, 0x08, 0x0000),
338    VmBiosTokenEntry::new(Q_EXT_MEMORY_LSB, 0x00b8, 0x08, 0x0000),
339    VmBiosTokenEntry::new(Q_EXT_MEMORY_MSB, 0x00c0, 0x08, 0x0000),
340    VmBiosTokenEntry::new(Q_PM_EXT_TYPE, 0x00c8, 0x08, 0x0030),
341    VmBiosTokenEntry::new(Q_PS_EXT_TYPE, 0x00d0, 0x08, 0x0030),
342    VmBiosTokenEntry::new(Q_PM_CYL, 0x00d8, 0x10, 0x0000),
343    VmBiosTokenEntry::new(Q_PM_HD, 0x00e8, 0x08, 0x0000),
344    VmBiosTokenEntry::new(Q_PM_WPCOM, 0x00f0, 0x10, 0x0000),
345    VmBiosTokenEntry::new(Q_PM_SPT, 0x0100, 0x08, 0x0000),
346    VmBiosTokenEntry::new(Q_PS_CYL, 0x0108, 0x10, 0x0000),
347    VmBiosTokenEntry::new(Q_PS_HD, 0x0118, 0x08, 0x0000),
348    VmBiosTokenEntry::new(Q_PS_WPCOM, 0x0120, 0x10, 0x0000),
349    VmBiosTokenEntry::new(Q_PS_SPT, 0x0130, 0x08, 0x0000),
350    VmBiosTokenEntry::new(Q_SM_TYPE, 0x0138, 0x08, 0x0030),
351    VmBiosTokenEntry::new(Q_SS_TYPE, 0x0140, 0x08, 0x0030),
352    VmBiosTokenEntry::new(Q_OS2_COMP_MODE, 0x0148, 0x01, 0x0000),
353    VmBiosTokenEntry::new(Q_WAIT_FOR_F1, 0x0149, 0x01, 0x0001),
354    VmBiosTokenEntry::new(Q_DISPLAY_HIT_DEL, 0x014a, 0x01, 0x0001),
355    VmBiosTokenEntry::new(Q_PCI_IDE_CONTROLLER, 0x014b, 0x03, 0x0004),
356    VmBiosTokenEntry::new(Q_PM_SMART, 0x014e, 0x02, 0x0000),
357    VmBiosTokenEntry::new(Q_PM_LBA_MODE, 0x0150, 0x01, 0x0001),
358    VmBiosTokenEntry::new(Q_PM_BLOCK_MODE, 0x0151, 0x01, 0x0001),
359    VmBiosTokenEntry::new(Q_PM_32BIT_XFER, 0x0152, 0x01, 0x0001),
360    VmBiosTokenEntry::new(Q_PM_PIO_MODE, 0x0153, 0x03, 0x0000),
361    VmBiosTokenEntry::new(Q_PM_EMULATION_TYPE, 0x0156, 0x02, 0x0000),
362    VmBiosTokenEntry::new(Q_PS_LBA_MODE, 0x0158, 0x01, 0x0001),
363    VmBiosTokenEntry::new(Q_PS_BLOCK_MODE, 0x0159, 0x01, 0x0001),
364    VmBiosTokenEntry::new(Q_PS_32BIT_XFER, 0x015a, 0x01, 0x0001),
365    VmBiosTokenEntry::new(Q_PS_PIO_MODE, 0x015b, 0x03, 0x0000),
366    VmBiosTokenEntry::new(Q_PS_SMART, 0x015e, 0x02, 0x0000),
367    VmBiosTokenEntry::new(Q_SM_LBA_MODE, 0x0160, 0x01, 0x0001),
368    VmBiosTokenEntry::new(Q_SM_BLOCK_MODE, 0x0161, 0x01, 0x0001),
369    VmBiosTokenEntry::new(Q_SM_32BIT_XFER, 0x0162, 0x01, 0x0001),
370    VmBiosTokenEntry::new(Q_SM_PIO_MODE, 0x0163, 0x03, 0x0000),
371    VmBiosTokenEntry::new(Q_PS_EMULATION_TYPE, 0x0166, 0x02, 0x0000),
372    VmBiosTokenEntry::new(Q_SS_LBA_MODE, 0x0168, 0x01, 0x0001),
373    VmBiosTokenEntry::new(Q_SS_BLOCK_MODE, 0x0169, 0x01, 0x0001),
374    VmBiosTokenEntry::new(Q_SS_32BIT_XFER, 0x016a, 0x01, 0x0001),
375    VmBiosTokenEntry::new(Q_SS_PIO_MODE, 0x016b, 0x03, 0x0000),
376    VmBiosTokenEntry::new(Q_SM_SMART, 0x016e, 0x02, 0x0000),
377    VmBiosTokenEntry::new(Q_CHECKSUM_MSB, 0x0170, 0x08, 0x0000),
378    VmBiosTokenEntry::new(Q_CHECKSUM_LSB, 0x0178, 0x08, 0x0000),
379    VmBiosTokenEntry::new(Q_POST_EXT_MEMORY_LSB, 0x0180, 0x08, 0x0000),
380    VmBiosTokenEntry::new(Q_POST_EXT_MEMORY_MSB, 0x0188, 0x08, 0x0000),
381    VmBiosTokenEntry::new(Q_CENTURY, 0x0190, 0x08, 0x0000),
382    VmBiosTokenEntry::new(Q_SCRATCH_33, 0x0198, 0x08, 0x0000),
383    VmBiosTokenEntry::new(Q_SCRATCH_34, 0x01a0, 0x08, 0x0000),
384    VmBiosTokenEntry::new(Q_SCRATCH_35, 0x01a8, 0x08, 0x0000),
385    VmBiosTokenEntry::new(Q_SCRATCH_36, 0x01b0, 0x08, 0x0000),
386    VmBiosTokenEntry::new(Q_COLOR, 0x01b8, 0x04, 0x0000),
387    VmBiosTokenEntry::new(Q_PM_DMA_MODE, 0x01bc, 0x04, 0x0000),
388    VmBiosTokenEntry::new(Q_PS_DMA_MODE, 0x01c0, 0x04, 0x0000),
389    VmBiosTokenEntry::new(Q_SM_DMA_MODE, 0x01c4, 0x04, 0x0000),
390    VmBiosTokenEntry::new(Q_SM_EMULATION_TYPE, 0x01c8, 0x02, 0x0000),
391    VmBiosTokenEntry::new(Q_SS_DMA_MODE, 0x01ca, 0x04, 0x0000),
392    VmBiosTokenEntry::new(Q_SS_SMART, 0x01ce, 0x02, 0x0000),
393    VmBiosTokenEntry::new(Q_SS_EMULATION_TYPE, 0x01d0, 0x02, 0x0000),
394    VmBiosTokenEntry::new(Q_HDD_ACCESS_CONTROL, 0x01d2, 0x01, 0x0000),
395    VmBiosTokenEntry::new(Q_ATA_DETECT_TIME_OUT, 0x01d3, 0x03, 0x0007),
396    VmBiosTokenEntry::new(Q_ATA_80PIN_CABLE_DETECT, 0x01d6, 0x02, 0x0000),
397    VmBiosTokenEntry::new(Q_PNP_AWARE_OS, 0x01d8, 0x01, 0x0000),
398    VmBiosTokenEntry::new(Q_RESET_CONFIG_DATA, 0x01d9, 0x01, 0x0000),
399    VmBiosTokenEntry::new(Q_PCI_LATENCY_TIMER, 0x01da, 0x03, 0x0001),
400    VmBiosTokenEntry::new(Q_PCI_VGA_IRQ, 0x01dd, 0x01, 0x0000),
401    VmBiosTokenEntry::new(Q_PCI_PALETTE_SNOOP, 0x01de, 0x01, 0x0000),
402    VmBiosTokenEntry::new(Q_PCI_IDE_BUS_MASTER, 0x01df, 0x01, 0x0001),
403    VmBiosTokenEntry::new(Q_PCI_OFFBOARD_IDE, 0x01e0, 0x03, 0x0000),
404    VmBiosTokenEntry::new(Q_PCI_OFFBOARD_IDE_PRI_IRQ, 0x01e3, 0x03, 0x0000),
405    VmBiosTokenEntry::new(Q_IRQ3_USED_BY_ISA, 0x01e6, 0x01, 0x0000),
406    VmBiosTokenEntry::new(Q_IRQ4_USED_BY_ISA, 0x01e7, 0x01, 0x0000),
407    VmBiosTokenEntry::new(Q_PCI_OFFBOARD_IDE_SEC_IRQ, 0x01e8, 0x03, 0x0000),
408    VmBiosTokenEntry::new(Q_IRQ5_USED_BY_ISA, 0x01eb, 0x01, 0x0000),
409    VmBiosTokenEntry::new(Q_IRQ7_USED_BY_ISA, 0x01ec, 0x01, 0x0000),
410    VmBiosTokenEntry::new(Q_IRQ9_USED_BY_ISA, 0x01ed, 0x01, 0x0000),
411    VmBiosTokenEntry::new(Q_IRQ10_USED_BY_ISA, 0x01ee, 0x01, 0x0001),
412    VmBiosTokenEntry::new(Q_IRQ11_USED_BY_ISA, 0x01ef, 0x01, 0x0000),
413    VmBiosTokenEntry::new(Q_EXT_CMOS_CHECKSUM_MSB, 0x01f0, 0x08, 0x0000),
414    VmBiosTokenEntry::new(Q_EXT_CMOS_CHECKSUM_LSB, 0x01f8, 0x08, 0x0000),
415    VmBiosTokenEntry::new(Q_SM_CYL, 0x0200, 0x10, 0x0000),
416    VmBiosTokenEntry::new(Q_SM_HD, 0x0210, 0x08, 0x0000),
417    VmBiosTokenEntry::new(Q_SM_WPCOM, 0x0218, 0x10, 0x0000),
418    VmBiosTokenEntry::new(Q_SM_SPT, 0x0228, 0x08, 0x0000),
419    VmBiosTokenEntry::new(Q_SS_CYL, 0x0230, 0x10, 0x0000),
420    VmBiosTokenEntry::new(Q_SS_HD, 0x0240, 0x08, 0x0000),
421    VmBiosTokenEntry::new(Q_SS_WPCOM, 0x0248, 0x10, 0x0000),
422    VmBiosTokenEntry::new(Q_SS_SPT, 0x0258, 0x08, 0x0000),
423    VmBiosTokenEntry::new(Q_IRQ14_USED_BY_ISA, 0x0260, 0x01, 0x0000),
424    VmBiosTokenEntry::new(Q_IRQ15_USED_BY_ISA, 0x0261, 0x01, 0x0000),
425    VmBiosTokenEntry::new(Q_DMA0_USED_BY_ISA, 0x0262, 0x01, 0x0000),
426    VmBiosTokenEntry::new(Q_DMA1_USED_BY_ISA, 0x0263, 0x01, 0x0000),
427    VmBiosTokenEntry::new(Q_DMA3_USED_BY_ISA, 0x0264, 0x01, 0x0000),
428    VmBiosTokenEntry::new(Q_DMA5_USED_BY_ISA, 0x0265, 0x01, 0x0000),
429    VmBiosTokenEntry::new(Q_DMA6_USED_BY_ISA, 0x0266, 0x01, 0x0000),
430    VmBiosTokenEntry::new(Q_DMA7_USED_BY_ISA, 0x0267, 0x01, 0x0000),
431    VmBiosTokenEntry::new(Q_MEM_SIZE_USED_BY_ISA, 0x0268, 0x02, 0x0000),
432    VmBiosTokenEntry::new(Q_MEM_BASE_USED_BY_ISA, 0x026a, 0x03, 0x0002),
433    VmBiosTokenEntry::new(Q_FLOPPY_CONTROLLER, 0x026d, 0x02, 0x0002),
434    VmBiosTokenEntry::new(Q_COMB_IR_PIN_SELECT, 0x026f, 0x01, 0x0000),
435    VmBiosTokenEntry::new(Q_COMA_PORT, 0x0270, 0x03, 0x0002),
436    VmBiosTokenEntry::new(Q_COMB_PORT, 0x0273, 0x03, 0x0003),
437    VmBiosTokenEntry::new(Q_COMB_MODE, 0x0276, 0x02, 0x0000),
438    VmBiosTokenEntry::new(Q_COMB_DUPLEX_MODE, 0x0278, 0x01, 0x0001),
439    VmBiosTokenEntry::new(Q_IR_PORT, 0x0279, 0x02, 0x0000),
440    VmBiosTokenEntry::new(Q_IR_PORT_IRQ, 0x027b, 0x03, 0x0003),
441    VmBiosTokenEntry::new(Q_LPT_MODE, 0x027e, 0x02, 0x0000),
442    VmBiosTokenEntry::new(Q_LPT_PORT, 0x0280, 0x03, 0x0002),
443    VmBiosTokenEntry::new(Q_LPT_EPPVER, 0x0283, 0x01, 0x0000),
444    VmBiosTokenEntry::new(Q_LPT_ECP_DMA, 0x0284, 0x02, 0x0003),
445    VmBiosTokenEntry::new(Q_LPT_IRQ, 0x0286, 0x01, 0x0001),
446    VmBiosTokenEntry::new(Q_CPU_SERIAL, 0x0287, 0x01, 0x0000),
447    VmBiosTokenEntry::new(Q_BU_UPDATE, 0x0288, 0x01, 0x0001),
448    VmBiosTokenEntry::new(Q_CACHE_BUS_ECC, 0x0289, 0x01, 0x0000),
449    VmBiosTokenEntry::new(Q_INTERNAL_CACHE, 0x028a, 0x02, 0x0002),
450    VmBiosTokenEntry::new(Q_C0000_SHADOW, 0x028c, 0x02, 0x0002),
451    VmBiosTokenEntry::new(Q_C4000_SHADOW, 0x028e, 0x02, 0x0002),
452    VmBiosTokenEntry::new(Q_CPU_FREQ_STRAP, 0x0290, 0x05, 0x0018),
453    VmBiosTokenEntry::new(Q_C8000_SHADOW, 0x0295, 0x02, 0x0000),
454    VmBiosTokenEntry::new(Q_NB_SERR, 0x0297, 0x01, 0x0000),
455    VmBiosTokenEntry::new(Q_CC000_SHADOW, 0x0298, 0x02, 0x0000),
456    VmBiosTokenEntry::new(Q_D0000_SHADOW, 0x029a, 0x02, 0x0000),
457    VmBiosTokenEntry::new(Q_D4000_SHADOW, 0x029c, 0x02, 0x0000),
458    VmBiosTokenEntry::new(Q_D8000_SHADOW, 0x029e, 0x02, 0x0000),
459    VmBiosTokenEntry::new(Q_DC000_SHADOW, 0x02a0, 0x02, 0x0000),
460    VmBiosTokenEntry::new(Q_NB_PERR, 0x02a2, 0x01, 0x0000),
461    VmBiosTokenEntry::new(Q_NB_USWC_WRITE_POST, 0x02a3, 0x01, 0x0001),
462    VmBiosTokenEntry::new(Q_NB_MLT, 0x02a4, 0x03, 0x0002),
463    VmBiosTokenEntry::new(Q_NB_PCI1_TO_PCI0_ACCESS, 0x02a7, 0x01, 0x0001),
464    VmBiosTokenEntry::new(Q_NB_MTT, 0x02a8, 0x03, 0x0001),
465    VmBiosTokenEntry::new(Q_NB_APERTURE_ACCESS_GLOBAL, 0x02ab, 0x01, 0x0000),
466    VmBiosTokenEntry::new(Q_NB_PCI0_TO_APERTURE_ACCESS, 0x02ac, 0x01, 0x0001),
467    VmBiosTokenEntry::new(Q_NB_DATA_INTEGRITY_MODE, 0x02ad, 0x02, 0x0003),
468    VmBiosTokenEntry::new(Q_NB_EDO_RASX_WAIT_STATE, 0x02af, 0x01, 0x0001),
469    VmBiosTokenEntry::new(Q_NB_DRAM_REFRESH_RATE, 0x02b0, 0x03, 0x0001),
470    VmBiosTokenEntry::new(Q_NB_EDO_CASX_WAIT_STATE, 0x02b3, 0x01, 0x0001),
471    VmBiosTokenEntry::new(Q_NB_SUSPEND_REFRESH, 0x02b4, 0x01, 0x0000),
472    VmBiosTokenEntry::new(Q_NB_SDRAM_RAS_TO_CAS_DELAY, 0x02b5, 0x02, 0x0000),
473    VmBiosTokenEntry::new(Q_NB_POWER_DOWN_SDRAM, 0x02b7, 0x01, 0x0000),
474    VmBiosTokenEntry::new(Q_NB_SDRAM_RAS_PRECHARGE, 0x02b8, 0x02, 0x0000),
475    VmBiosTokenEntry::new(Q_NB_SDRAM_PRECHARGE_CONTROL, 0x02ba, 0x02, 0x0000),
476    VmBiosTokenEntry::new(Q_NB_ACPI_CONTROL, 0x02bc, 0x01, 0x0001),
477    VmBiosTokenEntry::new(Q_NB_GATED_CLOCK, 0x02bd, 0x01, 0x0001),
478    VmBiosTokenEntry::new(Q_NB_SEARCH_MDA, 0x02be, 0x01, 0x0001),
479    VmBiosTokenEntry::new(Q_NB_AGP_SYNC, 0x02bf, 0x01, 0x0000),
480    VmBiosTokenEntry::new(Q_NB_APERTURE_SIZE, 0x02c0, 0x03, 0x0004),
481    VmBiosTokenEntry::new(Q_NB_AGP_SNOOP, 0x02c3, 0x01, 0x0000),
482    VmBiosTokenEntry::new(Q_NB_AMTT, 0x02c4, 0x03, 0x0000),
483    VmBiosTokenEntry::new(Q_AGP_SERR, 0x02c7, 0x01, 0x0000),
484    VmBiosTokenEntry::new(Q_NB_LPTT, 0x02c8, 0x04, 0x0000),
485    VmBiosTokenEntry::new(Q_AGP_PARITY_ERROR_RESPONSE, 0x02cc, 0x01, 0x0000),
486    VmBiosTokenEntry::new(Q_EXTERNAL_CACHE, 0x02cd, 0x02, 0x0000),
487    VmBiosTokenEntry::new(Q_SBH_SERR, 0x02cf, 0x01, 0x0000),
488    VmBiosTokenEntry::new(Q_8BIT_IO_RECOVERY, 0x02d0, 0x04, 0x0000),
489    VmBiosTokenEntry::new(Q_16BIT_IO_RECOVERY, 0x02d4, 0x03, 0x0000),
490    VmBiosTokenEntry::new(Q_SBH_USB_PASSIVE_RELEASE, 0x02d7, 0x01, 0x0001),
491    VmBiosTokenEntry::new(Q_SBH_PASSIVE_RELEASE, 0x02d8, 0x01, 0x0001),
492    VmBiosTokenEntry::new(Q_SBH_DELAYED_TRANSACTION, 0x02d9, 0x01, 0x0001),
493    VmBiosTokenEntry::new(Q_SBH_ROUTING1_DMA_TYPEF, 0x02da, 0x03, 0x0004),
494    VmBiosTokenEntry::new(Q_SBH_ROUTING2_DMA_TYPEF, 0x02dd, 0x03, 0x0004),
495    VmBiosTokenEntry::new(Q_SBH_DMA0_TYPE, 0x02e0, 0x02, 0x0000),
496    VmBiosTokenEntry::new(Q_SBH_DMA1_TYPE, 0x02e2, 0x02, 0x0000),
497    VmBiosTokenEntry::new(Q_SBH_DMA2_TYPE, 0x02e4, 0x02, 0x0000),
498    VmBiosTokenEntry::new(Q_SBH_DMA3_TYPE, 0x02e6, 0x02, 0x0000),
499    VmBiosTokenEntry::new(Q_SBH_DMA5_TYPE, 0x02e8, 0x02, 0x0000),
500    VmBiosTokenEntry::new(Q_SBH_DMA6_TYPE, 0x02ea, 0x02, 0x0000),
501    VmBiosTokenEntry::new(Q_SBH_DMA7_TYPE, 0x02ec, 0x02, 0x0000),
502    VmBiosTokenEntry::new(Q_ACPI_OS, 0x02ee, 0x01, 0x0001),
503    VmBiosTokenEntry::new(Q_ACPI_2, 0x02ef, 0x01, 0x0000),
504    VmBiosTokenEntry::new(Q_ACPI_APIC_TBL, 0x02f0, 0x01, 0x0001),
505    VmBiosTokenEntry::new(Q_ACPI_EXCH_BUF, 0x02f1, 0x01, 0x0001),
506    VmBiosTokenEntry::new(Q_ACPI_HEADLESS_MODE, 0x02f2, 0x01, 0x0000),
507    VmBiosTokenEntry::new(Q_LANGUAGE, 0x02f3, 0x03, 0x0000),
508    VmBiosTokenEntry::new(Q_FLOPPY_SWAP, 0x02f6, 0x01, 0x0000),
509    VmBiosTokenEntry::new(Q_I19_TRAP_ALLOW, 0x02f7, 0x01, 0x0000),
510    VmBiosTokenEntry::new(Q_PCI_SLOT1_IRQ, 0x02f8, 0x04, 0x0000),
511    VmBiosTokenEntry::new(Q_PCI_SLOT2_IRQ, 0x02fc, 0x04, 0x0000),
512    VmBiosTokenEntry::new(Q_PCI_SLOT3_IRQ, 0x0300, 0x04, 0x0000),
513    VmBiosTokenEntry::new(Q_PCI_SLOT4_IRQ, 0x0304, 0x04, 0x0000),
514    VmBiosTokenEntry::new(Q_FIRST_BOOT_DRIVE, 0x0308, 0x03, 0x0000),
515    VmBiosTokenEntry::new(Q_SECOND_BOOT_DRIVE, 0x030b, 0x03, 0x0001),
516    VmBiosTokenEntry::new(Q_RD_FIRST_BOOT_DRIVE, 0x030e, 0x02, 0x0000),
517    VmBiosTokenEntry::new(Q_THIRD_BOOT_DRIVE, 0x0310, 0x03, 0x0002),
518    VmBiosTokenEntry::new(Q_FOURTH_BOOT_DRIVE, 0x0313, 0x03, 0x0003),
519    VmBiosTokenEntry::new(Q_RD_SECOND_BOOT_DRIVE, 0x0316, 0x02, 0x0001),
520    VmBiosTokenEntry::new(Q_FIFTH_BOOT_DRIVE, 0x0318, 0x03, 0x0004),
521    VmBiosTokenEntry::new(Q_SIXTH_BOOT_DRIVE, 0x031b, 0x03, 0x0005),
522    VmBiosTokenEntry::new(Q_RD_THIRD_BOOT_DRIVE, 0x031e, 0x02, 0x0002),
523    VmBiosTokenEntry::new(Q_SEVENTH_BOOT_DRIVE, 0x0320, 0x03, 0x0006),
524    VmBiosTokenEntry::new(Q_EIGHTH_BOOT_DRIVE, 0x0323, 0x03, 0x0007),
525    VmBiosTokenEntry::new(Q_RD_FOURTH_BOOT_DRIVE, 0x0326, 0x02, 0x0003),
526    VmBiosTokenEntry::new(Q_HD_FIRST_BOOT_DRIVE, 0x0328, 0x04, 0x0000),
527    VmBiosTokenEntry::new(Q_HD_SECOND_BOOT_DRIVE, 0x032c, 0x04, 0x0001),
528    VmBiosTokenEntry::new(Q_HD_THIRD_BOOT_DRIVE, 0x0330, 0x04, 0x0002),
529    VmBiosTokenEntry::new(Q_HD_FOURTH_BOOT_DRIVE, 0x0334, 0x04, 0x0003),
530    VmBiosTokenEntry::new(Q_HD_FIFTH_BOOT_DRIVE, 0x0338, 0x04, 0x0004),
531    VmBiosTokenEntry::new(Q_HD_SIXTH_BOOT_DRIVE, 0x033c, 0x04, 0x0005),
532    VmBiosTokenEntry::new(Q_HD_SEVENTH_BOOT_DRIVE, 0x0340, 0x04, 0x0006),
533    VmBiosTokenEntry::new(Q_HD_EIGHTH_BOOT_DRIVE, 0x0344, 0x04, 0x0007),
534    VmBiosTokenEntry::new(Q_HD_NINTH_BOOT_DRIVE, 0x0348, 0x04, 0x0008),
535    VmBiosTokenEntry::new(Q_HD_TENTH_BOOT_DRIVE, 0x034c, 0x04, 0x0009),
536    VmBiosTokenEntry::new(Q_HD_ELEVENTH_BOOT_DRIVE, 0x0350, 0x04, 0x000a),
537    VmBiosTokenEntry::new(Q_HD_TWELVETH_BOOT_DRIVE, 0x0354, 0x04, 0x000b),
538    VmBiosTokenEntry::new(Q_CD_FIRST_BOOT_DRIVE, 0x0358, 0x02, 0x0000),
539    VmBiosTokenEntry::new(Q_CD_SECOND_BOOT_DRIVE, 0x035a, 0x02, 0x0001),
540    VmBiosTokenEntry::new(Q_CD_THIRD_BOOT_DRIVE, 0x035c, 0x02, 0x0002),
541    VmBiosTokenEntry::new(Q_CD_FOURTH_BOOT_DRIVE, 0x035e, 0x02, 0x0003),
542    VmBiosTokenEntry::new(Q_SUPERVISOR_PASSWORD, 0x0360, 0x06, 0x0000),
543    VmBiosTokenEntry::new(Q_DENY_SETUP, 0x0390, 0x02, 0x0003),
544    VmBiosTokenEntry::new(Q_PASSWORD_CHECK, 0x0392, 0x01, 0x0000),
545    VmBiosTokenEntry::new(Q_VIRUS_PROTECTION, 0x0393, 0x01, 0x0000),
546    VmBiosTokenEntry::new(Q_USER_PASSWORD, 0x0398, 0x06, 0x0000),
547    VmBiosTokenEntry::new(VMBIOS_ENDTOKEN, 0, 0, 0),
548];
549
550// This routine sets the value of a specific bit field within the CMOS
551// (non-volatile) memory image. The token number is used to look up the
552// token field position within a table that is generated as part of the
553// AMI BIOS build process.
554fn set_token_value(token: u16, value: u16, cmos: &mut [u8; 256]) {
555    let mut target: VmBiosTokenEntry = Default::default();
556    for entry in S_VM_BIOS_TOKEN_TABLE {
557        if entry.token == token {
558            target = *entry;
559            break;
560        }
561    }
562
563    if target.token == VMBIOS_ENDTOKEN
564        || target.token <= Q_RTC_STATUS_D
565        || target.token == Q_CENTURY
566    {
567        return;
568    }
569
570    //
571    // Determine the byte and bit offset of the field being written
572    // to the CMOS memory array.
573    //
574    let mut byte_offset = target.bit_offset / 8;
575    let mut bit_offset = target.bit_offset % 8;
576    let mut bits_left = target.bit_size;
577    assert!(bits_left <= 16);
578
579    //
580    // Make sure the value is reasonable.
581    //
582    let temp_mask = if bits_left == 16 {
583        0xFFFF
584    } else {
585        (1 << bits_left) - 1
586    };
587
588    let new_value = value & temp_mask;
589    assert_eq!(value, new_value);
590    while bits_left > 0 {
591        //
592        // Compute the mask for this byte.
593        //
594        let real_mask = (0xFF & ((0xFF & temp_mask) << bit_offset)) as u8;
595
596        //
597        // Do not touch any of the hardware CMOS/RTC values (byte offsets
598        // 0 through 13 and 0x32).
599        //
600        if byte_offset > 0x0D && byte_offset != 0x32 {
601            // Clear the old bits and OR in the new ones.
602            cmos[byte_offset as usize] &= !real_mask;
603            cmos[byte_offset as usize] |= (new_value << bit_offset) as u8;
604        }
605
606        //
607        // Advance to the next byte.
608        //
609        if bits_left > 8 - bit_offset {
610            bits_left -= 8 - bit_offset;
611            byte_offset += 1;
612            bit_offset = 0;
613        } else {
614            bits_left = 0;
615        }
616    }
617}
618
619/// Returns the default values PCAT BIOS expects to find in RTC CMOS memory.
620///
621/// By pre-initializing the CMOS values the first time the VM is booted, we
622/// prevent the BIOS from reporting an error to the user.
623pub fn default_cmos_values(mem_layout: &MemoryLayout) -> [u8; 256] {
624    let mut cmos_data = [0; 256];
625    let cmos = &mut cmos_data;
626
627    // The default value for the "base memory" CMOS value is 640K (0x280).
628    const CMOS_BASE_MEMORY_LOW_BYTE_DEFAULT: u8 = 0x80;
629    const CMOS_BASE_MEMORY_HIGH_BYTE_DEFAULT: u8 = 0x02;
630
631    // Parse all the entries in the BIOS token table and fill in the defaults.
632    for entry in S_VM_BIOS_TOKEN_TABLE {
633        set_token_value(entry.token, entry.default_value, cmos);
634    }
635
636    // Provide specific settings that correspond to the VM's initial hardware state.
637    //
638    // Set base memory to 640k, and extended memory to the top of the first
639    // memory block.
640    let total_extended_mem = mem_layout.ram()[0].range.len() >> 20;
641    assert_eq!(total_extended_mem & !0xFFFF, 0);
642    set_token_value(Q_EXT_MEMORY_LSB, (total_extended_mem & 0xFF) as u16, cmos);
643    set_token_value(
644        Q_EXT_MEMORY_MSB,
645        ((total_extended_mem >> 8) & 0xFF) as u16,
646        cmos,
647    );
648
649    set_token_value(
650        Q_BASE_MEMORY_LSB,
651        CMOS_BASE_MEMORY_LOW_BYTE_DEFAULT.into(),
652        cmos,
653    );
654    set_token_value(
655        Q_BASE_MEMORY_MSB,
656        CMOS_BASE_MEMORY_HIGH_BYTE_DEFAULT.into(),
657        cmos,
658    );
659
660    // Enable the math coprocessor.
661    set_token_value(Q_MATHCO_PRESENT, 1, cmos);
662
663    // Enable ACPI.
664    set_token_value(Q_ACPI_OS, 1, cmos);
665
666    // Turn the Parallel Port off for Viridian
667    set_token_value(Q_LPT_PORT, 1, cmos);
668
669    // Indicate the number and types of floppy drives.
670    //
671    // Hard coded for 1 floppy drive as the "A" drive.
672    set_token_value(Q_FLOPPY_A, 4, cmos); // 4 means A drive present
673    set_token_value(Q_FLOPPY_B, 0, cmos); // 0 means B drive not present
674    set_token_value(Q_FLOPPY_PRESENT, 1, cmos); // 1 means some drives are present
675    set_token_value(Q_FLOPPY_COUNT, 0, cmos); // 0 means 1 drive, 1 means 2 drives
676
677    // Force a reset of the IDE configuration data.
678    set_token_value(Q_RESET_CONFIG_DATA, 1, cmos);
679
680    // The remaining settings are just configured to equal the "optimum"
681    // settings, even though they don't really apply to us.
682    set_token_value(Q_ATA_DETECT_TIME_OUT, 2, cmos);
683    set_token_value(Q_NB_SDRAM_RAS_TO_CAS_DELAY, 2, cmos);
684    set_token_value(Q_NB_SDRAM_RAS_PRECHARGE, 2, cmos);
685    set_token_value(Q_NB_SDRAM_PRECHARGE_CONTROL, 1, cmos);
686    set_token_value(Q_NB_AMTT, 1, cmos); // AGP Multi-Trans Timer
687    set_token_value(Q_NB_LPTT, 1, cmos); // AGP Low-Priority Timer
688
689    // Compute checksums so the BIOS doesn't think that the CMOS has been corrupted.
690    //
691    // Compute and set checksum for addresses 0x10 through 0x2D (right up to the checksum word).
692    let mut basic_checksum = 0;
693    for item in cmos[0x10..=0x2D].iter() {
694        basic_checksum += *item as u16;
695    }
696
697    set_token_value(Q_CHECKSUM_LSB, basic_checksum & 0xFF, cmos);
698    set_token_value(Q_CHECKSUM_MSB, basic_checksum >> 8, cmos);
699
700    // Compute the extended checksum for addresses 0x42 to 0x7F (starting at the
701    // extended checksum word through to the end).
702    let mut ext_checksum = 0;
703    for item in cmos[0x37..=0x3D].iter() {
704        ext_checksum += *item as u16;
705    }
706    for item in cmos[0x40..=0x7F].iter() {
707        ext_checksum += *item as u16;
708    }
709
710    set_token_value(Q_EXT_CMOS_CHECKSUM_LSB, ext_checksum & 0xFF, cmos);
711    set_token_value(Q_EXT_CMOS_CHECKSUM_MSB, ext_checksum >> 8, cmos);
712
713    // For the record, after rebooting a machine and forcing defaults in the CMOS,
714    // the following is a list of entries that end up with different values after
715    // the first boot.
716    //
717    // Their     Our
718    // Value     Value    Token
719    //  -----     -----    ----------------------------
720    //   01        00       Q_PM_E_TYPE (01 = auto detect LBA/32-bit/etc settings)
721    //   01        00       Q_PS_E_TYPE (01 = auto detect LBA/32-bit/etc settings)
722    //   01        00       Q_SM_E_TYPE (01 = auto detect LBA/32-bit/etc settings)
723    //   01        00       Q_SS_E_TYPE (01 = auto detect LBA/32-bit/etc settings)
724    //   00        01       Q_RESET_CONFIG_DATA
725
726    cmos_data
727}
728
729#[cfg(test)]
730mod tests {
731    use super::*;
732
733    #[test]
734    fn test_default_cmos_values() {
735        use memory_range::MemoryRange;
736        use vm_topology::memory::MemoryLayout;
737        use vm_topology::memory::MemoryRangeWithNode;
738
739        const KB: u64 = 1024;
740        const MB: u64 = 1024 * KB;
741        const GB: u64 = 1024 * MB;
742        const TB: u64 = 1024 * GB;
743
744        let mmio = &[
745            MemoryRange::new(GB..2 * GB),
746            MemoryRange::new(3 * GB..4 * GB),
747        ];
748        let ram = &[
749            MemoryRangeWithNode {
750                range: MemoryRange::new(0..GB),
751                vnode: 0,
752            },
753            MemoryRangeWithNode {
754                range: MemoryRange::new(2 * GB..3 * GB),
755                vnode: 0,
756            },
757            MemoryRangeWithNode {
758                range: MemoryRange::new(4 * GB..TB + 2 * GB),
759                vnode: 0,
760            },
761        ];
762        let layout = MemoryLayout::new_from_ranges(ram, mmio).unwrap();
763
764        const CMOS_DEFAULT: [u8; 256] = [
765            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766            0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x1f, 0x80, 0x02, 0x00, 0x04, 0x30, 0x30, 0x00,
767            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x26,
768            0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769            0x00, 0x00, 0x10, 0x86, 0x00, 0x40, 0x0b, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x1a, 0x19, 0x71, 0xa9, 0x18, 0x00,
771            0xa8, 0xf1, 0x49, 0x76, 0x14, 0x01, 0x80, 0x93, 0x00, 0x40, 0x03, 0x00, 0x00, 0x08,
772            0x5a, 0xac, 0xfe, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xe4, 0x00, 0x00, 0x00, 0x00,
773            0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783            0x00, 0x00, 0x00, 0x00,
784        ];
785
786        assert_eq!(CMOS_DEFAULT, default_cmos_values(&layout));
787    }
788}