VirtualBox

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

Last change on this file since 82176 was 79655, checked in by vboxsync, 5 years ago

BIOS: ROM init routine may clobber registers, duh (see bugref:6549).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.3 KB
Line 
1/* $Id: post.c 79655 2019-07-10 08:18:56Z vboxsync $ */
2/** @file
3 * BIOS POST routines. Used only during initialization.
4 */
5
6/*
7 * Copyright (C) 2004-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <stdint.h>
19#include <string.h>
20#include "biosint.h"
21#include "inlines.h"
22
23#if DEBUG_POST
24# define DPRINT(...) BX_DEBUG(__VA_ARGS__)
25#else
26# define DPRINT(...)
27#endif
28
29/* In general, checksumming ROMs in a VM just wastes time. */
30//#define CHECKSUM_ROMS
31
32/* The format of a ROM is as follows:
33 *
34 * ------------------------------
35 * 0 | AA55h signature (word) |
36 * ------------------------------
37 * 2 | Size in 512B blocks (byte) |
38 * ------------------------------
39 * 3 | Start of executable code |
40 * | ....... |
41 * end | |
42 * ------------------------------
43 */
44
45typedef struct rom_hdr_tag {
46 uint16_t signature;
47 uint8_t num_blks;
48 uint8_t code;
49} rom_hdr;
50
51
52/* Calculate the checksum of a ROM. Note that the ROM might be
53 * larger than 64K.
54 */
55static inline uint8_t rom_checksum(uint8_t __far *rom, uint8_t blocks)
56{
57 uint8_t sum = 0;
58
59#ifdef CHECKSUM_ROMS
60 while (blocks--) {
61 int i;
62
63 for (i = 0; i < 512; ++i)
64 sum += rom[i];
65 /* Add 512 bytes (32 paragraphs) to segment. */
66 rom = MK_FP(FP_SEG(rom) + (512 >> 4), 0);
67 }
68#endif
69 return sum;
70}
71
72/* The ROM init routine might trash register. Give the compiler a heads-up. */
73typedef void (rom_init_rtn)(void);
74#pragma aux rom_init_rtn modify [ax bx cx dx si di es] loadds;
75
76/* Scan for ROMs in the given range and execute their POST code. */
77void rom_scan(uint16_t start_seg, uint16_t end_seg)
78{
79 rom_hdr __far *rom;
80 uint8_t rom_blks;
81
82 DPRINT("Scanning for ROMs in %04X-%04X range\n", start_seg, end_seg);
83
84 while (start_seg < end_seg) {
85 rom = MK_FP(start_seg, 0);
86 /* Check for the ROM signature. */
87 if (rom->signature == 0xAA55) {
88 DPRINT("Found ROM at segment %04X\n", start_seg);
89 if (!rom_checksum((void __far *)rom, rom->num_blks)) {
90 rom_init_rtn __far *rom_init;
91
92 /* Checksum good, initialize ROM. */
93 rom_init = (void __far *)&rom->code;
94 rom_init();
95 int_disable();
96 DPRINT("ROM initialized\n");
97
98 /* Continue scanning past the end of this ROM. */
99 rom_blks = (rom->num_blks + 3) & ~3; /* 4 blocks = 2K */
100 start_seg += rom_blks / 4;
101 }
102 } else {
103 /* Scanning is done in 2K steps. */
104 start_seg += 2048 >> 4;
105 }
106 }
107}
108
109#if VBOX_BIOS_CPU >= 80386
110
111/* NB: The CPUID detection is generic but currently not used elsewhere. */
112
113/* Check CPUID availability. */
114int is_cpuid_supported( void )
115{
116 uint32_t old_flags, new_flags;
117
118 old_flags = eflags_read();
119 new_flags = old_flags ^ (1L << 21); /* Toggle CPUID bit. */
120 eflags_write( new_flags );
121 new_flags = eflags_read();
122 return( old_flags != new_flags ); /* Supported if bit changed. */
123}
124
125#define APICMODE_DISABLED 0
126#define APICMODE_APIC 1
127#define APICMODE_X2APIC 2
128
129#define APIC_BASE_MSR 0x1B
130#define APICBASE_X2APIC 0x400 /* bit 10 */
131#define APICBASE_ENABLE 0x800 /* bit 11 */
132
133/*
134 * Set up APIC/x2APIC. See also DevPcBios.cpp.
135 *
136 * NB: Virtual wire compatibility is set up earlier in 32-bit protected
137 * mode assembler (because it needs to access MMIO just under 4GB).
138 * Switching to x2APIC mode or disabling the APIC is done through an MSR
139 * and needs no 32-bit addressing. Going to x2APIC mode does not lose the
140 * existing virtual wire setup.
141 *
142 * NB: This code does not assume that there is a local APIC. It is necessary
143 * to check CPUID whether APIC is present; the CPUID instruction might not be
144 * available either.
145 *
146 * NB: Destroys high bits of 32-bit registers.
147 */
148void BIOSCALL apic_setup(void)
149{
150 uint64_t base_msr;
151 uint16_t mask_set;
152 uint16_t mask_clr;
153 uint8_t apic_mode;
154 uint32_t cpu_id[4];
155
156 /* If there's no CPUID, there's certainly no APIC. */
157 if (!is_cpuid_supported()) {
158 return;
159 }
160
161 /* Check EDX bit 9 */
162 cpuid(&cpu_id, 1);
163 BX_DEBUG("CPUID EDX: 0x%lx\n", cpu_id[3]);
164 if ((cpu_id[3] & (1 << 9)) == 0) {
165 return; /* No local APIC, nothing to do. */
166 }
167
168 /* APIC mode at offset 78h in CMOS NVRAM. */
169 apic_mode = inb_cmos(0x78);
170
171 mask_set = mask_clr = 0;
172 if (apic_mode == APICMODE_X2APIC)
173 mask_set = APICBASE_X2APIC;
174 else if (apic_mode == APICMODE_DISABLED)
175 mask_clr = APICBASE_ENABLE;
176 else
177 ; /* Any other setting leaves things alone. */
178
179 if (mask_set || mask_clr) {
180 base_msr = msr_read(APIC_BASE_MSR);
181 base_msr &= ~(uint64_t)mask_clr;
182 base_msr |= mask_set;
183 msr_write(base_msr, APIC_BASE_MSR);
184 }
185}
186
187#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette