From 3e77eb6d1e0a3ff9c0a32504a5221dc57b10506c Mon Sep 17 00:00:00 2001 From: Patrick Georgi Date: Thu, 22 Nov 2012 10:39:16 +0100 Subject: x86emu: Move realmode handler into own directory It's really a feature in parallel to YABEL/x86emu. Reflect this in the directory structure. Change-Id: Ie88e4fa6bfef13d23c55b2db3faacbd90f8cc30b Signed-off-by: Patrick Georgi Reviewed-on: http://review.coreboot.org/1889 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/devices/oprom/Makefile.inc | 6 +- src/devices/oprom/realmode/Makefile.inc | 23 ++ src/devices/oprom/realmode/x86.c | 469 ++++++++++++++++++++++++++++ src/devices/oprom/realmode/x86.h | 49 +++ src/devices/oprom/realmode/x86_asm.S | 413 ++++++++++++++++++++++++ src/devices/oprom/realmode/x86_interrupts.c | 233 ++++++++++++++ src/devices/oprom/x86.c | 469 ---------------------------- src/devices/oprom/x86.h | 49 --- src/devices/oprom/x86_asm.S | 413 ------------------------ src/devices/oprom/x86_interrupts.c | 233 -------------- src/northbridge/via/cx700/vga.c | 2 +- src/northbridge/via/vt8623/vga.c | 2 +- src/northbridge/via/vx800/vga.c | 2 +- 13 files changed, 1192 insertions(+), 1171 deletions(-) create mode 100644 src/devices/oprom/realmode/Makefile.inc create mode 100644 src/devices/oprom/realmode/x86.c create mode 100644 src/devices/oprom/realmode/x86.h create mode 100644 src/devices/oprom/realmode/x86_asm.S create mode 100644 src/devices/oprom/realmode/x86_interrupts.c delete mode 100644 src/devices/oprom/x86.c delete mode 100644 src/devices/oprom/x86.h delete mode 100644 src/devices/oprom/x86_asm.S delete mode 100644 src/devices/oprom/x86_interrupts.c diff --git a/src/devices/oprom/Makefile.inc b/src/devices/oprom/Makefile.inc index 62fdc3182a..aa4a74d4d8 100644 --- a/src/devices/oprom/Makefile.inc +++ b/src/devices/oprom/Makefile.inc @@ -17,9 +17,7 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ## -ramstage-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86.c -ramstage-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_asm.S -ramstage-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_interrupts.c - subdirs-$(CONFIG_PCI_OPTION_ROM_RUN_YABEL) += x86emu subdirs-$(CONFIG_PCI_OPTION_ROM_RUN_YABEL) += yabel +subdirs-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += realmode + diff --git a/src/devices/oprom/realmode/Makefile.inc b/src/devices/oprom/realmode/Makefile.inc new file mode 100644 index 0000000000..fafeb2c573 --- /dev/null +++ b/src/devices/oprom/realmode/Makefile.inc @@ -0,0 +1,23 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 secunet Security Networks AG +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +ramstage-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86.c +ramstage-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_asm.S +ramstage-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_interrupts.c + diff --git a/src/devices/oprom/realmode/x86.c b/src/devices/oprom/realmode/x86.c new file mode 100644 index 0000000000..32d24ec1c3 --- /dev/null +++ b/src/devices/oprom/realmode/x86.c @@ -0,0 +1,469 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2009-2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "x86.h" +#include "vbe.h" +#include + +void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, + u32 esi, u32 edi) __attribute__((regparm(0))) = + (void *)&__realmode_call; + +void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, u32 edx, + u32 esi, u32 edi) __attribute__((regparm(0))) = + (void *)&__realmode_interrupt; + +static void setup_rombios(void) +{ + const char date[] = "06/11/99"; + memcpy((void *)0xffff5, &date, 8); + + const char ident[] = "PCI_ISA"; + memcpy((void *)0xfffd9, &ident, 7); + + /* system model: IBM-AT */ + write8(0xffffe, 0xfc); +} + +int (*intXX_handler[256])(struct eregs *regs) = { NULL }; + +static int intXX_exception_handler(struct eregs *regs) +{ + printk(BIOS_INFO, "Oops, exception %d while executing option rom\n", + regs->vector); + x86_exception(regs); // Call coreboot exception handler + + return 0; // Never really returns +} + +static int intXX_unknown_handler(struct eregs *regs) +{ + printk(BIOS_INFO, "Unsupported software interrupt #0x%x eax 0x%x\n", + regs->vector, regs->eax); + + return -1; +} + +/* setup interrupt handlers for mainboard */ +void mainboard_interrupt_handlers(int intXX, void *intXX_func) +{ + intXX_handler[intXX] = intXX_func; +} + +static void setup_interrupt_handlers(void) +{ + int i; + + /* The first 16 intXX functions are not BIOS services, + * but the CPU-generated exceptions ("hardware interrupts") + */ + for (i = 0; i < 0x10; i++) + intXX_handler[i] = &intXX_exception_handler; + + /* Mark all other intXX calls as unknown first */ + for (i = 0x10; i < 0x100; i++) + { + /* If the mainboard_interrupt_handler isn't called first. + */ + if(!intXX_handler[i]) + { + /* Now set the default functions that are actually + * needed to initialize the option roms. This is + * very slick, as it allows us to implement mainboard + * specific interrupt handlers, such as the int15. + */ + switch (i) { + case 0x10: + intXX_handler[0x10] = &int10_handler; + break; + case 0x12: + intXX_handler[0x12] = &int12_handler; + break; + case 0x16: + intXX_handler[0x16] = &int16_handler; + break; + case 0x1a: + intXX_handler[0x1a] = &int1a_handler; + break; + default: + intXX_handler[i] = &intXX_unknown_handler; + break; + } + } + } +} + +static void write_idt_stub(void *target, u8 intnum) +{ + unsigned char *codeptr; + codeptr = (unsigned char *) target; + memcpy(codeptr, &__idt_handler, (size_t)&__idt_handler_size); + codeptr[3] = intnum; /* modify int# in the code stub. */ +} + +static void setup_realmode_idt(void) +{ + struct realmode_idt *idts = (struct realmode_idt *) 0; + int i; + + /* Copy IDT stub code for each interrupt. This might seem wasteful + * but it is really simple + */ + for (i = 0; i < 256; i++) { + idts[i].cs = 0; + idts[i].offset = 0x1000 + (i * (u32)&__idt_handler_size); + write_idt_stub((void *)((u32 )idts[i].offset), i); + } + + /* Many option ROMs use the hard coded interrupt entry points in the + * system bios. So install them at the known locations. + */ + + /* int42 is the relocated int10 */ + write_idt_stub((void *)0xff065, 0x42); + /* BIOS Int 11 Handler F000:F84D */ + write_idt_stub((void *)0xff84d, 0x11); + /* BIOS Int 12 Handler F000:F841 */ + write_idt_stub((void *)0xff841, 0x12); + /* BIOS Int 13 Handler F000:EC59 */ + write_idt_stub((void *)0xfec59, 0x13); + /* BIOS Int 14 Handler F000:E739 */ + write_idt_stub((void *)0xfe739, 0x14); + /* BIOS Int 15 Handler F000:F859 */ + write_idt_stub((void *)0xff859, 0x15); + /* BIOS Int 16 Handler F000:E82E */ + write_idt_stub((void *)0xfe82e, 0x16); + /* BIOS Int 17 Handler F000:EFD2 */ + write_idt_stub((void *)0xfefd2, 0x17); + /* ROM BIOS Int 1A Handler F000:FE6E */ + write_idt_stub((void *)0xffe6e, 0x1a); +} + +#if CONFIG_FRAMEBUFFER_SET_VESA_MODE +vbe_mode_info_t mode_info; +static int mode_info_valid; + +int vbe_mode_info_valid(void) +{ + return mode_info_valid; +} + +static u8 vbe_get_mode_info(vbe_mode_info_t * mi) +{ + printk(BIOS_DEBUG, "VBE: Getting information about VESA mode %04x\n", + mi->video_mode); + char *buffer = (char *)&__buffer; + u16 buffer_seg = (((unsigned long)buffer) >> 4) & 0xff00; + u16 buffer_adr = ((unsigned long)buffer) & 0xffff; + realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, + mi->video_mode, 0x0000, buffer_seg, buffer_adr); + memcpy(mi->mode_info_block, buffer, sizeof(vbe_mode_info_t)); + mode_info_valid = 1; + return 0; +} + +static u8 vbe_set_mode(vbe_mode_info_t * mi) +{ + printk(BIOS_DEBUG, "VBE: Setting VESA mode %04x\n", mi->video_mode); + // request linear framebuffer mode + mi->video_mode |= (1 << 14); + // request clearing of framebuffer + mi->video_mode &= ~(1 << 15); + realmode_interrupt(0x10, VESA_SET_MODE, mi->video_mode, + 0x0000, 0x0000, 0x0000, 0x0000); + return 0; +} + +/* These two functions could probably even be generic between + * yabel and x86 native. TBD later. + */ +void vbe_set_graphics(void) +{ + mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE; + vbe_get_mode_info(&mode_info); + unsigned char *framebuffer = + (unsigned char *)mode_info.vesa.phys_base_ptr; + printk(BIOS_DEBUG, "VBE: resolution: %dx%d@%d\n", + le16_to_cpu(mode_info.vesa.x_resolution), + le16_to_cpu(mode_info.vesa.y_resolution), + mode_info.vesa.bits_per_pixel); + printk(BIOS_DEBUG, "VBE: framebuffer: %p\n", framebuffer); + if (!framebuffer) { + printk(BIOS_DEBUG, "VBE: Mode does not support linear " + "framebuffer\n"); + return; + } + + vbe_set_mode(&mode_info); +#if CONFIG_BOOTSPLASH + struct jpeg_decdata *decdata; + decdata = malloc(sizeof(*decdata)); + unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", + CBFS_TYPE_BOOTSPLASH); + if (!jpeg) { + printk(BIOS_DEBUG, "VBE: No bootsplash found.\n"); + return; + } + int ret = 0; + ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata); +#endif +} + +void vbe_textmode_console(void) +{ + delay(2); + realmode_interrupt(0x10, 0x0003, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000); +} + +void fill_lb_framebuffer(struct lb_framebuffer *framebuffer) +{ + framebuffer->physical_address = mode_info.vesa.phys_base_ptr; + + framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution); + framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution); + framebuffer->bytes_per_line = + le16_to_cpu(mode_info.vesa.bytes_per_scanline); + framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel; + + framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos; + framebuffer->red_mask_size = mode_info.vesa.red_mask_size; + + framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos; + framebuffer->green_mask_size = mode_info.vesa.green_mask_size; + + framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos; + framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size; + + framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos; + framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size; +} +#endif + +void run_bios(struct device *dev, unsigned long addr) +{ + u32 num_dev = (dev->bus->secondary << 8) | dev->path.pci.devfn; + + /* Setting up required hardware. + * Removing this will cause random illegal instruction exceptions + * in some option roms. + */ + setup_i8259(); + + /* Set up some legacy information in the F segment */ + setup_rombios(); + + /* Set up C interrupt handlers */ + setup_interrupt_handlers(); + + /* Set up real-mode IDT */ + setup_realmode_idt(); + + memcpy(REALMODE_BASE, &__realmode_code, (size_t)&__realmode_code_size); + printk(BIOS_SPEW, "Real mode stub @%p: %d bytes\n", REALMODE_BASE, + (u32)&__realmode_code_size); + + printk(BIOS_DEBUG, "Calling Option ROM...\n"); + /* TODO ES:DI Pointer to System BIOS PnP Installation Check Structure */ + /* Option ROM entry point is at OPROM start + 3 */ + realmode_call(addr + 0x0003, num_dev, 0xffff, 0x0000, 0xffff, 0x0, 0x0); + printk(BIOS_DEBUG, "... Option ROM returned.\n"); + +#if CONFIG_FRAMEBUFFER_SET_VESA_MODE + vbe_set_graphics(); +#endif +} + +#if CONFIG_GEODE_VSA +#include +#include +#include + +#define VSA2_BUFFER 0x60000 +#define VSA2_ENTRY_POINT 0x60020 + +// TODO move to a header file. +void do_vsmbios(void); + +/* VSA virtual register helper */ +static u32 VSA_vrRead(u16 classIndex) +{ + u32 eax, ebx, ecx, edx; + asm volatile ( + "movw $0x0AC1C, %%dx\n" + "orl $0x0FC530000, %%eax\n" + "outl %%eax, %%dx\n" + "addb $2, %%dl\n" + "inw %%dx, %%ax\n" + : "=a" (eax), "=b"(ebx), "=c"(ecx), "=d"(edx) + : "a"(classIndex) + ); + + return eax; +} + +void do_vsmbios(void) +{ + printk(BIOS_DEBUG, "Preparing for VSA...\n"); + + /* Set up C interrupt handlers */ + setup_interrupt_handlers(); + + /* Setting up realmode IDT */ + setup_realmode_idt(); + + memcpy(REALMODE_BASE, &__realmode_code, (size_t)&__realmode_code_size); + printk(BIOS_SPEW, "VSA: Real mode stub @%p: %d bytes\n", REALMODE_BASE, + (u32)&__realmode_code_size); + + if ((unsigned int)cbfs_load_stage("vsa") != VSA2_ENTRY_POINT) { + printk(BIOS_ERR, "Failed to load VSA.\n"); + return; + } + + unsigned char *buf = (unsigned char *)VSA2_BUFFER; + printk(BIOS_DEBUG, "VSA: Buffer @%p *[0k]=%02x\n", buf, buf[0]); + printk(BIOS_DEBUG, "VSA: Signature *[0x20-0x23] is %02x:%02x:%02x:%02x\n", + buf[0x20], buf[0x21], buf[0x22], buf[0x23]); + + /* Check for code to emit POST code at start of VSA. */ + if ((buf[0x20] != 0xb0) || (buf[0x21] != 0x10) || + (buf[0x22] != 0xe6) || (buf[0x23] != 0x80)) { + printk(BIOS_WARNING, "VSA: Signature incorrect. Install failed.\n"); + return; + } + + printk(BIOS_DEBUG, "Calling VSA module...\n"); + + /* ECX gets SMM, EDX gets SYSMEM */ + realmode_call(VSA2_ENTRY_POINT, 0x0, 0x0, MSR_GLIU0_SMM, + MSR_GLIU0_SYSMEM, 0x0, 0x0); + + printk(BIOS_DEBUG, "... VSA module returned.\n"); + + /* Restart timer 1 */ + outb(0x56, 0x43); + outb(0x12, 0x41); + + /* Check that VSA is running OK */ + if (VSA_vrRead(SIGNATURE) == VSA2_SIGNATURE) + printk(BIOS_DEBUG, "VSM: VSA2 VR signature verified.\n"); + else + printk(BIOS_ERR, "VSM: VSA2 VR signature not valid. Install failed.\n"); +} +#endif + +/* interrupt_handler() is called from assembler code only, + * so there is no use in putting the prototype into a header file. + */ +int __attribute__((regparm(0))) interrupt_handler(u32 intnumber, + u32 gsfs, u32 dses, + u32 edi, u32 esi, + u32 ebp, u32 esp, + u32 ebx, u32 edx, + u32 ecx, u32 eax, + u32 cs_ip, u16 stackflags); + +int __attribute__((regparm(0))) interrupt_handler(u32 intnumber, + u32 gsfs, u32 dses, + u32 edi, u32 esi, + u32 ebp, u32 esp, + u32 ebx, u32 edx, + u32 ecx, u32 eax, + u32 cs_ip, u16 stackflags) +{ + u32 ip; + u32 cs; + u32 flags; + int ret = -1; + struct eregs reg_info; + + ip = cs_ip & 0xffff; + cs = cs_ip >> 16; + flags = stackflags; + +#if CONFIG_REALMODE_DEBUG + printk(BIOS_DEBUG, "oprom: INT# 0x%x\n", intnumber); + printk(BIOS_DEBUG, "oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n", + eax, ebx, ecx, edx); + printk(BIOS_DEBUG, "oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n", + ebp, esp, edi, esi); + printk(BIOS_DEBUG, "oprom: ip: %04x cs: %04x flags: %08x\n", + ip, cs, flags); +#endif + + // Fetch arguments from the stack and put them into + // a structure that we want to pass on to our sub interrupt + // handlers. + reg_info = (struct eregs) { + .eax=eax, + .ecx=ecx, + .edx=edx, + .ebx=ebx, + .esp=esp, + .ebp=ebp, + .esi=esi, + .edi=edi, + .vector=intnumber, + .error_code=0, // ?? + .eip=ip, + .cs=cs, + .eflags=flags // ?? + }; + + // Call the interrupt handler for this int# + ret = intXX_handler[intnumber](®_info); + + // Put registers back on the stack. The assembler code + // will later pop them. + // What happens here is that we force (volatile!) changing + // the values of the parameters of this function. We do this + // because we know that they stay alive on the stack after + // we leave this function. Don't say this is bollocks. + *(volatile u32 *)&eax = reg_info.eax; + *(volatile u32 *)&ecx = reg_info.ecx; + *(volatile u32 *)&edx = reg_info.edx; + *(volatile u32 *)&ebx = reg_info.ebx; + *(volatile u32 *)&esi = reg_info.esi; + *(volatile u32 *)&edi = reg_info.edi; + flags = reg_info.eflags; + + /* Pass errors back to our caller via the CARRY flag */ + if (ret) { + printk(BIOS_DEBUG,"int%02x call returned error.\n", intnumber); + flags |= 1; // error: set carry + }else{ + flags &= ~1; // no error: clear carry + } + *(volatile u16 *)&stackflags = flags; + + return ret; +} + diff --git a/src/devices/oprom/realmode/x86.h b/src/devices/oprom/realmode/x86.h new file mode 100644 index 0000000000..40c5778de5 --- /dev/null +++ b/src/devices/oprom/realmode/x86.h @@ -0,0 +1,49 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2009-2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#define REALMODE_BASE ((void *)0x600) + +struct realmode_idt { + u16 offset, cs; +}; + +void x86_exception(struct eregs *info); + +/* From x86_asm.S */ +extern unsigned char __idt_handler, __idt_handler_size; +extern unsigned char __realmode_code, __realmode_code_size; +extern unsigned char __realmode_call, __realmode_interrupt; +extern unsigned char __buffer; + +extern void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, + u32 esi, u32 edi) __attribute__((regparm(0))); + +extern void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, u32 edx, + u32 esi, u32 edi) __attribute__((regparm(0))); + +#define FAKE_MEMORY_SIZE (1024*1024) // only 1MB +#define INITIAL_EBDA_SEGMENT 0xF600 +#define INITIAL_EBDA_SIZE 0x400 + +int int10_handler(struct eregs *regs); +int int12_handler(struct eregs *regs); +int int16_handler(struct eregs *regs); +int int1a_handler(struct eregs *regs); + diff --git a/src/devices/oprom/realmode/x86_asm.S b/src/devices/oprom/realmode/x86_asm.S new file mode 100644 index 0000000000..56ebb3a885 --- /dev/null +++ b/src/devices/oprom/realmode/x86_asm.S @@ -0,0 +1,413 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#define REALMODE_BASE 0x600 +#define RELOCATED(x) (x - __realmode_code + REALMODE_BASE) + +/* CR0 bits */ +#define PE (1 << 0) + +/* This is the intXX interrupt handler stub code. It gets copied + * to the IDT and to some fixed addresses in the F segment. Before + * the code can used, it gets patched up by the C function copying + * it: byte 3 (the $0 in movb $0, %al) is overwritten with the int#. + */ + + .code16 + .globl __idt_handler +__idt_handler: + pushal + movb $0, %al /* This instruction gets modified */ + ljmp $0, $__interrupt_handler_16bit + .globl __idt_handler_size +__idt_handler_size = ( . - __idt_handler) + + +/* In order to be independent of coreboot's position in RAM + * we relocate a part of the code to the low megabyte, so the + * CPU can use it in real-mode. This code lives at __realmode_code. + */ + .globl __realmode_code +__realmode_code: + +/* Realmode IDT pointer structure. */ + .globl __realmode_idt +__realmode_idt = RELOCATED(.) + .word 1023 /* 16 bit limit */ + .long 0 /* 24 bit base */ + .word 0 + +/* Preserve old stack */ +__stack = RELOCATED(.) + .long 0 + +/* Register store for realmode_call and realmode_interrupt */ +__registers = RELOCATED(.) + .long 0 /* 0 - EAX */ + .long 0 /* 4 - EBX */ + .long 0 /* 8 - ECX */ + .long 0 /* 12 - EDX */ + .long 0 /* 16 - ESI */ + .long 0 /* 20 - EDI */ + +/* 256 byte buffer, used by int10 */ + .globl __buffer +__buffer = RELOCATED(.) + .skip 256 + + .code32 + .globl __realmode_call +__realmode_call = RELOCATED(.) + /* save all registers to the stack */ + pusha + pushf + + /* Move the protected mode stack pointer to a safe place */ + movl %esp, __stack + movl %esp, %ebp + + /* This function is called with regparm=0 and we have to + * skip the 36 byte from pushf+pusha. Hence start at 40. + */ + + /* entry point */ + movl 40(%ebp), %eax + mov %ax, __lcall_instr + 1 + andl $0xffff0000, %eax + shrl $4, %eax + mov %ax, __lcall_instr + 3 + + /* initial register values */ + movl 44(%ebp), %eax + movl %eax, __registers + 0 /* eax */ + movl 48(%ebp), %eax + movl %eax, __registers + 4 /* ebx */ + movl 52(%ebp), %eax + movl %eax, __registers + 8 /* ecx */ + movl 56(%ebp), %eax + movl %eax, __registers + 12 /* edx */ + movl 60(%ebp), %eax + movl %eax, __registers + 16 /* esi */ + movl 64(%ebp), %eax + movl %eax, __registers + 20 /* edi */ + + /* Activate the right segment descriptor real mode. */ + ljmp $0x28, $RELOCATED(1f) +1: +.code16 + /* 16 bit code from here on... */ + + /* Load the segment registers w/ properly configured + * segment descriptors. They will retain these + * configurations (limits, writability, etc.) once + * protected mode is turned off. + */ + mov $0x30, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* Turn off protection */ + movl %cr0, %eax + andl $~PE, %eax + movl %eax, %cr0 + + /* Now really going into real mode */ + ljmp $0, $RELOCATED(1f) +1: + /* Setup a stack: Put the stack at the end of page zero. + * That way we can easily share it between real and + * protected, since the 16 bit ESP at segment 0 will + * work for any case. */ + mov $0x0, %ax + mov %ax, %ss + movl $0x1000, %eax + movl %eax, %esp + + /* Load 16 bit IDT */ + xor %ax, %ax + mov %ax, %ds + lidt __realmode_idt + + /* initialize registers for option rom lcall */ + movl __registers + 0, %eax + movl __registers + 4, %ebx + movl __registers + 8, %ecx + movl __registers + 12, %edx + movl __registers + 16, %esi + movl __registers + 20, %edi + + /* Set all segments to 0x0000, ds to 0x0040 */ + push %ax + xor %ax, %ax + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov $0x40, %ax + mov %ax, %ds + pop %ax + + /* ************************************ */ +__lcall_instr = RELOCATED(.) + .byte 0x9a + .word 0x0000, 0x0000 + /* ************************************ */ + + /* If we got here, we are just about done. + * Need to get back to protected mode. + */ + movl %cr0, %eax + orl $PE, %eax + movl %eax, %cr0 + + /* Now that we are in protected mode + * jump to a 32 bit code segment. + */ + data32 ljmp $0x10, $RELOCATED(1f) +1: + .code32 + mov $0x18, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* restore proper idt */ + lidt idtarg + + /* restore stack pointer, eflags and register values */ + movl __stack, %esp + popf + popa + + /* and exit */ + // TODO return AX from OPROM call + ret + + .globl __realmode_interrupt +__realmode_interrupt = RELOCATED(.) + /* save all registers to the stack */ + pusha + pushf + + /* save the stack pointer */ + movl %esp, __stack + movl %esp, %ebp + + /* This function is called with regparm=0 and we have to + * skip the 36 byte from pushf+pusha. Hence start at 40. + */ + + /* prepare interrupt calling code */ + movl 40(%ebp), %eax + movb %al, __intXX_instr + 1 /* intno */ + + /* initial register values */ + movl 44(%ebp), %eax + movl %eax, __registers + 0 /* eax */ + movl 48(%ebp), %eax + movl %eax, __registers + 4 /* ebx */ + movl 52(%ebp), %eax + movl %eax, __registers + 8 /* ecx */ + movl 56(%ebp), %eax + movl %eax, __registers + 12 /* edx */ + movl 60(%ebp), %eax + movl %eax, __registers + 16 /* esi */ + movl 64(%ebp), %eax + movl %eax, __registers + 20 /* edi */ + + /* This configures CS properly for real mode. */ + ljmp $0x28, $RELOCATED(1f) +1: + .code16 /* 16 bit code from here on... */ + + /* Load the segment registers w/ properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. + */ + mov $0x30, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* Turn off protected mode */ + movl %cr0, %eax + andl $~PE, %eax + movl %eax, %cr0 + + /* Now really going into real mode */ + data32 ljmp $0, $RELOCATED(1f) +1: + + /* put the stack at the end of page zero. That way we can easily + * share it between real mode and protected mode, because %esp and + * %ss:%sp point to the same memory. + */ + /* setup a stack */ + mov $0x0, %ax + mov %ax, %ss + movl $0x1000, %eax + movl %eax, %esp + + /* Load 16-bit intXX IDT */ + xor %ax, %ax + mov %ax, %ds + lidt __realmode_idt + + /* initialize registers for intXX call */ + movl __registers + 0, %eax + movl __registers + 4, %ebx + movl __registers + 8, %ecx + movl __registers + 12, %edx + movl __registers + 16, %esi + movl __registers + 20, %edi + + /* Set all segments to 0x0000 */ + push %ax + xor %ax, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + pop %ax + +__intXX_instr = RELOCATED(.) + .byte 0xcd, 0x00 /* This becomes intXX */ + + /* Ok, the job is done, now go back to protected mode coreboot */ + movl %cr0, %eax + orl $PE, %eax + movl %eax, %cr0 + + /* Now that we are in protected mode jump to a 32-bit code segment. */ + data32 ljmp $0x10, $RELOCATED(1f) +1: + .code32 + mov $0x18, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* restore coreboot's 32-bit IDT */ + lidt idtarg + + /* restore stack pointer, eflags and register values and exit */ + movl __stack, %esp + popf + popa + ret + +/* This is the 16-bit interrupt entry point called by the IDT stub code. + * + * Before this code code is called, %eax is pushed to the stack, and the + * interrupt number is loaded into %al. On return this function cleans up + * for its caller. + */ + .code16 +__interrupt_handler_16bit = RELOCATED(.) + push %ds + push %es + push %fs + push %gs + + /* Clear DF to not break ABI assumptions */ + cld + + /* Clean up the interrupt number. We could have done this in the stub, + * but it would have cost 2 more bytes per stub entry. + */ + andl $0xff, %eax + pushl %eax /* ... and make it the first parameter */ + + /* Switch to protected mode */ + movl %cr0, %eax + orl $PE, %eax + movl %eax, %cr0 + + /* ... and jump to a 32 bit code segment. */ + data32 ljmp $0x10, $RELOCATED(1f) +1: + .code32 + mov $0x18, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + lidt idtarg + + /* Call the C interrupt handler */ + movl $interrupt_handler, %eax + call *%eax + + /* Now return to real mode ... */ + ljmp $0x28, $RELOCATED(1f) +1: + .code16 + /* Load the segment registers with properly configured segment + * descriptors. They will retain these configurations (limits, + * writability, etc.) once protected mode is turned off. + */ + mov $0x30, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* Disable Protected Mode */ + movl %cr0, %eax + andl $~PE, %eax + movl %eax, %cr0 + + /* Now really going into real mode */ + ljmp $0, $RELOCATED(1f) +1: + /* Restore real-mode stack segment */ + mov $0x0, %ax + mov %ax, %ss + + /* Restore 16 bit IDT */ + xor %ax, %ax + mov %ax, %ds + lidt __realmode_idt + + /* Restore all registers, including those + * manipulated by the C handler + */ + popl %eax + pop %gs + pop %fs + pop %es + pop %ds + popal + iret + + .globl __realmode_code_size +__realmode_code_size = (. - __realmode_code) + + .code32 diff --git a/src/devices/oprom/realmode/x86_interrupts.c b/src/devices/oprom/realmode/x86_interrupts.c new file mode 100644 index 0000000000..2ea05d44ba --- /dev/null +++ b/src/devices/oprom/realmode/x86_interrupts.c @@ -0,0 +1,233 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2001 Ronald G. Minnich + * Copyright (C) 2005 Nick.Barker9@btinternet.com + * Copyright (C) 2007-2009 coresystems GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "x86.h" + +// errors go in AH. Just set these up so that word assigns +// will work. KISS. +enum { + PCIBIOS_SUCCESSFUL = 0x0000, + PCIBIOS_UNSUPPORTED = 0x8100, + PCIBIOS_BADVENDOR = 0x8300, + PCIBIOS_NODEV = 0x8600, + PCIBIOS_BADREG = 0x8700 +}; + +int int10_handler(struct eregs *regs) +{ + int res=-1; + static u8 cursor_row=0, cursor_col=0; + switch((regs->eax & 0xff00)>>8) { + case 0x01: // Set cursor shape + res = 0; + break; + case 0x02: // Set cursor position + if (cursor_row != ((regs->edx >> 8) & 0xff) || + cursor_col >= (regs->edx & 0xff)) { + printk(BIOS_INFO, "\n"); + } + cursor_row = (regs->edx >> 8) & 0xff; + cursor_col = regs->edx & 0xff; + res = 0; + break; + case 0x03: // Get cursor position + regs->eax &= 0x00ff; + regs->ecx = 0x0607; + regs->edx = (cursor_row << 8) | cursor_col; + res = 0; + break; + case 0x06: // Scroll up + printk(BIOS_INFO, "\n"); + res = 0; + break; + case 0x08: // Get Character and Mode at Cursor Position + regs->eax = 0x0f00 | 'A'; // White on black 'A' + res = 0; + break; + case 0x09: // Write Character and attribute + case 0x0e: // Write Character + printk(BIOS_INFO, "%c", regs->eax & 0xff); + res = 0; + break; + case 0x0f: // Get video mode + regs->eax = 0x5002; //80x25 + regs->ebx &= 0x00ff; + res = 0; + break; + default: + printk(BIOS_WARNING, "Unknown INT10 function %04x!\n", + regs->eax & 0xffff); + break; + } + return res; +} + +int int12_handler(struct eregs *regs) +{ + regs->eax = 64 * 1024; + return 0; +} + +int int16_handler(struct eregs *regs) +{ + int res=-1; + switch((regs->eax & 0xff00)>>8) { + case 0x00: // Check for Keystroke + regs->eax = 0x6120; // Space Bar, Space + res = 0; + break; + case 0x01: // Check for Keystroke + regs->eflags |= 1<<6; // Zero Flag set (no key available) + res = 0; + break; + default: + printk(BIOS_WARNING, "Unknown INT16 function %04x!\n", + regs->eax & 0xffff); + break; + } + return res; +} + +#define PCI_CONFIG_SPACE_TYPE1 (1 << 0) +#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4) + +int int1a_handler(struct eregs *regs) +{ + unsigned short func = (unsigned short)regs->eax; + int retval = 0; + unsigned short devid, vendorid, devfn; + /* Use short to get rid of gabage in upper half of 32-bit register */ + short devindex; + unsigned char bus; + struct device *dev; + u32 dword; + u16 word; + u8 byte, reg; + + switch (func) { + case 0xb101: /* PCIBIOS Check */ + regs->edx = 0x20494350; /* ' ICP' */ + regs->eax &= 0xffff0000; /* Clear AH / AL */ + regs->eax |= PCI_CONFIG_SPACE_TYPE1 | PCI_SPECIAL_CYCLE_TYPE1; + // last bus in the system. Hard code to 255 for now. + // dev_enumerate() does not seem to tell us (publically) + regs->ecx = 0xff; + regs->edi = 0x00000000; /* protected mode entry */ + retval = 0; + break; + case 0xb102: /* Find Device */ + devid = regs->ecx; + vendorid = regs->edx; + devindex = regs->esi; + dev = 0; + while ((dev = dev_find_device(vendorid, devid, dev))) { + if (devindex <= 0) + break; + devindex--; + } + if (dev) { + unsigned short busdevfn; + regs->eax &= 0xffff00ff; /* Clear AH */ + regs->eax |= PCIBIOS_SUCCESSFUL; + // busnum is an unsigned char; + // devfn is an int, so we mask it off. + busdevfn = (dev->bus->secondary << 8) + | (dev->path.pci.devfn & 0xff); + printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn); + regs->ebx = busdevfn; + retval = 0; + } else { + regs->eax &= 0xffff00ff; /* Clear AH */ + regs->eax |= PCIBIOS_NODEV; + retval = -1; + } + break; + case 0xb10a: /* Read Config Dword */ + case 0xb109: /* Read Config Word */ + case 0xb108: /* Read Config Byte */ + case 0xb10d: /* Write Config Dword */ + case 0xb10c: /* Write Config Word */ + case 0xb10b: /* Write Config Byte */ + devfn = regs->ebx & 0xff; + bus = regs->ebx >> 8; + reg = regs->edi; + dev = dev_find_slot(bus, devfn); + if (!dev) { + printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn); + // Or are we supposed to return PCIBIOS_NODEV? + regs->eax &= 0xffff00ff; /* Clear AH */ + regs->eax |= PCIBIOS_BADREG; + retval = -1; + return retval; + } + switch (func) { + case 0xb108: /* Read Config Byte */ + byte = pci_read_config8(dev, reg); + regs->ecx = byte; + break; + case 0xb109: /* Read Config Word */ + word = pci_read_config16(dev, reg); + regs->ecx = word; + break; + case 0xb10a: /* Read Config Dword */ + dword = pci_read_config32(dev, reg); + regs->ecx = dword; + break; + case 0xb10b: /* Write Config Byte */ + byte = regs->ecx; + pci_write_config8(dev, reg, byte); + break; + case 0xb10c: /* Write Config Word */ + word = regs->ecx; + pci_write_config16(dev, reg, word); + break; + case 0xb10d: /* Write Config Dword */ + dword = regs->ecx; + pci_write_config32(dev, reg, dword); + break; + } + +#if CONFIG_REALMODE_DEBUG + printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", + func, bus, devfn, reg, regs->ecx); +#endif + regs->eax &= 0xffff00ff; /* Clear AH */ + regs->eax |= PCIBIOS_SUCCESSFUL; + retval = 0; + break; + default: + printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); + regs->eax &= 0xffff00ff; /* Clear AH */ + regs->eax |= PCIBIOS_UNSUPPORTED; + retval = -1; + break; + } + + return retval; +} + diff --git a/src/devices/oprom/x86.c b/src/devices/oprom/x86.c deleted file mode 100644 index 1791a87f14..0000000000 --- a/src/devices/oprom/x86.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2007 Advanced Micro Devices, Inc. - * Copyright (C) 2009-2010 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "x86.h" -#include "vbe.h" -#include "../../src/lib/jpeg.h" - -void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, - u32 esi, u32 edi) __attribute__((regparm(0))) = - (void *)&__realmode_call; - -void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, u32 edx, - u32 esi, u32 edi) __attribute__((regparm(0))) = - (void *)&__realmode_interrupt; - -static void setup_rombios(void) -{ - const char date[] = "06/11/99"; - memcpy((void *)0xffff5, &date, 8); - - const char ident[] = "PCI_ISA"; - memcpy((void *)0xfffd9, &ident, 7); - - /* system model: IBM-AT */ - write8(0xffffe, 0xfc); -} - -int (*intXX_handler[256])(struct eregs *regs) = { NULL }; - -static int intXX_exception_handler(struct eregs *regs) -{ - printk(BIOS_INFO, "Oops, exception %d while executing option rom\n", - regs->vector); - x86_exception(regs); // Call coreboot exception handler - - return 0; // Never really returns -} - -static int intXX_unknown_handler(struct eregs *regs) -{ - printk(BIOS_INFO, "Unsupported software interrupt #0x%x eax 0x%x\n", - regs->vector, regs->eax); - - return -1; -} - -/* setup interrupt handlers for mainboard */ -void mainboard_interrupt_handlers(int intXX, void *intXX_func) -{ - intXX_handler[intXX] = intXX_func; -} - -static void setup_interrupt_handlers(void) -{ - int i; - - /* The first 16 intXX functions are not BIOS services, - * but the CPU-generated exceptions ("hardware interrupts") - */ - for (i = 0; i < 0x10; i++) - intXX_handler[i] = &intXX_exception_handler; - - /* Mark all other intXX calls as unknown first */ - for (i = 0x10; i < 0x100; i++) - { - /* If the mainboard_interrupt_handler isn't called first. - */ - if(!intXX_handler[i]) - { - /* Now set the default functions that are actually - * needed to initialize the option roms. This is - * very slick, as it allows us to implement mainboard - * specific interrupt handlers, such as the int15. - */ - switch (i) { - case 0x10: - intXX_handler[0x10] = &int10_handler; - break; - case 0x12: - intXX_handler[0x12] = &int12_handler; - break; - case 0x16: - intXX_handler[0x16] = &int16_handler; - break; - case 0x1a: - intXX_handler[0x1a] = &int1a_handler; - break; - default: - intXX_handler[i] = &intXX_unknown_handler; - break; - } - } - } -} - -static void write_idt_stub(void *target, u8 intnum) -{ - unsigned char *codeptr; - codeptr = (unsigned char *) target; - memcpy(codeptr, &__idt_handler, (size_t)&__idt_handler_size); - codeptr[3] = intnum; /* modify int# in the code stub. */ -} - -static void setup_realmode_idt(void) -{ - struct realmode_idt *idts = (struct realmode_idt *) 0; - int i; - - /* Copy IDT stub code for each interrupt. This might seem wasteful - * but it is really simple - */ - for (i = 0; i < 256; i++) { - idts[i].cs = 0; - idts[i].offset = 0x1000 + (i * (u32)&__idt_handler_size); - write_idt_stub((void *)((u32 )idts[i].offset), i); - } - - /* Many option ROMs use the hard coded interrupt entry points in the - * system bios. So install them at the known locations. - */ - - /* int42 is the relocated int10 */ - write_idt_stub((void *)0xff065, 0x42); - /* BIOS Int 11 Handler F000:F84D */ - write_idt_stub((void *)0xff84d, 0x11); - /* BIOS Int 12 Handler F000:F841 */ - write_idt_stub((void *)0xff841, 0x12); - /* BIOS Int 13 Handler F000:EC59 */ - write_idt_stub((void *)0xfec59, 0x13); - /* BIOS Int 14 Handler F000:E739 */ - write_idt_stub((void *)0xfe739, 0x14); - /* BIOS Int 15 Handler F000:F859 */ - write_idt_stub((void *)0xff859, 0x15); - /* BIOS Int 16 Handler F000:E82E */ - write_idt_stub((void *)0xfe82e, 0x16); - /* BIOS Int 17 Handler F000:EFD2 */ - write_idt_stub((void *)0xfefd2, 0x17); - /* ROM BIOS Int 1A Handler F000:FE6E */ - write_idt_stub((void *)0xffe6e, 0x1a); -} - -#if CONFIG_FRAMEBUFFER_SET_VESA_MODE -vbe_mode_info_t mode_info; -static int mode_info_valid; - -int vbe_mode_info_valid(void) -{ - return mode_info_valid; -} - -static u8 vbe_get_mode_info(vbe_mode_info_t * mi) -{ - printk(BIOS_DEBUG, "VBE: Getting information about VESA mode %04x\n", - mi->video_mode); - char *buffer = (char *)&__buffer; - u16 buffer_seg = (((unsigned long)buffer) >> 4) & 0xff00; - u16 buffer_adr = ((unsigned long)buffer) & 0xffff; - realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, - mi->video_mode, 0x0000, buffer_seg, buffer_adr); - memcpy(mi->mode_info_block, buffer, sizeof(vbe_mode_info_t)); - mode_info_valid = 1; - return 0; -} - -static u8 vbe_set_mode(vbe_mode_info_t * mi) -{ - printk(BIOS_DEBUG, "VBE: Setting VESA mode %04x\n", mi->video_mode); - // request linear framebuffer mode - mi->video_mode |= (1 << 14); - // request clearing of framebuffer - mi->video_mode &= ~(1 << 15); - realmode_interrupt(0x10, VESA_SET_MODE, mi->video_mode, - 0x0000, 0x0000, 0x0000, 0x0000); - return 0; -} - -/* These two functions could probably even be generic between - * yabel and x86 native. TBD later. - */ -void vbe_set_graphics(void) -{ - mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE; - vbe_get_mode_info(&mode_info); - unsigned char *framebuffer = - (unsigned char *)mode_info.vesa.phys_base_ptr; - printk(BIOS_DEBUG, "VBE: resolution: %dx%d@%d\n", - le16_to_cpu(mode_info.vesa.x_resolution), - le16_to_cpu(mode_info.vesa.y_resolution), - mode_info.vesa.bits_per_pixel); - printk(BIOS_DEBUG, "VBE: framebuffer: %p\n", framebuffer); - if (!framebuffer) { - printk(BIOS_DEBUG, "VBE: Mode does not support linear " - "framebuffer\n"); - return; - } - - vbe_set_mode(&mode_info); -#if CONFIG_BOOTSPLASH - struct jpeg_decdata *decdata; - decdata = malloc(sizeof(*decdata)); - unsigned char *jpeg = cbfs_find_file("bootsplash.jpg", - CBFS_TYPE_BOOTSPLASH); - if (!jpeg) { - printk(BIOS_DEBUG, "VBE: No bootsplash found.\n"); - return; - } - int ret = 0; - ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata); -#endif -} - -void vbe_textmode_console(void) -{ - delay(2); - realmode_interrupt(0x10, 0x0003, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000); -} - -void fill_lb_framebuffer(struct lb_framebuffer *framebuffer) -{ - framebuffer->physical_address = mode_info.vesa.phys_base_ptr; - - framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution); - framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution); - framebuffer->bytes_per_line = - le16_to_cpu(mode_info.vesa.bytes_per_scanline); - framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel; - - framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos; - framebuffer->red_mask_size = mode_info.vesa.red_mask_size; - - framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos; - framebuffer->green_mask_size = mode_info.vesa.green_mask_size; - - framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos; - framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size; - - framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos; - framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size; -} -#endif - -void run_bios(struct device *dev, unsigned long addr) -{ - u32 num_dev = (dev->bus->secondary << 8) | dev->path.pci.devfn; - - /* Setting up required hardware. - * Removing this will cause random illegal instruction exceptions - * in some option roms. - */ - setup_i8259(); - - /* Set up some legacy information in the F segment */ - setup_rombios(); - - /* Set up C interrupt handlers */ - setup_interrupt_handlers(); - - /* Set up real-mode IDT */ - setup_realmode_idt(); - - memcpy(REALMODE_BASE, &__realmode_code, (size_t)&__realmode_code_size); - printk(BIOS_SPEW, "Real mode stub @%p: %d bytes\n", REALMODE_BASE, - (u32)&__realmode_code_size); - - printk(BIOS_DEBUG, "Calling Option ROM...\n"); - /* TODO ES:DI Pointer to System BIOS PnP Installation Check Structure */ - /* Option ROM entry point is at OPROM start + 3 */ - realmode_call(addr + 0x0003, num_dev, 0xffff, 0x0000, 0xffff, 0x0, 0x0); - printk(BIOS_DEBUG, "... Option ROM returned.\n"); - -#if CONFIG_FRAMEBUFFER_SET_VESA_MODE - vbe_set_graphics(); -#endif -} - -#if CONFIG_GEODE_VSA -#include -#include -#include - -#define VSA2_BUFFER 0x60000 -#define VSA2_ENTRY_POINT 0x60020 - -// TODO move to a header file. -void do_vsmbios(void); - -/* VSA virtual register helper */ -static u32 VSA_vrRead(u16 classIndex) -{ - u32 eax, ebx, ecx, edx; - asm volatile ( - "movw $0x0AC1C, %%dx\n" - "orl $0x0FC530000, %%eax\n" - "outl %%eax, %%dx\n" - "addb $2, %%dl\n" - "inw %%dx, %%ax\n" - : "=a" (eax), "=b"(ebx), "=c"(ecx), "=d"(edx) - : "a"(classIndex) - ); - - return eax; -} - -void do_vsmbios(void) -{ - printk(BIOS_DEBUG, "Preparing for VSA...\n"); - - /* Set up C interrupt handlers */ - setup_interrupt_handlers(); - - /* Setting up realmode IDT */ - setup_realmode_idt(); - - memcpy(REALMODE_BASE, &__realmode_code, (size_t)&__realmode_code_size); - printk(BIOS_SPEW, "VSA: Real mode stub @%p: %d bytes\n", REALMODE_BASE, - (u32)&__realmode_code_size); - - if ((unsigned int)cbfs_load_stage("vsa") != VSA2_ENTRY_POINT) { - printk(BIOS_ERR, "Failed to load VSA.\n"); - return; - } - - unsigned char *buf = (unsigned char *)VSA2_BUFFER; - printk(BIOS_DEBUG, "VSA: Buffer @%p *[0k]=%02x\n", buf, buf[0]); - printk(BIOS_DEBUG, "VSA: Signature *[0x20-0x23] is %02x:%02x:%02x:%02x\n", - buf[0x20], buf[0x21], buf[0x22], buf[0x23]); - - /* Check for code to emit POST code at start of VSA. */ - if ((buf[0x20] != 0xb0) || (buf[0x21] != 0x10) || - (buf[0x22] != 0xe6) || (buf[0x23] != 0x80)) { - printk(BIOS_WARNING, "VSA: Signature incorrect. Install failed.\n"); - return; - } - - printk(BIOS_DEBUG, "Calling VSA module...\n"); - - /* ECX gets SMM, EDX gets SYSMEM */ - realmode_call(VSA2_ENTRY_POINT, 0x0, 0x0, MSR_GLIU0_SMM, - MSR_GLIU0_SYSMEM, 0x0, 0x0); - - printk(BIOS_DEBUG, "... VSA module returned.\n"); - - /* Restart timer 1 */ - outb(0x56, 0x43); - outb(0x12, 0x41); - - /* Check that VSA is running OK */ - if (VSA_vrRead(SIGNATURE) == VSA2_SIGNATURE) - printk(BIOS_DEBUG, "VSM: VSA2 VR signature verified.\n"); - else - printk(BIOS_ERR, "VSM: VSA2 VR signature not valid. Install failed.\n"); -} -#endif - -/* interrupt_handler() is called from assembler code only, - * so there is no use in putting the prototype into a header file. - */ -int __attribute__((regparm(0))) interrupt_handler(u32 intnumber, - u32 gsfs, u32 dses, - u32 edi, u32 esi, - u32 ebp, u32 esp, - u32 ebx, u32 edx, - u32 ecx, u32 eax, - u32 cs_ip, u16 stackflags); - -int __attribute__((regparm(0))) interrupt_handler(u32 intnumber, - u32 gsfs, u32 dses, - u32 edi, u32 esi, - u32 ebp, u32 esp, - u32 ebx, u32 edx, - u32 ecx, u32 eax, - u32 cs_ip, u16 stackflags) -{ - u32 ip; - u32 cs; - u32 flags; - int ret = -1; - struct eregs reg_info; - - ip = cs_ip & 0xffff; - cs = cs_ip >> 16; - flags = stackflags; - -#if CONFIG_REALMODE_DEBUG - printk(BIOS_DEBUG, "oprom: INT# 0x%x\n", intnumber); - printk(BIOS_DEBUG, "oprom: eax: %08x ebx: %08x ecx: %08x edx: %08x\n", - eax, ebx, ecx, edx); - printk(BIOS_DEBUG, "oprom: ebp: %08x esp: %08x edi: %08x esi: %08x\n", - ebp, esp, edi, esi); - printk(BIOS_DEBUG, "oprom: ip: %04x cs: %04x flags: %08x\n", - ip, cs, flags); -#endif - - // Fetch arguments from the stack and put them into - // a structure that we want to pass on to our sub interrupt - // handlers. - reg_info = (struct eregs) { - .eax=eax, - .ecx=ecx, - .edx=edx, - .ebx=ebx, - .esp=esp, - .ebp=ebp, - .esi=esi, - .edi=edi, - .vector=intnumber, - .error_code=0, // ?? - .eip=ip, - .cs=cs, - .eflags=flags // ?? - }; - - // Call the interrupt handler for this int# - ret = intXX_handler[intnumber](®_info); - - // Put registers back on the stack. The assembler code - // will later pop them. - // What happens here is that we force (volatile!) changing - // the values of the parameters of this function. We do this - // because we know that they stay alive on the stack after - // we leave this function. Don't say this is bollocks. - *(volatile u32 *)&eax = reg_info.eax; - *(volatile u32 *)&ecx = reg_info.ecx; - *(volatile u32 *)&edx = reg_info.edx; - *(volatile u32 *)&ebx = reg_info.ebx; - *(volatile u32 *)&esi = reg_info.esi; - *(volatile u32 *)&edi = reg_info.edi; - flags = reg_info.eflags; - - /* Pass errors back to our caller via the CARRY flag */ - if (ret) { - printk(BIOS_DEBUG,"int%02x call returned error.\n", intnumber); - flags |= 1; // error: set carry - }else{ - flags &= ~1; // no error: clear carry - } - *(volatile u16 *)&stackflags = flags; - - return ret; -} - diff --git a/src/devices/oprom/x86.h b/src/devices/oprom/x86.h deleted file mode 100644 index 40c5778de5..0000000000 --- a/src/devices/oprom/x86.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2007 Advanced Micro Devices, Inc. - * Copyright (C) 2009-2010 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#define REALMODE_BASE ((void *)0x600) - -struct realmode_idt { - u16 offset, cs; -}; - -void x86_exception(struct eregs *info); - -/* From x86_asm.S */ -extern unsigned char __idt_handler, __idt_handler_size; -extern unsigned char __realmode_code, __realmode_code_size; -extern unsigned char __realmode_call, __realmode_interrupt; -extern unsigned char __buffer; - -extern void (*realmode_call)(u32 addr, u32 eax, u32 ebx, u32 ecx, u32 edx, - u32 esi, u32 edi) __attribute__((regparm(0))); - -extern void (*realmode_interrupt)(u32 intno, u32 eax, u32 ebx, u32 ecx, u32 edx, - u32 esi, u32 edi) __attribute__((regparm(0))); - -#define FAKE_MEMORY_SIZE (1024*1024) // only 1MB -#define INITIAL_EBDA_SEGMENT 0xF600 -#define INITIAL_EBDA_SIZE 0x400 - -int int10_handler(struct eregs *regs); -int int12_handler(struct eregs *regs); -int int16_handler(struct eregs *regs); -int int1a_handler(struct eregs *regs); - diff --git a/src/devices/oprom/x86_asm.S b/src/devices/oprom/x86_asm.S deleted file mode 100644 index 56ebb3a885..0000000000 --- a/src/devices/oprom/x86_asm.S +++ /dev/null @@ -1,413 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2009-2010 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#define REALMODE_BASE 0x600 -#define RELOCATED(x) (x - __realmode_code + REALMODE_BASE) - -/* CR0 bits */ -#define PE (1 << 0) - -/* This is the intXX interrupt handler stub code. It gets copied - * to the IDT and to some fixed addresses in the F segment. Before - * the code can used, it gets patched up by the C function copying - * it: byte 3 (the $0 in movb $0, %al) is overwritten with the int#. - */ - - .code16 - .globl __idt_handler -__idt_handler: - pushal - movb $0, %al /* This instruction gets modified */ - ljmp $0, $__interrupt_handler_16bit - .globl __idt_handler_size -__idt_handler_size = ( . - __idt_handler) - - -/* In order to be independent of coreboot's position in RAM - * we relocate a part of the code to the low megabyte, so the - * CPU can use it in real-mode. This code lives at __realmode_code. - */ - .globl __realmode_code -__realmode_code: - -/* Realmode IDT pointer structure. */ - .globl __realmode_idt -__realmode_idt = RELOCATED(.) - .word 1023 /* 16 bit limit */ - .long 0 /* 24 bit base */ - .word 0 - -/* Preserve old stack */ -__stack = RELOCATED(.) - .long 0 - -/* Register store for realmode_call and realmode_interrupt */ -__registers = RELOCATED(.) - .long 0 /* 0 - EAX */ - .long 0 /* 4 - EBX */ - .long 0 /* 8 - ECX */ - .long 0 /* 12 - EDX */ - .long 0 /* 16 - ESI */ - .long 0 /* 20 - EDI */ - -/* 256 byte buffer, used by int10 */ - .globl __buffer -__buffer = RELOCATED(.) - .skip 256 - - .code32 - .globl __realmode_call -__realmode_call = RELOCATED(.) - /* save all registers to the stack */ - pusha - pushf - - /* Move the protected mode stack pointer to a safe place */ - movl %esp, __stack - movl %esp, %ebp - - /* This function is called with regparm=0 and we have to - * skip the 36 byte from pushf+pusha. Hence start at 40. - */ - - /* entry point */ - movl 40(%ebp), %eax - mov %ax, __lcall_instr + 1 - andl $0xffff0000, %eax - shrl $4, %eax - mov %ax, __lcall_instr + 3 - - /* initial register values */ - movl 44(%ebp), %eax - movl %eax, __registers + 0 /* eax */ - movl 48(%ebp), %eax - movl %eax, __registers + 4 /* ebx */ - movl 52(%ebp), %eax - movl %eax, __registers + 8 /* ecx */ - movl 56(%ebp), %eax - movl %eax, __registers + 12 /* edx */ - movl 60(%ebp), %eax - movl %eax, __registers + 16 /* esi */ - movl 64(%ebp), %eax - movl %eax, __registers + 20 /* edi */ - - /* Activate the right segment descriptor real mode. */ - ljmp $0x28, $RELOCATED(1f) -1: -.code16 - /* 16 bit code from here on... */ - - /* Load the segment registers w/ properly configured - * segment descriptors. They will retain these - * configurations (limits, writability, etc.) once - * protected mode is turned off. - */ - mov $0x30, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - /* Turn off protection */ - movl %cr0, %eax - andl $~PE, %eax - movl %eax, %cr0 - - /* Now really going into real mode */ - ljmp $0, $RELOCATED(1f) -1: - /* Setup a stack: Put the stack at the end of page zero. - * That way we can easily share it between real and - * protected, since the 16 bit ESP at segment 0 will - * work for any case. */ - mov $0x0, %ax - mov %ax, %ss - movl $0x1000, %eax - movl %eax, %esp - - /* Load 16 bit IDT */ - xor %ax, %ax - mov %ax, %ds - lidt __realmode_idt - - /* initialize registers for option rom lcall */ - movl __registers + 0, %eax - movl __registers + 4, %ebx - movl __registers + 8, %ecx - movl __registers + 12, %edx - movl __registers + 16, %esi - movl __registers + 20, %edi - - /* Set all segments to 0x0000, ds to 0x0040 */ - push %ax - xor %ax, %ax - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov $0x40, %ax - mov %ax, %ds - pop %ax - - /* ************************************ */ -__lcall_instr = RELOCATED(.) - .byte 0x9a - .word 0x0000, 0x0000 - /* ************************************ */ - - /* If we got here, we are just about done. - * Need to get back to protected mode. - */ - movl %cr0, %eax - orl $PE, %eax - movl %eax, %cr0 - - /* Now that we are in protected mode - * jump to a 32 bit code segment. - */ - data32 ljmp $0x10, $RELOCATED(1f) -1: - .code32 - mov $0x18, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - /* restore proper idt */ - lidt idtarg - - /* restore stack pointer, eflags and register values */ - movl __stack, %esp - popf - popa - - /* and exit */ - // TODO return AX from OPROM call - ret - - .globl __realmode_interrupt -__realmode_interrupt = RELOCATED(.) - /* save all registers to the stack */ - pusha - pushf - - /* save the stack pointer */ - movl %esp, __stack - movl %esp, %ebp - - /* This function is called with regparm=0 and we have to - * skip the 36 byte from pushf+pusha. Hence start at 40. - */ - - /* prepare interrupt calling code */ - movl 40(%ebp), %eax - movb %al, __intXX_instr + 1 /* intno */ - - /* initial register values */ - movl 44(%ebp), %eax - movl %eax, __registers + 0 /* eax */ - movl 48(%ebp), %eax - movl %eax, __registers + 4 /* ebx */ - movl 52(%ebp), %eax - movl %eax, __registers + 8 /* ecx */ - movl 56(%ebp), %eax - movl %eax, __registers + 12 /* edx */ - movl 60(%ebp), %eax - movl %eax, __registers + 16 /* esi */ - movl 64(%ebp), %eax - movl %eax, __registers + 20 /* edi */ - - /* This configures CS properly for real mode. */ - ljmp $0x28, $RELOCATED(1f) -1: - .code16 /* 16 bit code from here on... */ - - /* Load the segment registers w/ properly configured segment - * descriptors. They will retain these configurations (limits, - * writability, etc.) once protected mode is turned off. - */ - mov $0x30, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - /* Turn off protected mode */ - movl %cr0, %eax - andl $~PE, %eax - movl %eax, %cr0 - - /* Now really going into real mode */ - data32 ljmp $0, $RELOCATED(1f) -1: - - /* put the stack at the end of page zero. That way we can easily - * share it between real mode and protected mode, because %esp and - * %ss:%sp point to the same memory. - */ - /* setup a stack */ - mov $0x0, %ax - mov %ax, %ss - movl $0x1000, %eax - movl %eax, %esp - - /* Load 16-bit intXX IDT */ - xor %ax, %ax - mov %ax, %ds - lidt __realmode_idt - - /* initialize registers for intXX call */ - movl __registers + 0, %eax - movl __registers + 4, %ebx - movl __registers + 8, %ecx - movl __registers + 12, %edx - movl __registers + 16, %esi - movl __registers + 20, %edi - - /* Set all segments to 0x0000 */ - push %ax - xor %ax, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - pop %ax - -__intXX_instr = RELOCATED(.) - .byte 0xcd, 0x00 /* This becomes intXX */ - - /* Ok, the job is done, now go back to protected mode coreboot */ - movl %cr0, %eax - orl $PE, %eax - movl %eax, %cr0 - - /* Now that we are in protected mode jump to a 32-bit code segment. */ - data32 ljmp $0x10, $RELOCATED(1f) -1: - .code32 - mov $0x18, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - /* restore coreboot's 32-bit IDT */ - lidt idtarg - - /* restore stack pointer, eflags and register values and exit */ - movl __stack, %esp - popf - popa - ret - -/* This is the 16-bit interrupt entry point called by the IDT stub code. - * - * Before this code code is called, %eax is pushed to the stack, and the - * interrupt number is loaded into %al. On return this function cleans up - * for its caller. - */ - .code16 -__interrupt_handler_16bit = RELOCATED(.) - push %ds - push %es - push %fs - push %gs - - /* Clear DF to not break ABI assumptions */ - cld - - /* Clean up the interrupt number. We could have done this in the stub, - * but it would have cost 2 more bytes per stub entry. - */ - andl $0xff, %eax - pushl %eax /* ... and make it the first parameter */ - - /* Switch to protected mode */ - movl %cr0, %eax - orl $PE, %eax - movl %eax, %cr0 - - /* ... and jump to a 32 bit code segment. */ - data32 ljmp $0x10, $RELOCATED(1f) -1: - .code32 - mov $0x18, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - lidt idtarg - - /* Call the C interrupt handler */ - movl $interrupt_handler, %eax - call *%eax - - /* Now return to real mode ... */ - ljmp $0x28, $RELOCATED(1f) -1: - .code16 - /* Load the segment registers with properly configured segment - * descriptors. They will retain these configurations (limits, - * writability, etc.) once protected mode is turned off. - */ - mov $0x30, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - /* Disable Protected Mode */ - movl %cr0, %eax - andl $~PE, %eax - movl %eax, %cr0 - - /* Now really going into real mode */ - ljmp $0, $RELOCATED(1f) -1: - /* Restore real-mode stack segment */ - mov $0x0, %ax - mov %ax, %ss - - /* Restore 16 bit IDT */ - xor %ax, %ax - mov %ax, %ds - lidt __realmode_idt - - /* Restore all registers, including those - * manipulated by the C handler - */ - popl %eax - pop %gs - pop %fs - pop %es - pop %ds - popal - iret - - .globl __realmode_code_size -__realmode_code_size = (. - __realmode_code) - - .code32 diff --git a/src/devices/oprom/x86_interrupts.c b/src/devices/oprom/x86_interrupts.c deleted file mode 100644 index 2ea05d44ba..0000000000 --- a/src/devices/oprom/x86_interrupts.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2001 Ronald G. Minnich - * Copyright (C) 2005 Nick.Barker9@btinternet.com - * Copyright (C) 2007-2009 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "x86.h" - -// errors go in AH. Just set these up so that word assigns -// will work. KISS. -enum { - PCIBIOS_SUCCESSFUL = 0x0000, - PCIBIOS_UNSUPPORTED = 0x8100, - PCIBIOS_BADVENDOR = 0x8300, - PCIBIOS_NODEV = 0x8600, - PCIBIOS_BADREG = 0x8700 -}; - -int int10_handler(struct eregs *regs) -{ - int res=-1; - static u8 cursor_row=0, cursor_col=0; - switch((regs->eax & 0xff00)>>8) { - case 0x01: // Set cursor shape - res = 0; - break; - case 0x02: // Set cursor position - if (cursor_row != ((regs->edx >> 8) & 0xff) || - cursor_col >= (regs->edx & 0xff)) { - printk(BIOS_INFO, "\n"); - } - cursor_row = (regs->edx >> 8) & 0xff; - cursor_col = regs->edx & 0xff; - res = 0; - break; - case 0x03: // Get cursor position - regs->eax &= 0x00ff; - regs->ecx = 0x0607; - regs->edx = (cursor_row << 8) | cursor_col; - res = 0; - break; - case 0x06: // Scroll up - printk(BIOS_INFO, "\n"); - res = 0; - break; - case 0x08: // Get Character and Mode at Cursor Position - regs->eax = 0x0f00 | 'A'; // White on black 'A' - res = 0; - break; - case 0x09: // Write Character and attribute - case 0x0e: // Write Character - printk(BIOS_INFO, "%c", regs->eax & 0xff); - res = 0; - break; - case 0x0f: // Get video mode - regs->eax = 0x5002; //80x25 - regs->ebx &= 0x00ff; - res = 0; - break; - default: - printk(BIOS_WARNING, "Unknown INT10 function %04x!\n", - regs->eax & 0xffff); - break; - } - return res; -} - -int int12_handler(struct eregs *regs) -{ - regs->eax = 64 * 1024; - return 0; -} - -int int16_handler(struct eregs *regs) -{ - int res=-1; - switch((regs->eax & 0xff00)>>8) { - case 0x00: // Check for Keystroke - regs->eax = 0x6120; // Space Bar, Space - res = 0; - break; - case 0x01: // Check for Keystroke - regs->eflags |= 1<<6; // Zero Flag set (no key available) - res = 0; - break; - default: - printk(BIOS_WARNING, "Unknown INT16 function %04x!\n", - regs->eax & 0xffff); - break; - } - return res; -} - -#define PCI_CONFIG_SPACE_TYPE1 (1 << 0) -#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4) - -int int1a_handler(struct eregs *regs) -{ - unsigned short func = (unsigned short)regs->eax; - int retval = 0; - unsigned short devid, vendorid, devfn; - /* Use short to get rid of gabage in upper half of 32-bit register */ - short devindex; - unsigned char bus; - struct device *dev; - u32 dword; - u16 word; - u8 byte, reg; - - switch (func) { - case 0xb101: /* PCIBIOS Check */ - regs->edx = 0x20494350; /* ' ICP' */ - regs->eax &= 0xffff0000; /* Clear AH / AL */ - regs->eax |= PCI_CONFIG_SPACE_TYPE1 | PCI_SPECIAL_CYCLE_TYPE1; - // last bus in the system. Hard code to 255 for now. - // dev_enumerate() does not seem to tell us (publically) - regs->ecx = 0xff; - regs->edi = 0x00000000; /* protected mode entry */ - retval = 0; - break; - case 0xb102: /* Find Device */ - devid = regs->ecx; - vendorid = regs->edx; - devindex = regs->esi; - dev = 0; - while ((dev = dev_find_device(vendorid, devid, dev))) { - if (devindex <= 0) - break; - devindex--; - } - if (dev) { - unsigned short busdevfn; - regs->eax &= 0xffff00ff; /* Clear AH */ - regs->eax |= PCIBIOS_SUCCESSFUL; - // busnum is an unsigned char; - // devfn is an int, so we mask it off. - busdevfn = (dev->bus->secondary << 8) - | (dev->path.pci.devfn & 0xff); - printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn); - regs->ebx = busdevfn; - retval = 0; - } else { - regs->eax &= 0xffff00ff; /* Clear AH */ - regs->eax |= PCIBIOS_NODEV; - retval = -1; - } - break; - case 0xb10a: /* Read Config Dword */ - case 0xb109: /* Read Config Word */ - case 0xb108: /* Read Config Byte */ - case 0xb10d: /* Write Config Dword */ - case 0xb10c: /* Write Config Word */ - case 0xb10b: /* Write Config Byte */ - devfn = regs->ebx & 0xff; - bus = regs->ebx >> 8; - reg = regs->edi; - dev = dev_find_slot(bus, devfn); - if (!dev) { - printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn); - // Or are we supposed to return PCIBIOS_NODEV? - regs->eax &= 0xffff00ff; /* Clear AH */ - regs->eax |= PCIBIOS_BADREG; - retval = -1; - return retval; - } - switch (func) { - case 0xb108: /* Read Config Byte */ - byte = pci_read_config8(dev, reg); - regs->ecx = byte; - break; - case 0xb109: /* Read Config Word */ - word = pci_read_config16(dev, reg); - regs->ecx = word; - break; - case 0xb10a: /* Read Config Dword */ - dword = pci_read_config32(dev, reg); - regs->ecx = dword; - break; - case 0xb10b: /* Write Config Byte */ - byte = regs->ecx; - pci_write_config8(dev, reg, byte); - break; - case 0xb10c: /* Write Config Word */ - word = regs->ecx; - pci_write_config16(dev, reg, word); - break; - case 0xb10d: /* Write Config Dword */ - dword = regs->ecx; - pci_write_config32(dev, reg, dword); - break; - } - -#if CONFIG_REALMODE_DEBUG - printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", - func, bus, devfn, reg, regs->ecx); -#endif - regs->eax &= 0xffff00ff; /* Clear AH */ - regs->eax |= PCIBIOS_SUCCESSFUL; - retval = 0; - break; - default: - printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); - regs->eax &= 0xffff00ff; /* Clear AH */ - regs->eax |= PCIBIOS_UNSUPPORTED; - retval = -1; - break; - } - - return retval; -} - diff --git a/src/northbridge/via/cx700/vga.c b/src/northbridge/via/cx700/vga.c index c6bf72ea8f..4acad7e852 100644 --- a/src/northbridge/via/cx700/vga.c +++ b/src/northbridge/via/cx700/vga.c @@ -32,7 +32,7 @@ #include #include "registers.h" #if CONFIG_PCI_OPTION_ROM_RUN_REALMODE -#include +#include #endif /* PCI Domain 1 Device 0 Function 0 */ diff --git a/src/northbridge/via/vt8623/vga.c b/src/northbridge/via/vt8623/vga.c index dffe7cb1ff..fea691ebc2 100644 --- a/src/northbridge/via/vt8623/vga.c +++ b/src/northbridge/via/vt8623/vga.c @@ -31,7 +31,7 @@ #include #include #if CONFIG_PCI_OPTION_ROM_RUN_REALMODE -#include +#include #endif static int via_vt8623_int15_handler(struct eregs *regs) diff --git a/src/northbridge/via/vx800/vga.c b/src/northbridge/via/vx800/vga.c index c3ae224898..d91ad9fea3 100644 --- a/src/northbridge/via/vx800/vga.c +++ b/src/northbridge/via/vx800/vga.c @@ -34,7 +34,7 @@ #include #include #if CONFIG_PCI_OPTION_ROM_RUN_REALMODE -#include +#include #endif /* PCI Domain 1 Device 0 Function 0 */ -- cgit v1.2.3