1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
|
// 32bit code to Power On Self Test (POST) a machine.
//
// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002 MandrakeSoft S.A.
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
#include "biosvar.h" // SET_BDA
#include "block.h" // block_setup
#include "bregs.h" // struct bregs
#include "config.h" // CONFIG_*
#include "e820map.h" // e820_add
#include "fw/paravirt.h" // qemu_cfg_preinit
#include "fw/xen.h" // xen_preinit
#include "hw/pic.h" // pic_setup
#include "hw/ps2port.h" // ps2port_setup
#include "hw/rtc.h" // rtc_write
#include "hw/serialio.h" // serial_debug_preinit
#include "hw/usb.h" // usb_setup
#include "malloc.h" // malloc_init
#include "memmap.h" // SYMBOL
#include "output.h" // dprintf
#include "string.h" // memset
#include "util.h" // kbd_init
#include "tcgbios.h" // tpm_*
/****************************************************************
* BIOS initialization and hardware setup
****************************************************************/
static void
ivt_init(void)
{
dprintf(3, "init ivt\n");
// Initialize all vectors to the default handler.
int i;
for (i=0; i<256; i++)
SET_IVT(i, FUNC16(entry_iret_official));
// Initialize all hw vectors to a default hw handler.
for (i=BIOS_HWIRQ0_VECTOR; i<BIOS_HWIRQ0_VECTOR+8; i++)
SET_IVT(i, FUNC16(entry_hwpic1));
for (i=BIOS_HWIRQ8_VECTOR; i<BIOS_HWIRQ8_VECTOR+8; i++)
SET_IVT(i, FUNC16(entry_hwpic2));
// Initialize software handlers.
SET_IVT(0x02, FUNC16(entry_02));
SET_IVT(0x05, FUNC16(entry_05));
SET_IVT(0x10, FUNC16(entry_10));
SET_IVT(0x11, FUNC16(entry_11));
SET_IVT(0x12, FUNC16(entry_12));
SET_IVT(0x13, FUNC16(entry_13_official));
SET_IVT(0x14, FUNC16(entry_14));
SET_IVT(0x15, FUNC16(entry_15_official));
SET_IVT(0x16, FUNC16(entry_16));
SET_IVT(0x17, FUNC16(entry_17));
SET_IVT(0x18, FUNC16(entry_18));
SET_IVT(0x19, FUNC16(entry_19_official));
SET_IVT(0x1a, FUNC16(entry_1a_official));
SET_IVT(0x40, FUNC16(entry_40));
// INT 60h-66h reserved for user interrupt
for (i=0x60; i<=0x66; i++)
SET_IVT(i, SEGOFF(0, 0));
// set vector 0x79 to zero
// this is used by 'gardian angel' protection system
SET_IVT(0x79, SEGOFF(0, 0));
}
static void
bda_init(void)
{
dprintf(3, "init bda\n");
struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
memset(bda, 0, sizeof(*bda));
int esize = EBDA_SIZE_START;
u16 ebda_seg = EBDA_SEGMENT_START;
if (!CONFIG_MALLOC_UPPERMEMORY)
ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN(SYMBOL(final_varlow_start), 1024)
- EBDA_SIZE_START*1024);
SET_BDA(ebda_seg, ebda_seg);
SET_BDA(mem_size_kb, ebda_seg / (1024/16));
// Init ebda
struct extended_bios_data_area_s *ebda = get_ebda_ptr();
memset(ebda, 0, sizeof(*ebda));
ebda->size = esize;
e820_add((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED);
// Init extra stack
StackPos = &ExtraStack[BUILD_EXTRA_STACK_SIZE] - SYMBOL(zonelow_base);
}
void
interface_init(void)
{
// Running at new code address - do code relocation fixups
malloc_init();
// Setup romfile items.
qemu_cfg_init();
coreboot_cbfs_init();
multiboot_init();
// Setup ivt/bda/ebda
ivt_init();
bda_init();
// Other interfaces
boot_init();
bios32_init();
pmm_init();
pnp_init();
kbd_init();
mouse_init();
}
// Initialize hardware devices
void
device_hardware_setup(void)
{
usb_setup();
ps2port_setup();
block_setup();
lpt_setup();
serial_setup();
cbfs_payload_setup();
}
static void
platform_hardware_setup(void)
{
// Make sure legacy DMA isn't running.
dma_setup();
// Init base pc hardware.
pic_setup();
thread_setup();
mathcp_setup();
// Platform specific setup
qemu_platform_setup();
coreboot_platform_setup();
// Setup timers and periodic clock interrupt
timer_setup();
clock_setup();
// Initialize TPM
tpm_setup();
}
void
prepareboot(void)
{
// Change TPM phys. presence state befor leaving BIOS
tpm_prepboot();
// Run BCVs
bcv_prepboot();
// Finalize data structures before boot
cdrom_prepboot();
pmm_prepboot();
malloc_prepboot();
e820_prepboot();
HaveRunPost = 2;
// Setup bios checksum.
BiosChecksum -= checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE);
}
// Begin the boot process by invoking an int0x19 in 16bit mode.
void VISIBLE32FLAT
startBoot(void)
{
// Clear low-memory allocations (required by PMM spec).
memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR);
dprintf(3, "Jump to int19\n");
struct bregs br;
memset(&br, 0, sizeof(br));
br.flags = F_IF;
call16_int(0x19, &br);
}
// Main setup code.
static void
maininit(void)
{
// Initialize internal interfaces.
interface_init();
// Setup platform devices.
platform_hardware_setup();
// Start hardware initialization (if threads allowed during optionroms)
if (threads_during_optionroms())
device_hardware_setup();
// Run vga option rom
vgarom_setup();
sercon_setup();
enable_vga_console();
// Do hardware initialization (if running synchronously)
if (!threads_during_optionroms()) {
device_hardware_setup();
wait_threads();
}
// Run option roms
optionrom_setup();
// Allow user to modify overall boot order.
interactive_bootmenu();
wait_threads();
// Prepare for boot.
prepareboot();
// Write protect bios memory.
make_bios_readonly();
// Invoke int 19 to start boot process.
startBoot();
}
/****************************************************************
* POST entry and code relocation
****************************************************************/
// Update given relocs for the code at 'dest' with a given 'delta'
static void
updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta)
{
u32 *reloc;
for (reloc = rstart; reloc < rend; reloc++)
*((u32*)(dest + *reloc)) += delta;
}
// Relocate init code and then call a function at its new address.
// The passed function should be in the "init" section and must not
// return.
void __noreturn
reloc_preinit(void *f, void *arg)
{
void (*func)(void *) __noreturn = f;
if (!CONFIG_RELOCATE_INIT)
func(arg);
// Allocate space for init code.
u32 initsize = SYMBOL(code32init_end) - SYMBOL(code32init_start);
u32 codealign = SYMBOL(_reloc_min_align);
void *codedest = memalign_tmp(codealign, initsize);
void *codesrc = VSYMBOL(code32init_start);
if (!codedest)
panic("No space for init relocation.\n");
// Copy code and update relocs (init absolute, init relative, and runtime)
dprintf(1, "Relocating init from %p to %p (size %d)\n"
, codesrc, codedest, initsize);
s32 delta = codedest - codesrc;
memcpy(codedest, codesrc, initsize);
updateRelocs(codedest, VSYMBOL(_reloc_abs_start), VSYMBOL(_reloc_abs_end)
, delta);
updateRelocs(codedest, VSYMBOL(_reloc_rel_start), VSYMBOL(_reloc_rel_end)
, -delta);
updateRelocs(VSYMBOL(code32flat_start), VSYMBOL(_reloc_init_start)
, VSYMBOL(_reloc_init_end), delta);
if (f >= codesrc && f < VSYMBOL(code32init_end))
func = f + delta;
// Call function in relocated code.
barrier();
func(arg);
}
// Runs after all code is present and prior to any modifications
void
code_mutable_preinit(void)
{
if (HaveRunPost)
// Already run
return;
// Setup reset-vector entry point (controls legacy reboots).
rtc_write(CMOS_RESET_CODE, 0);
barrier();
HaveRunPost = 1;
barrier();
}
// Setup for code relocation and then relocate.
void VISIBLE32INIT
dopost(void)
{
code_mutable_preinit();
// Detect ram and setup internal malloc.
qemu_preinit();
coreboot_preinit();
malloc_preinit();
// Relocate initialization code and call maininit().
reloc_preinit(maininit, NULL);
}
// Entry point for Power On Self Test (POST) - the BIOS initilization
// phase. This function makes the memory at 0xc0000-0xfffff
// read/writable and then calls dopost().
void VISIBLE32FLAT
handle_post(void)
{
if (!CONFIG_QEMU && !CONFIG_COREBOOT)
return;
serial_debug_preinit();
debug_banner();
// Check if we are running under Xen.
xen_preinit();
// Allow writes to modify bios area (0xf0000)
make_bios_writable();
// Now that memory is read/writable - start post process.
dopost();
}
|