VirtualBox

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

Last change on this file since 73494 was 72499, checked in by vboxsync, 7 years ago

BIOS: Fixed APIC disable logic, it was backwards before. No one probably noticed.

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