VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.6 KB
Line 
1/* $Id: post.c 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * BIOS POST routines. Used only during initialization.
4 */
5
6/*
7 * Copyright (C) 2004-2022 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
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 (rom_init_rtn)(void);
84#pragma aux rom_init_rtn modify [ax bx cx dx si di es] loadds;
85
86/* Scan for ROMs in the given range and execute their POST code. */
87void rom_scan(uint16_t start_seg, uint16_t end_seg)
88{
89 rom_hdr __far *rom;
90 uint8_t rom_blks;
91
92 DPRINT("Scanning for ROMs in %04X-%04X range\n", start_seg, end_seg);
93
94 while (start_seg < end_seg) {
95 rom = MK_FP(start_seg, 0);
96 /* Check for the ROM signature. */
97 if (rom->signature == 0xAA55) {
98 DPRINT("Found ROM at segment %04X\n", start_seg);
99 if (!rom_checksum((void __far *)rom, rom->num_blks)) {
100 rom_init_rtn __far *rom_init;
101
102 /* Checksum good, initialize ROM. */
103 rom_init = (void __far *)&rom->code;
104 rom_init();
105 int_disable();
106 DPRINT("ROM initialized\n");
107
108 /* Continue scanning past the end of this ROM. */
109 rom_blks = (rom->num_blks + 3) & ~3; /* 4 blocks = 2K */
110 start_seg += rom_blks / 4;
111 }
112 } else {
113 /* Scanning is done in 2K steps. */
114 start_seg += 2048 >> 4;
115 }
116 }
117}
118
119#if VBOX_BIOS_CPU >= 80386
120
121/* NB: The CPUID detection is generic but currently not used elsewhere. */
122
123/* Check CPUID availability. */
124int is_cpuid_supported( void )
125{
126 uint32_t old_flags, new_flags;
127
128 old_flags = eflags_read();
129 new_flags = old_flags ^ (1L << 21); /* Toggle CPUID bit. */
130 eflags_write( new_flags );
131 new_flags = eflags_read();
132 return( old_flags != new_flags ); /* Supported if bit changed. */
133}
134
135#define APICMODE_DISABLED 0
136#define APICMODE_APIC 1
137#define APICMODE_X2APIC 2
138
139#define APIC_BASE_MSR 0x1B
140#define APICBASE_X2APIC 0x400 /* bit 10 */
141#define APICBASE_ENABLE 0x800 /* bit 11 */
142
143/*
144 * Set up APIC/x2APIC. See also DevPcBios.cpp.
145 *
146 * NB: Virtual wire compatibility is set up earlier in 32-bit protected
147 * mode assembler (because it needs to access MMIO just under 4GB).
148 * Switching to x2APIC mode or disabling the APIC is done through an MSR
149 * and needs no 32-bit addressing. Going to x2APIC mode does not lose the
150 * existing virtual wire setup.
151 *
152 * NB: This code does not assume that there is a local APIC. It is necessary
153 * to check CPUID whether APIC is present; the CPUID instruction might not be
154 * available either.
155 *
156 * NB: Destroys high bits of 32-bit registers.
157 */
158void BIOSCALL apic_setup(void)
159{
160 uint64_t base_msr;
161 uint16_t mask_set;
162 uint16_t mask_clr;
163 uint8_t apic_mode;
164 uint32_t cpu_id[4];
165
166 /* If there's no CPUID, there's certainly no APIC. */
167 if (!is_cpuid_supported()) {
168 return;
169 }
170
171 /* Check EDX bit 9 */
172 cpuid(&cpu_id, 1);
173 BX_DEBUG("CPUID EDX: 0x%lx\n", cpu_id[3]);
174 if ((cpu_id[3] & (1 << 9)) == 0) {
175 return; /* No local APIC, nothing to do. */
176 }
177
178 /* APIC mode at offset 78h in CMOS NVRAM. */
179 apic_mode = inb_cmos(0x78);
180
181 mask_set = mask_clr = 0;
182 if (apic_mode == APICMODE_X2APIC)
183 mask_set = APICBASE_X2APIC;
184 else if (apic_mode == APICMODE_DISABLED)
185 mask_clr = APICBASE_ENABLE;
186 else
187 ; /* Any other setting leaves things alone. */
188
189 if (mask_set || mask_clr) {
190 base_msr = msr_read(APIC_BASE_MSR);
191 base_msr &= ~(uint64_t)mask_clr;
192 base_msr |= mask_set;
193 msr_write(base_msr, APIC_BASE_MSR);
194 }
195}
196
197#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use