Author: rminnich Date: 2008-01-24 22:54:22 +0100 (Thu, 24 Jan 2008) New Revision: 560
Added: coreboot-v3/northbridge/amd/geodelx/vsmsetup.c Modified: coreboot-v3/northbridge/amd/geodelx/Makefile coreboot-v3/util/x86emu/vm86.c Log:
This is a first cut at the implementation of VSM support. What has do be done, long term, is to remove almost all of the vsmsetup.c file and use functions in the vm86.c file.
The barrier to achieving that goal is the specialized nature of the vga bios support code vs. the vsm bios support code. There are a few issues to resolve but what I'd like to do is get VSA working first, then work out how to merge the rest of the code.
I have already done some merging at this point.
This code does not yet work. But the board does not work either, and I want to get the code into the repo in case my hard drive dies.
Makefile: add vmsetup.o
vsmsetup.c: Add this file from v2. Fix copyright and includes. Remove almost all assembly code in favor of code in vm86.c. In future, almost all code will be removed and the vm86.c code used instead.
vm86.c: make some assembly symbols .globl so that vsmsetup.c can use them.
Signed-off-by: Ronald G. Minnich rminnich@gmail.com
Acked-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Modified: coreboot-v3/northbridge/amd/geodelx/Makefile =================================================================== --- coreboot-v3/northbridge/amd/geodelx/Makefile 2008-01-21 02:39:45 UTC (rev 559) +++ coreboot-v3/northbridge/amd/geodelx/Makefile 2008-01-24 21:54:22 UTC (rev 560) @@ -22,6 +22,7 @@ ifeq ($(CONFIG_NORTHBRIDGE_AMD_GEODELX),y)
STAGE2_CHIPSET_OBJ += $(obj)/northbridge/amd/geodelx/geodelx.o \ - $(obj)/northbridge/amd/geodelx/geodelxinit.o + $(obj)/northbridge/amd/geodelx/geodelxinit.o \ + $(obj)/northbridge/amd/geodelx/vsmsetup.o
endif
Added: coreboot-v3/northbridge/amd/geodelx/vsmsetup.c =================================================================== --- coreboot-v3/northbridge/amd/geodelx/vsmsetup.c (rev 0) +++ coreboot-v3/northbridge/amd/geodelx/vsmsetup.c 2008-01-24 21:54:22 UTC (rev 560) @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2000 Erik Arjan Hendriks + * Copyright (C) 2000 Scyld Computing Corporation + * Copyright (C) 2001 University of California. LA-CC Number 01-67. + * Copyright (C) 2005 Nick.Barker9@btinternet.com + * Copyright (C) 2007 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * LA-CC is the Los Alamos Control and Compliance Number, see also: + * http://supply.lanl.gov/property/customs/eximguide/default.shtml + */ +#include <types.h> +#include <console.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pci_ids.h> +#include <msr.h> +#include <amd_geodelx.h> + +#define VSA2_BUFFER 0x60000 +#define VSA2_ENTRY_POINT 0x60020 + + +/* The address arguments to this function are PHYSICAL ADDRESSES */ +static void real_mode_switch_call_vsm(unsigned long smm, unsigned long sysm) +{ + u16 entryHi = (VSA2_ENTRY_POINT & 0xffff0000) >> 4; + u16 entryLo = (VSA2_ENTRY_POINT & 0xffff); + + __asm__ __volatile__( + // paranoia -- does ecx get saved? not sure. This is + // the easiest safe thing to do. + " pushal \n" + /* save the stack */ + " mov %%esp, __stack \n" + " jmp 1f \n" + "__stack: .long 0 \n" + "1:\n" + /* get devfn into %%ecx */ + " movl %%esp, %%ebp \n" + /* Get the smm and sysm args into ecx and edx */ + " movl %0, %%ecx \n" + " movl %1, %%edx \n" + /* load 'our' gdt */ + " lgdt %%cs:__mygdtaddr \n" + /* This configures CS properly for real mode. */ + " ljmp $0x28, $__rms_16bit\n" + "__rms_16bit: \n" + " .code16 \n" + /* 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 \n" + " mov %%ax, %%ds \n" + " mov %%ax, %%es \n" + " mov %%ax, %%fs \n" + " mov %%ax, %%gs \n" + " mov %%ax, %%ss \n" + /* Turn off protection (bit 0 in CR0) */ + " movl %%cr0, %%eax \n" + " andl $0xFFFFFFFE, %%eax \n" + " movl %%eax, %%cr0 \n" + /* Now really going into real mode */ + " ljmp $0, $__rms_real\n" + "__rms_real: \n" + + /* 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. + */ + + /* Setup a stack */ + " mov $0x0, %%ax \n" + " mov %%ax, %%ss \n" + " movl $0x1000, %%eax \n" + " movl %%eax, %%esp \n" + /* Load our 16 it idt */ + " xor %%ax, %%ax \n" + " mov %%ax, %%ds \n" + " lidt __myidt \n" + /* Dump zeros in the other segregs */ + " mov %%ax, %%es \n" + /* FixMe: Big real mode for gs, fs? */ + " mov %%ax, %%fs \n" + " mov %%ax, %%gs \n" + " mov $0x40, %%ax \n" + " mov %%ax, %%ds \n" + //" mov %%cx, %%ax \n" + " movl %0, %%ecx \n" + " movl %1, %%edx \n" + /* call the VSA2 entry point address */ + " lcall %2, %3\n" + /* if we got here, just about done. + * Need to get back to protected mode */ + " movl %%cr0, %%eax \n" + " orl $0x0000001, %%eax\n" /* PE = 1 */ + " movl %%eax, %%cr0 \n" + /* Now that we are in protected mode jump to a 32 bit code segment. */ + " data32 ljmp $0x10, $vsmrestart\n" + "vsmrestart:\n" + " .code32\n" + " movw $0x18, %%ax \n" + " mov %%ax, %%ds \n" + " mov %%ax, %%es \n" + " mov %%ax, %%fs \n" + " mov %%ax, %%gs \n" + " mov %%ax, %%ss \n" + /* restore proper gdt and idt */ + " lgdt %%cs:gdtarg \n" + " lidt idtarg \n" + ".globl vsm_exit \n" + "vsm_exit: \n" + " mov __stack, %%esp \n" + " popal \n":: + "g" (smm), "g"(sysm), "g"(entryHi), "g"(entryLo) + ); +} + +__asm__(".text\n" "real_mode_switch_end:\n"); +extern char real_mode_switch_end[]; + +// andrei: some VSA virtual register helpers: raw read and MSR read + +u32 VSA_vrRead(u16 classIndex) +{ + unsigned 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; +} + +u32 VSA_msrRead(u32 msrAddr) +{ + unsigned eax, ebx, ecx, edx; + asm volatile ( + "movw $0x0AC1C, %%dx \n" + "movl $0x0FC530007, %%eax \n" + "outl %%eax, %%dx \n" + "addb $2, %%dl \n" + "inw %%dx, %%ax \n" + : "=a" (eax), "=b"(ebx), "=c"(ecx), "=d"(edx) + : "c"(msrAddr) + ); + + return eax; +} + +void do_vsmbios(void *bios) +{ + struct device *dev; + unsigned long busdevfn; + unsigned int rom = 0; + unsigned char *buf; + unsigned int size = SMM_SIZE * 1024; + int i; + unsigned long ilen, olen; + + printk(BIOS_ERR, "do_vsmbios\n"); + /* clear vsm bios data area */ + for (i = 0x400; i < 0x500; i++) { + *(volatile unsigned char *)i = 0; + } + + rom = (unsigned long) bios; + buf = (unsigned char *)VSA2_BUFFER; + // FIXME + //olen = unrv2b((u8 *) rom, buf, &ilen); + printk(BIOS_DEBUG, "buf ilen %d olen%d\n", ilen, olen); + printk(BIOS_DEBUG, "buf %p *buf %d buf[256k] %d\n", + buf, buf[0], buf[SMM_SIZE * 1024]); + printk(BIOS_DEBUG, "buf[0x20] signature is %x:%x:%x:%x\n", + buf[0x20], buf[0x21], buf[0x22], buf[0x23]); + /* check for post code at start of vsainit.bin. If you don't see it, + don't bother. */ + if ((buf[0x20] != 0xb0) || (buf[0x21] != 0x10) || + (buf[0x22] != 0xe6) || (buf[0x23] != 0x80)) { + printk(BIOS_ERR, "do_vsmbios: no vsainit.bin signature, skipping!\n"); + return; + } + + /* ecx gets smm, edx gets sysm */ + printk(BIOS_ERR, "Call real_mode_switch_call_vsm\n"); + real_mode_switch_call_vsm(MSR_GLIU0_SMM, MSR_GLIU0_SYSMEM); + + /* restart timer 1 */ + outb(0x56, 0x43); + outb(0x12, 0x41); + + // check that VSA is running OK + if (VSA_vrRead(SIGNATURE) == VSA2_SIGNATURE) + printk(BIOS_DEBUG, "do_vsmbios: VSA2 VR signature verified\n"); + else + printk(BIOS_ERR, + "do_vsmbios: VSA2 VR signature not valid, install failed!\n"); +} + +enum { + PCIBIOS = 0x1a, + MEMSIZE = 0x12 +}; + +int pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp, + unsigned long *pesp, unsigned long *pebx, unsigned long *pedx, + unsigned long *pecx, unsigned long *peax, unsigned long *pflags); + +int handleint21(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp, + unsigned long *pesp, unsigned long *pebx, unsigned long *pedx, + unsigned long *pecx, unsigned long *peax, + unsigned long *pflags); + +/* see the vga_exit() call. until we clean this up this function will remain here */ +static int biosint(unsigned long intnumber, + unsigned long gsfs, unsigned long dses, + unsigned long edi, unsigned long esi, + unsigned long ebp, unsigned long esp, + unsigned long ebx, unsigned long edx, + unsigned long ecx, unsigned long eax, + unsigned long cs_ip, unsigned short stackflags) +{ + unsigned long ip; + unsigned long cs; + unsigned long flags; + int ret = -1; + + ip = cs_ip & 0xffff; + cs = cs_ip >> 16; + flags = stackflags; + + printk(BIOS_DEBUG, "biosint: INT# 0x%lx\n", intnumber); + printk(BIOS_DEBUG, "biosint: eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n", + eax, ebx, ecx, edx); + printk(BIOS_DEBUG, "biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n", + ebp, esp, edi, esi); + printk(BIOS_DEBUG, "biosint: ip 0x%x cs 0x%x flags 0x%x\n", + ip, cs, flags); + printk(BIOS_DEBUG, "biosint: gs 0x%x fs 0x%x ds 0x%x es 0x%x\n", + gsfs >> 16, gsfs & 0xffff, dses >> 16, dses & 0xffff); + + // cases in a good compiler are just as good as your own tables. + switch (intnumber) { + case 0 ... 15: + // These are not BIOS service, but the CPU-generated exceptions + printk(BIOS_INFO, "biosint: Oops, exception %u\n", intnumber); + if (esp < 0x1000) { + printk(BIOS_DEBUG, "Stack contents: "); + while (esp < 0x1000) { + printk(BIOS_DEBUG, "0x%04x ", *(unsigned short *)esp); + esp += 2; + } + printk(BIOS_DEBUG, "\n"); + } + printk(BIOS_DEBUG, "biosint: Bailing out ... not now\n"); + // "longjmp" + //vga_exit(); + break; + + case PCIBIOS: + ret = pcibios(&edi, &esi, &ebp, &esp, + &ebx, &edx, &ecx, &eax, &flags); + break; + case MEMSIZE: + // who cares. + eax = 128 * 1024; + ret = 0; + break; + case 0x15: + ret = handleint21(&edi, &esi, &ebp, &esp, + &ebx, &edx, &ecx, &eax, &flags); + break; + default: + printk(BIOS_INFO, "BIOSINT: Unsupport int #0x%x\n", intnumber); + break; + } + if (ret) + flags |= 1; // carry flags + else + flags &= ~1; + stackflags = flags; + return ret; +} +
Modified: coreboot-v3/util/x86emu/vm86.c =================================================================== --- coreboot-v3/util/x86emu/vm86.c 2008-01-21 02:39:45 UTC (rev 559) +++ coreboot-v3/util/x86emu/vm86.c 2008-01-24 21:54:22 UTC (rev 560) @@ -37,17 +37,19 @@
__asm__ ( /* pointer to original gdt */ + " .globl gdtarg\n" "gdtarg: \n" " .word gdt_limit \n" " .long gdtptr \n"
/* compute the table limit */ "__mygdt_limit = __mygdt_end - __mygdt - 1 \n" - + " .globl __mygdtaddr\n" "__mygdtaddr: \n" " .word __mygdt_limit \n" " .long __mygdt \n"
+ " .globl __mygdt\n" "__mygdt: \n" /* selgdt 0, unused */ " .word 0x0000, 0x0000 \n" @@ -80,6 +82,7 @@ "__mygdt_end: \n"
/* FIXME: This does probably not belong here */ + " .globl idtarg\n" "idtarg:\n" " .word _idt_end - _idt - 1\n" /* limit */ " .long _idt\n" @@ -89,6 +92,7 @@ "_idt_end:\n"
/* Declare a pointer to where our idt is going to be i.e. at mem zero */ + " .globl __myidt\n" "__myidt: \n" /* 16-bit limit */ " .word 1023 \n"