VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/post.c

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.6 KB
Line 
1/* $Id: post.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * BIOS POST routines. Used only during initialization.
4 */
5
6/*
7 * Copyright (C) 2004-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <stdint.h>
29#include <string.h>
30#include "biosint.h"
31#include "inlines.h"
32
33#if DEBUG_POST || 0
34# define DPRINT(...) BX_DEBUG(__VA_ARGS__)
35#else
36# define DPRINT(...)
37#endif
38
39/* In general, checksumming ROMs in a VM just wastes time. */
40//#define CHECKSUM_ROMS
41
42/* The format of a ROM is as follows:
43 *
44 * ------------------------------
45 * 0 | AA55h signature (word) |
46 * ------------------------------
47 * 2 | Size in 512B blocks (byte) |
48 * ------------------------------
49 * 3 | Start of executable code |
50 * | ....... |
51 * end | |
52 * ------------------------------
53 */
54
55typedef struct rom_hdr_tag {
56 uint16_t signature;
57 uint8_t num_blks;
58 uint8_t code;
59} rom_hdr;
60
61
62/* Calculate the checksum of a ROM. Note that the ROM might be
63 * larger than 64K.
64 */
65static inline uint8_t rom_checksum(uint8_t __far *rom, uint8_t blocks)
66{
67 uint8_t sum = 0;
68
69#ifdef CHECKSUM_ROMS
70 while (blocks--) {
71 int i;
72
73 for (i = 0; i < 512; ++i)
74 sum += rom[i];
75 /* Add 512 bytes (32 paragraphs) to segment. */
76 rom = MK_FP(FP_SEG(rom) + (512 >> 4), 0);
77 }
78#endif
79 return sum;
80}
81
82/* The ROM init routine might trash register. Give the compiler a heads-up. */
83typedef void __far (rom_init_rtn)(void);
84#pragma aux rom_init_rtn modify [ax bx cx dx si di es /*ignored:*/ bp] /*ignored:*/ loadds;
85
86/* The loadds bit is ignored for rom_init_rtn, the impression from the code
87 generator is that this is due to using a memory model where DS is fixed.
88 If we add DS as a modified register, we'll get run into compiler error
89 E1122 (BAD_REG) because FixedRegs() in cg/intel/386/c/386rgtbl.c returns
90 HW_DS as part of the fixed register set that cannot be modified.
91
92 The problem of the vga bios trashing DS isn't a biggie, except when
93 something goes sideways before we can reload it. Setting a I/O port
94 breakpoint on port 80h and wait a while before resuming execution
95 (ba i 1 80 "sleep 400 ; g") will usually trigger a keyboard init panic and
96 showcase the issue. The panic message is garbage because it's read from
97 segment 0c000h instead of 0f000h. */
98static void restore_ds_as_dgroup(void);
99#pragma aux restore_ds_as_dgroup = \
100 "mov ax, 0f000h" \
101 "mov ds, ax" \
102 modify exact [ax];
103
104
105/* Scan for ROMs in the given range and execute their POST code. */
106void rom_scan(uint16_t start_seg, uint16_t end_seg)
107{
108 rom_hdr __far *rom;
109 uint8_t rom_blks;
110
111 DPRINT("Scanning for ROMs in %04X-%04X range\n", start_seg, end_seg);
112
113 while (start_seg < end_seg) {
114 rom = MK_FP(start_seg, 0);
115 /* Check for the ROM signature. */
116 if (rom->signature == 0xAA55) {
117 DPRINT("Found ROM at segment %04X\n", start_seg);
118 if (!rom_checksum((void __far *)rom, rom->num_blks)) {
119 rom_init_rtn *rom_init;
120
121 /* Checksum good, initialize ROM. */
122 rom_init = (rom_init_rtn *)&rom->code;
123 rom_init();
124 int_disable();
125 restore_ds_as_dgroup();
126 /** @todo BP is not restored. */
127 DPRINT("ROM initialized\n");
128
129 /* Continue scanning past the end of this ROM. */
130 rom_blks = (rom->num_blks + 3) & ~3; /* 4 blocks = 2K */
131 start_seg += rom_blks / 4;
132 }
133 } else {
134 /* Scanning is done in 2K steps. */
135 start_seg += 2048 >> 4;
136 }
137 }
138}
139
140#if VBOX_BIOS_CPU >= 80386
141
142/* NB: The CPUID detection is generic but currently not used elsewhere. */
143
144/* Check CPUID availability. */
145int is_cpuid_supported( void )
146{
147 uint32_t old_flags, new_flags;
148
149 old_flags = eflags_read();
150 new_flags = old_flags ^ (1L << 21); /* Toggle CPUID bit. */
151 eflags_write( new_flags );
152 new_flags = eflags_read();
153 return( old_flags != new_flags ); /* Supported if bit changed. */
154}
155
156#define APICMODE_DISABLED 0
157#define APICMODE_APIC 1
158#define APICMODE_X2APIC 2
159
160#define APIC_BASE_MSR 0x1B
161#define APICBASE_X2APIC 0x400 /* bit 10 */
162#define APICBASE_ENABLE 0x800 /* bit 11 */
163
164/*
165 * Set up APIC/x2APIC. See also DevPcBios.cpp.
166 *
167 * NB: Virtual wire compatibility is set up earlier in 32-bit protected
168 * mode assembler (because it needs to access MMIO just under 4GB).
169 * Switching to x2APIC mode or disabling the APIC is done through an MSR
170 * and needs no 32-bit addressing. Going to x2APIC mode does not lose the
171 * existing virtual wire setup.
172 *
173 * NB: This code does not assume that there is a local APIC. It is necessary
174 * to check CPUID whether APIC is present; the CPUID instruction might not be
175 * available either.
176 *
177 * NB: Destroys high bits of 32-bit registers.
178 */
179void BIOSCALL apic_setup(void)
180{
181 uint64_t base_msr;
182 uint16_t mask_set;
183 uint16_t mask_clr;
184 uint8_t apic_mode;
185 uint32_t cpu_id[4];
186
187 /* If there's no CPUID, there's certainly no APIC. */
188 if (!is_cpuid_supported()) {
189 return;
190 }
191
192 /* Check EDX bit 9 */
193 cpuid(&cpu_id, 1);
194 BX_DEBUG("CPUID EDX: 0x%lx\n", cpu_id[3]);
195 if ((cpu_id[3] & (1 << 9)) == 0) {
196 return; /* No local APIC, nothing to do. */
197 }
198
199 /* APIC mode at offset 78h in CMOS NVRAM. */
200 apic_mode = inb_cmos(0x78);
201
202 mask_set = mask_clr = 0;
203 if (apic_mode == APICMODE_X2APIC)
204 mask_set = APICBASE_X2APIC;
205 else if (apic_mode == APICMODE_DISABLED)
206 mask_clr = APICBASE_ENABLE;
207 else
208 ; /* Any other setting leaves things alone. */
209
210 if (mask_set || mask_clr) {
211 base_msr = msr_read(APIC_BASE_MSR);
212 base_msr &= ~(uint64_t)mask_clr;
213 base_msr |= mask_set;
214 msr_write(base_msr, APIC_BASE_MSR);
215 }
216}
217
218#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use