Change real mode API to allow passing intXX number or entry point and some register values from C. This theoretically fixes non-vga option roms, but it also allows to use the same assembler code for option roms and vsm. It will also make using the bootsplash without yabel a lot easier. Factor out and improve BDA setup, do some rom segment setup for those option roms that need it. Signed-off-by: Stefan Reinauer Index: src/devices/oprom/x86.c =================================================================== --- src/devices/oprom/x86.c (revision 5530) +++ src/devices/oprom/x86.c (working copy) @@ -36,11 +36,55 @@ extern unsigned char __idt_handler, __idt_handler_size; extern unsigned char __realmode_code, __realmode_code_size; -extern unsigned char __run_optionrom, __run_interrupt; +extern unsigned char __realmode_call, __realmode_interrupt; -void (*run_optionrom)(u32 devfn) __attribute__((regparm(0))) = (void *)&__run_optionrom; -void (*vga_enable_console)(void) __attribute__((regparm(0))) = (void *)&__run_interrupt; +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; + +void vga_enable_console(void); +void vga_enable_console(void) +{ + /* Call VGA BIOS int10 function 0x4f14 to enable main console + * Epia-M does not always autosense the main console so forcing + * it on is good. + */ + + /* int#, EAX, EBX, ECX, EDX, ESI, EDI */ + realmode_interrupt(0x10, 0x4f1f, 0x8003, 0x0001, 0x0000, 0x0000, 0x0000); +} + +#define FAKE_MEMORY_SIZE (1024*1024) // only 1MB +#define INITIAL_EBDA_SEGMENT 0xF600 +#define INITIAL_EBDA_SIZE 0x400 + +static void setup_bda(void) +{ + /* clear BIOS DATA AREA */ + memset((void *)0x400, 0, 0x200); + + write16(0x413, FAKE_MEMORY_SIZE / 1024); + write16(0x40e, INITIAL_EBDA_SEGMENT); + + /* Set up EBDA */ + memset((void *)(INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE); + write16((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024); +} + +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) @@ -138,20 +182,38 @@ /* int42 is the relocated int10 */ write_idt_stub((void *)0xff065, 0x42); - - /* VIA's VBIOS calls f000:f859 instead of int15 */ + /* 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); } void run_bios(struct device *dev, unsigned long addr) { - /* clear vga bios data area */ - memset((void *)0x400, 0, 0x200); + u32 num_dev = (dev->bus->secondary << 8) | dev->path.pci.devfn; + /* Set up BIOS Data Area */ + setup_bda(); + + /* Set up some legacy information in the F segment */ + setup_rombios(); + /* Set up C interrupt handlers */ setup_interrupt_handlers(); - /* Setting up realmode IDT */ + /* Set up real-mode IDT */ setup_realmode_idt(); memcpy(REALMODE_BASE, &__realmode_code, (size_t)&__realmode_code_size); @@ -159,7 +221,9 @@ (u32)&__realmode_code_size); printk(BIOS_DEBUG, "Calling Option ROM...\n"); - run_optionrom((dev->bus->secondary << 8) | dev->path.pci.devfn); + /* 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"); } @@ -168,9 +232,6 @@ #include #include -extern unsigned char __run_vsa; -void (*run_vsa)(u32 smm, u32 sysmem) __attribute__((regparm(0))) = (void *)&__run_vsa; - #define VSA2_BUFFER 0x60000 #define VSA2_ENTRY_POINT 0x60020 @@ -198,9 +259,6 @@ { printk(BIOS_DEBUG, "Preparing for VSA...\n"); - /* clear bios data area */ - memset((void *)0x400, 0, 0x200); - /* Set up C interrupt handlers */ setup_interrupt_handlers(); @@ -229,8 +287,11 @@ } printk(BIOS_DEBUG, "Calling VSA module...\n"); + /* ECX gets SMM, EDX gets SYSMEM */ - run_vsa(MSR_GLIU0_SMM, MSR_GLIU0_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 */ Index: src/devices/oprom/x86_asm.S =================================================================== --- src/devices/oprom/x86_asm.S (revision 5530) +++ src/devices/oprom/x86_asm.S (working copy) @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2009 coresystems GmbH + * 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 @@ -57,22 +57,51 @@ __stack = RELOCATED(.) .long 0 +/* Register store for realmode_call and realmode_interrupt */ +__registers = RELOCATED(.) + .long 0 /* 0x00 - EAX */ + .long 0 /* 0x04 - EBX */ + .long 0 /* 0x08 - ECX */ + .long 0 /* 0x0c - EDX */ + .long 0 /* 0x10 - EDI */ + .long 0 /* 0x14 - ESI */ + .code32 - .globl __run_optionrom -__run_optionrom = RELOCATED(.) + .globl __realmode_call +__realmode_call = RELOCATED(.) /* save all registers to the stack */ pushal /* Move the protected mode stack to a safe place */ - mov %esp, __stack + movl %esp, __stack /* Get devfn into %ecx */ movl %esp, %ebp /* This function is called with regparm=0 and we have * to skip the 32 byte from pushal: */ + + /* entry point */ movl 36(%ebp), %ecx + movw %cx, __lcall_instr + 1 + andl $0xffff0000, %ecx + shrl $4, %ecx + movw %cx, __lcall_instr + 3 + + movl 40(%ebp), %eax + movl %eax, __registers + 0x00 /* eax */ + movl 44(%ebp), %eax + movl %eax, __registers + 0x04 /* ebx */ + movl 48(%ebp), %eax + movl %eax, __registers + 0x08 /* ecx */ + movl 52(%ebp), %eax + movl %eax, __registers + 0x0c /* edx */ + movl 56(%ebp), %eax + movl %eax, __registers + 0x10 /* esi */ + movl 60(%ebp), %eax + movl %eax, __registers + 0x14 /* esi */ + /* Activate the right segment descriptor real mode. */ ljmp $0x28, $RELOCATED(1f) 1: @@ -120,11 +149,19 @@ mov $0x40, %ax mov %ax, %ds + /* initialize registers for intXX call */ + movl __registers, %ebp + movl 0(%ebp), %eax + movl 4(%ebp), %ebx + movl 8(%ebp), %ecx + movl 12(%ebp), %edx + movl 16(%ebp), %esi + movl 20(%ebp), %edi + /* ************************************ */ - mov %cx, %ax // restore ax - // TODO this will not work for non-VGA option ROMs - /* run VGA BIOS at 0xc000:0003 */ - lcall $0xc000, $0x0003 +__lcall_instr = RELOCATED(.) + .byte 0x9a + .word 0x0000, 0x0000 /* ************************************ */ /* If we got here, just about done. @@ -151,117 +188,38 @@ lidt idtarg /* and exit */ - mov __stack, %esp + movl __stack, %esp popal + + // TODO return AX from OPROM call ret -#if defined(CONFIG_GEODE_VSA) && CONFIG_GEODE_VSA -#define VSA2_ENTRY_POINT 0x60020 + .globl __realmode_interrupt +__realmode_interrupt = RELOCATED(.) - .globl __run_vsa -__run_vsa = RELOCATED(.) - /* save all registers to the stack */ pushal - - /* Move the protected mode stack to a safe place */ - mov %esp, __stack - + /* save the stack */ + movl %esp, __stack movl %esp, %ebp + /* This function is called with regparm=0 and we have * to skip the 32 byte from pushal: */ - movl 36(%ebp), %ecx - movl 40(%ebp), %edx + movl 36(%ebp), %eax + movb %al, __intXX_instr + 1 /* intno */ + movl 40(%ebp), %eax + movl %eax, __registers + 0x00 /* eax */ + movl 44(%ebp), %eax + movl %eax, __registers + 0x04 /* ebx */ + movl 48(%ebp), %eax + movl %eax, __registers + 0x08 /* ecx */ + movl 52(%ebp), %eax + movl %eax, __registers + 0x0c /* edx */ + movl 56(%ebp), %eax + movl %eax, __registers + 0x10 /* esi */ + movl 60(%ebp), %eax + movl %eax, __registers + 0x14 /* esi */ - /* 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 our 16 bit idt */ - xor %ax, %ax - mov %ax, %ds - lidt __realmode_idt - - /* Set all segments to 0x0000, ds to 0x0040 */ - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov $0x40, %ax - mov %ax, %ds - mov %cx, %ax // restore ax - - /* ************************************ */ - lcall $((VSA2_ENTRY_POINT & 0xffff0000) >> 4), $(VSA2_ENTRY_POINT & 0xffff) - /* ************************************ */ - - /* If we got here, 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 - movw $0x18, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss - - /* restore proper idt */ - lidt idtarg - - /* and exit */ - mov __stack, %esp - popal - ret -#endif - - .globl __run_interrupt -__run_interrupt = RELOCATED(.) - - pushal - /* save the stack */ - mov %esp, __stack - - /* This configures CS properly for real mode. */ ljmp $0x28, $RELOCATED(1f) 1: @@ -312,18 +270,17 @@ mov %ax, %fs mov %ax, %gs - /* Call VGA BIOS int10 function 0x4f14 to enable main console - * Epia-M does not always autosence the main console so forcing - * it on is good. - */ + /* initialize registers for intXX call */ + movl __registers, %ebp + movl 0(%ebp), %eax + movl 4(%ebp), %ebx + movl 8(%ebp), %ecx + movl 12(%ebp), %edx + movl 16(%ebp), %esi + movl 20(%ebp), %edi - /* Ask VGA option rom to enable main console */ - movw $0x4f14,%ax - movw $0x8003,%bx - movw $1, %cx - movw $0, %dx - movw $0, %di - int $0x10 +__intXX_instr = RELOCATED(.) + .byte 0xcd, 0x00 /* This becomes intXX */ /* Ok, the job is done, now go back to protected mode coreboot */ movl %cr0, %eax @@ -345,7 +302,7 @@ lidt idtarg /* Exit */ - mov __stack, %esp + movl __stack, %esp popal ret