From 50b12df836fddc9d76f59a23d35a801d43cfef31 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 6 Feb 2008 12:07:55 +0000 Subject: x86 vmx: Remove vmxassist. Signed-off-by: Keir Fraser --- tools/firmware/Makefile | 1 - tools/firmware/README | 88 -- tools/firmware/hvmloader/Makefile | 3 +- tools/firmware/hvmloader/config.h | 1 - tools/firmware/hvmloader/hvmloader.c | 28 +- tools/firmware/vmxassist/Makefile | 81 -- tools/firmware/vmxassist/gen.c | 52 - tools/firmware/vmxassist/head.S | 94 -- tools/firmware/vmxassist/machine.h | 199 ---- tools/firmware/vmxassist/setup.c | 337 ------ tools/firmware/vmxassist/trap.S | 179 --- tools/firmware/vmxassist/util.c | 430 ------- tools/firmware/vmxassist/util.h | 45 - tools/firmware/vmxassist/vm86.c | 1992 --------------------------------- tools/firmware/vmxassist/vm86.h | 64 -- tools/firmware/vmxassist/vmxassist.ld | 32 - 16 files changed, 2 insertions(+), 3624 deletions(-) delete mode 100644 tools/firmware/README delete mode 100644 tools/firmware/vmxassist/Makefile delete mode 100644 tools/firmware/vmxassist/gen.c delete mode 100644 tools/firmware/vmxassist/head.S delete mode 100644 tools/firmware/vmxassist/machine.h delete mode 100644 tools/firmware/vmxassist/setup.c delete mode 100644 tools/firmware/vmxassist/trap.S delete mode 100644 tools/firmware/vmxassist/util.c delete mode 100644 tools/firmware/vmxassist/util.h delete mode 100644 tools/firmware/vmxassist/vm86.c delete mode 100644 tools/firmware/vmxassist/vm86.h delete mode 100644 tools/firmware/vmxassist/vmxassist.ld (limited to 'tools/firmware') diff --git a/tools/firmware/Makefile b/tools/firmware/Makefile index 0ec31883fd..67fee87473 100644 --- a/tools/firmware/Makefile +++ b/tools/firmware/Makefile @@ -9,7 +9,6 @@ INST_DIR := $(DESTDIR)/usr/lib/xen/boot SUBDIRS := SUBDIRS += rombios rombios/32bit SUBDIRS += vgabios -SUBDIRS += vmxassist SUBDIRS += extboot #SUBDIRS += etherboot SUBDIRS += hvmloader diff --git a/tools/firmware/README b/tools/firmware/README deleted file mode 100644 index be796000f6..0000000000 --- a/tools/firmware/README +++ /dev/null @@ -1,88 +0,0 @@ -Domain firmware support ------------------------ - -One of the key advantages of full virtualization hardware support (such -as Intel's VT or AMD's SVM extensions) is the ability to run unmodified -guest operating systems. However, since most OSes rely on BIOS support -during their early bringup, we need to provide a surrogate ROMBIOS and -VGABIOS firmware layer. - -What's more, we need to support real-mode which is required by -the firmware and bootstrap loaders. Real-mode support is especially -challenging for Intel's VMX (VT) enabled CPUs where there is no real-mode -support for VMX guest partitions. In this case you either have to do full -emulation (full real-mode emulator; more complete but potentially slower) -or partial emulation (use the VM8086 extensions, emulate only those -instructions that are missing; faster, but potentially incomplete). The -vmxassist code in this subdirectory uses the later approach because it -is smaller and faster. - -The approach is relatively straight forward. Vmxloader contains three -payloads (rombios, vgabios and vmxassist) and it is bootstrapped as any -other 32-bit OS. Vmxloader copies its payloads to the addresses below -and transfers control to vmxassist. - - vgabios VGABIOS (standard and Cirrus). - Resides at C000:0000. - - vmxassist VMXAssist VM86 realmode emulator for VMX. - Resides at D000:0000. - - rombios ROMBIOS code. Derived from Bochs. - Resides at F000:0000 - -Vmxassist first sets up it own world (GDT, IDT, TR, etc), enables -VM8086 and then transfers control to F000:FFF0 and executes 16-bit -code. Unsupported instructions cause a general protection failure at -which point vmxassist kicks in and emulates the offending instruction. -Whever the emulated code transitions to 32-bit protected mode, vmxassist -will go away. Whenever 32-bit protected code transitions to real-mode, -Xen/VMX will detect this and transfer control to vmxassist. - -Most of the vmxassist complexity comes from properly handling the -real to protected mode and protected to real mode transitions and -the proper emulation of the segment registers. Even though the Intel -manual clearly states that you should immediately perform a jmp far -after a mode transition, many operating systems execute additional -instructions and some even refer to segment selectors and pop data -from the stack. Vmxassist contains a number of work arounds for these -OSes. - - -Acknowledgements ----------------- - -The rombios was taken (largely unmodified) from Bochs, which was written -by Kevin Lawton. The VGABIOS was written by Christophe Bothamy. Arun Sharma, -Asit Mallick and Nitin Kamble (Intel) provided the E820 patches and lots -of useful feedback. - - -Contact -------- - -Leendert van Doorn -IBM T.J. Watson Research Center -19 Skyline Drive -Hawthorne, NY 10532 -leendert@watson.ibm.com - - -Tested Operating Systems ------------------------- - -Since vmxassist uses partial emulation, it may always miss opcodes -that are required by a particular OS. The table below lists the OSes -I have tried. The Install column indicates a full CD/DVD install into -a VMX partition. The Disk column indicates booting from prefabricated -disk image. - -Operating System Install Disk ------------------------------------------------------------- -RedHat Enterprise Linux (RHEL3_U5) Yes Yes -Fedora Code (FC3) (-) Yes -FreeBSD 5.3 (-) Yes -MS-DOS 5.0 (-) Yes - -(-) not tried yet - diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index f34bcb3880..6187480586 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -50,11 +50,10 @@ hvmloader: roms.h acpi/acpi.a $(SRCS) acpi/acpi.a: $(MAKE) -C acpi -roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabios/VGABIOS-lgpl-latest.cirrus.bin ../vmxassist/vmxassist.bin ../etherboot/eb-roms.h ../extboot/extboot.bin +roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabios/VGABIOS-lgpl-latest.cirrus.bin ../etherboot/eb-roms.h ../extboot/extboot.bin sh ./mkhex rombios ../rombios/BIOS-bochs-latest > roms.h sh ./mkhex vgabios_stdvga ../vgabios/VGABIOS-lgpl-latest.bin >> roms.h sh ./mkhex vgabios_cirrusvga ../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h - sh ./mkhex vmxassist ../vmxassist/vmxassist.bin >> roms.h cat ../etherboot/eb-roms.h >> roms.h sh ./mkhex extboot ../extboot/extboot.bin >> roms.h diff --git a/tools/firmware/hvmloader/config.h b/tools/firmware/hvmloader/config.h index 12c89db821..24d3e47159 100644 --- a/tools/firmware/hvmloader/config.h +++ b/tools/firmware/hvmloader/config.h @@ -21,7 +21,6 @@ #define HYPERCALL_PHYSICAL_ADDRESS 0x00080000 #define VGABIOS_PHYSICAL_ADDRESS 0x000C0000 #define ETHERBOOT_PHYSICAL_ADDRESS 0x000C8000 -#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000 #define EXTBOOT_PHYSICAL_ADDRESS 0x000DF800 #define SMBIOS_PHYSICAL_ADDRESS 0x000E9000 #define SMBIOS_MAXIMUM_SIZE 0x00001000 diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index 9316ff81a1..b59120dd03 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -1,5 +1,5 @@ /* - * hvmloader.c: HVM ROMBIOS/VGABIOS/ACPI/VMXAssist image loader. + * hvmloader.c: HVM bootloader. * * Leendert van Doorn, leendert@watson.ibm.com * Copyright (c) 2005, International Business Machines Corporation. @@ -40,7 +40,6 @@ asm( " cli \n" " movl $stack_top,%esp \n" " movl %esp,%ebp \n" - " movl %eax,initial_eax \n" " call main \n" /* Relocate real-mode trampoline to 0x0. */ " mov $trampoline_start,%esi \n" @@ -98,8 +97,6 @@ asm( "stack_top: \n" ); -static unsigned int initial_eax; - void create_mp_tables(void); int hvm_write_smbios_tables(void); @@ -124,12 +121,6 @@ check_amd(void) return __builtin_memcmp(id, "AuthenticAMD", 12) == 0; } -static int -use_vmxassist(void) -{ - return !check_amd() && !initial_eax; -} - static void wrmsr(uint32_t idx, uint64_t v) { @@ -506,10 +497,6 @@ int main(void) printf(" %05x-%05x: Extboot ROM\n", EXTBOOT_PHYSICAL_ADDRESS, EXTBOOT_PHYSICAL_ADDRESS + extboot_sz - 1); - if ( use_vmxassist() ) - printf(" %05x-%05x: VMXAssist\n", - VMXASSIST_PHYSICAL_ADDRESS, - VMXASSIST_PHYSICAL_ADDRESS + sizeof(vmxassist) - 1); if ( smbios_sz ) printf(" %05x-%05x: SMBIOS tables\n", SMBIOS_PHYSICAL_ADDRESS, @@ -523,19 +510,6 @@ int main(void) ROMBIOS_PHYSICAL_ADDRESS, ROMBIOS_PHYSICAL_ADDRESS + rombios_sz - 1); - if ( use_vmxassist() ) - { - printf("Loading VMXAssist ...\n"); - memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS, - vmxassist, sizeof(vmxassist)); - - printf("VMX go ...\n"); - __asm__ __volatile__( - "jmp *%%eax" - : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0) - ); - } - printf("Invoking ROMBIOS ...\n"); return 0; } diff --git a/tools/firmware/vmxassist/Makefile b/tools/firmware/vmxassist/Makefile deleted file mode 100644 index 503f9cea82..0000000000 --- a/tools/firmware/vmxassist/Makefile +++ /dev/null @@ -1,81 +0,0 @@ -# -# Makefile -# -# Leendert van Doorn, leendert@watson.ibm.com -# Copyright (c) 2005, International Business Machines Corporation. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms and conditions of the GNU General Public License, -# version 2, as published by the Free Software Foundation. -# -# This program is distributed in the hope 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. -# - -# External CFLAGS can do more harm than good. -CFLAGS := - -override XEN_TARGET_ARCH = x86_32 -XEN_ROOT = ../../.. -include $(XEN_ROOT)/tools/Rules.mk - -# The emulator code lives in ROM space -TEXTADDR=0x000D0000 - -DEFINES=-DDEBUG -DTEXTADDR=$(TEXTADDR) -XENINC=$(CFLAGS_include) - -# Disable PIE/SSP if GCC supports them. They can break us. -CFLAGS += $(call cc-option,$(CC),-nopie,) -CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) -CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) - -CPP = cpp -P -CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float - -OBJECTS = head.o trap.o vm86.o setup.o util.o - -.PHONY: all -all: vmxassist.bin - -vmxassist.bin: vmxassist.ld $(OBJECTS) - $(CPP) $(DEFINES) vmxassist.ld > vmxassist.tmp - $(LD) -o vmxassist $(LDFLAGS_DIRECT) --fatal-warnings -N -T vmxassist.tmp $(OBJECTS) - nm -n vmxassist > vmxassist.sym - $(OBJCOPY) -p -O binary -R .note -R .comment -R .bss -S --gap-fill=0 vmxassist vmxassist.tmp - dd if=vmxassist.tmp of=vmxassist.bin ibs=512 conv=sync - rm -f vmxassist.tmp - -head.o: machine.h vm86.h head.S - $(CC) $(CFLAGS) -D__ASSEMBLY__ $(DEFINES) -c head.S - -trap.o: machine.h vm86.h offsets.h trap.S - $(CC) $(CFLAGS) -D__ASSEMBLY__ $(DEFINES) -c trap.S - -vm86.o: machine.h vm86.h vm86.c - $(CC) $(CFLAGS) -c vm86.c - -setup.o: machine.h vm86.h setup.c - $(CC) $(CFLAGS) -c setup.c - -util.o: machine.h vm86.h util.c - $(CC) $(CFLAGS) -c util.c - -offsets.h: gen - ./gen > offsets.h - -gen: vm86.h gen.c - $(HOSTCC) $(HOSTCFLAGS) -I. $(XENINC) -o gen gen.c - -.PHONY: clean -clean: - rm -f vmxassist vmxassist.tmp vmxassist.bin vmxassist.run vmxassist.sym head.s - rm -f $(OBJECTS) - rm -f gen gen.o offsets.h - diff --git a/tools/firmware/vmxassist/gen.c b/tools/firmware/vmxassist/gen.c deleted file mode 100644 index 2dcb229ee8..0000000000 --- a/tools/firmware/vmxassist/gen.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * gen.c: Generate assembler symbols. - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#include -#include -#include -#include - -int -main(void) -{ - printf("/* MACHINE GENERATED; DO NOT EDIT */\n"); - printf("#define VMX_ASSIST_CTX_GS_SEL 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, gs_sel)); - printf("#define VMX_ASSIST_CTX_FS_SEL 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, fs_sel)); - printf("#define VMX_ASSIST_CTX_DS_SEL 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, ds_sel)); - printf("#define VMX_ASSIST_CTX_ES_SEL 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, es_sel)); - printf("#define VMX_ASSIST_CTX_SS_SEL 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, ss_sel)); - printf("#define VMX_ASSIST_CTX_ESP 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, esp)); - printf("#define VMX_ASSIST_CTX_EFLAGS 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, eflags)); - printf("#define VMX_ASSIST_CTX_CS_SEL 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, cs_sel)); - printf("#define VMX_ASSIST_CTX_EIP 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, eip)); - - printf("#define VMX_ASSIST_CTX_CR0 0x%x\n", - (unsigned int)offsetof(struct vmx_assist_context, cr0)); - - return 0; -} diff --git a/tools/firmware/vmxassist/head.S b/tools/firmware/vmxassist/head.S deleted file mode 100644 index 3af285eada..0000000000 --- a/tools/firmware/vmxassist/head.S +++ /dev/null @@ -1,94 +0,0 @@ -/* - * head.S: VMXAssist runtime start off. - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#include "vm86.h" -#include "machine.h" - -/* - * When a partition tries to mask off the CR0_PE bit a world - * switch happens to the environment below. The magic indicates - * that this is a valid context. - */ - jmp _start - - .align 8 - .long VMXASSIST_MAGIC - .long newctx /* new context */ - .long oldctx /* old context */ - -/* - * This is the real start. Control was transfered to this point - * with CR0_PE set and executing in some 32-bit segment. We call - * main and setup our own environment. - */ - .globl _start - .code32 -_start: - cli - - /* save register parameters to C land */ - - /* clear bss */ - cld - xorb %al, %al - movl $_bbss, %edi - movl $_ebss, %ecx - subl %edi, %ecx - rep stosb - - movl %edx, booting_cpu - movl %ebx, booting_vector - - /* make sure we are in a sane world */ - clts - - /* setup my own stack */ - movl $stack_top, %esp - movl %esp, %ebp - - /* go ... */ - call main - jmp halt - -/* - * Something bad happened, print invoking %eip and loop forever - */ - .align 4 - .globl halt -halt: - push $halt_msg - call printf - cli - jmp . - - .data -halt_msg: - .asciz "Halt called from %%eip 0x%x\n" - - -/* - * Our stack - */ - .bss - .align 8 - .globl stack, stack_top -stack: - .skip STACK_SIZE -stack_top: - diff --git a/tools/firmware/vmxassist/machine.h b/tools/firmware/vmxassist/machine.h deleted file mode 100644 index f91646f3e3..0000000000 --- a/tools/firmware/vmxassist/machine.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * machine.h: Intel CPU specific definitions - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#ifndef __MACHINE_H__ -#define __MACHINE_H__ - -/* the size of our stack (4KB) */ -#define STACK_SIZE 8192 - -#define TSS_SELECTOR 0x08 -#define CODE_SELECTOR 0x10 -#define DATA_SELECTOR 0x18 - -#define CR0_PE (1 << 0) -#define CR0_EM (1 << 2) -#define CR0_TS (1 << 3) -#define CR0_NE (1 << 5) -#define CR0_PG (1 << 31) - -#define CR4_VME (1 << 0) -#define CR4_PVI (1 << 1) -#define CR4_PSE (1 << 4) -#define CR4_PAE (1 << 5) - -#define EFLAGS_CF (1 << 0) -#define EFLAGS_PF (1 << 2) -#define EFLAGS_AF (1 << 4) -#define EFLAGS_ZF (1 << 6) -#define EFLAGS_SF (1 << 7) -#define EFLAGS_TF (1 << 8) -#define EFLAGS_IF (1 << 9) -#define EFLAGS_DF (1 << 10) -#define EFLAGS_OF (1 << 11) -#define EFLAGS_IOPL (3 << 12) -#define EFLAGS_VM ((1 << 17) | EFLAGS_IOPL) -#define EFLAGS_VIF (1 << 19) -#define EFLAGS_VIP (1 << 20) - -#define LOG_PGSIZE 12 /* log2(page size) */ -#define LOG_PDSIZE 22 /* log2(page directory size) */ - -/* Derived constants */ -#define PGSIZE (1 << LOG_PGSIZE) /* page size */ -#define PGMASK (~(PGSIZE - 1)) /* page mask */ -#define LPGSIZE (1 << LOG_PDSIZE) /* large page size */ -#define LPGMASK (~(LPGSIZE - 1)) /* large page mask */ - -/* Programmable Interrupt Contoller (PIC) defines */ -#define PIC_MASTER 0x20 -#define PIC_SLAVE 0xA0 - -#define PIC_CMD 0 /* command */ -#define PIC_ISR 0 /* interrupt status */ -#define PIC_IMR 1 /* interrupt mask */ - - -#ifndef __ASSEMBLY__ - -struct dtr { - unsigned short size; - unsigned long base __attribute__ ((packed)); -}; - -struct tss { - unsigned short prev_link; - unsigned short _1; - unsigned long esp0; - unsigned short ss0; - unsigned short _2; - unsigned long esp1; - unsigned short ss1; - unsigned short _3; - unsigned long esp2; - unsigned short ss2; - unsigned short _4; - unsigned long cr3; - unsigned long eip; - unsigned long eflags; - unsigned long eax; - unsigned long ecx; - unsigned long edx; - unsigned long ebx; - unsigned long esi; - unsigned long edi; - unsigned long esp; - unsigned long ebp; - unsigned long es; - unsigned long cs; - unsigned long ss; - unsigned long ds; - unsigned long fs; - unsigned long gs; - unsigned short ldt_segment; - unsigned short _5; - unsigned short _6; - unsigned short iomap_base; -#ifdef ENABLE_VME - unsigned long int_redir[8]; -#endif - unsigned char iomap[8193]; -}; - -static inline void -outw(unsigned short addr, unsigned short val) -{ - __asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val)); -} - -static inline void -outb(unsigned short addr, unsigned char val) -{ - __asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val)); -} - -static inline unsigned char -inb(unsigned short addr) -{ - unsigned char val; - - __asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr)); - return val; -} - -static inline unsigned -get_cmos(int reg) -{ - outb(0x70, reg); - return inb(0x71); -} - -static inline unsigned -get_cr0(void) -{ - unsigned rv; - __asm__ __volatile__("movl %%cr0, %0" : "=r"(rv)); - return rv; -} - -static inline void -set_cr0(unsigned value) -{ - __asm__ __volatile__( - "movl %0, %%cr0\n" - "jmp 1f\n" - "1: nop\n" - : /* no outputs */ - : "r"(value) - ); -} - -static inline unsigned -get_cr2(void) -{ - unsigned rv; - - __asm__ __volatile__("movl %%cr2, %0" : "=r"(rv)); - return rv; -} - -static inline unsigned -get_cr4(void) -{ - unsigned rv; - __asm__ __volatile__("movl %%cr4, %0" : "=r"(rv)); - return rv; -} - -static inline void -set_cr3(unsigned addr) -{ - __asm__ __volatile__("movl %0, %%cr3" : /* no outputs */ : "r"(addr)); -} - -static inline void -set_cr4(unsigned value) -{ - __asm__ __volatile__("movl %0, %%cr4" : /* no outputs */ : "r"(value)); -} - -#endif /* __ASSEMBLY__ */ - -#endif /* __MACHINE_H__ */ - diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c deleted file mode 100644 index 1e2e86c27b..0000000000 --- a/tools/firmware/vmxassist/setup.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * setup.c: Setup the world for vmxassist. - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#include "vm86.h" -#include "util.h" -#include "machine.h" - -#if (VMXASSIST_BASE != TEXTADDR) -#error VMXAssist base mismatch -#endif - -#define NR_PGD (PGSIZE / sizeof(unsigned)) - -#define min(a, b) ((a) > (b) ? (b) : (a)) - -/* Which CPU are we booting, and what is the initial CS segment? */ -int booting_cpu, booting_vector; - -unsigned long long gdt[] __attribute__ ((aligned(32))) = { - 0x0000000000000000ULL, /* 0x00: reserved */ - 0x0000890000000000ULL, /* 0x08: 32-bit TSS */ - 0x00CF9A000000FFFFULL, /* 0x10: CS 32-bit */ - 0x00CF92000000FFFFULL, /* 0x18: DS 32-bit */ -}; - -struct dtr gdtr = { sizeof(gdt)-1, (unsigned long) &gdt }; - -struct tss tss __attribute__ ((aligned(4))); - -unsigned long long idt[NR_TRAPS] __attribute__ ((aligned(32))); - -struct dtr idtr = { sizeof(idt)-1, (unsigned long) &idt }; - -struct vmx_assist_context oldctx; -struct vmx_assist_context newctx; - -unsigned long memory_size; -int initialize_real_mode; - -extern char stack_top[]; -extern unsigned trap_handlers[]; - -void -banner(void) -{ - printf("VMXAssist (%s)\n", __DATE__); - - /* Bochs its way to convey memory size */ - memory_size = ((get_cmos(0x35) << 8) | get_cmos(0x34)) << 6; - if (memory_size > 0x3bc000) - memory_size = 0x3bc000; - memory_size = (memory_size << 10) + 0xF00000; - if (memory_size <= 0xF00000) - memory_size = - (((get_cmos(0x31) << 8) | get_cmos(0x30)) + 0x400) << 10; - memory_size += 0x400 << 10; /* + 1MB */ - - printf("Memory size %ld MB\n", memory_size >> 20); - printf("E820 map:\n"); - print_e820_map(HVM_E820, *HVM_E820_NR); - printf("\n"); -} - -void -setup_gdt(void) -{ - unsigned long long addr = (unsigned long long) &tss; - - /* setup task state segment */ - memset(&tss, 0, sizeof(tss)); - tss.ss0 = DATA_SELECTOR; - tss.esp0 = (unsigned) stack_top; - tss.iomap_base = offsetof(struct tss, iomap); - tss.iomap[sizeof(tss.iomap)-1] = 0xff; - - /* initialize gdt's tss selector */ - gdt[TSS_SELECTOR / sizeof(gdt[0])] |= - ((addr & 0xFF000000) << (56-24)) | - ((addr & 0x00FF0000) << (32-16)) | - ((addr & 0x0000FFFF) << (16)) | - (sizeof(tss) - 1); - - /* switch to our own gdt and set current tss */ - __asm__ __volatile__ ("lgdt %0" : : "m" (gdtr)); - __asm__ __volatile__ ("movl %%eax,%%ds;" - "movl %%eax,%%es;" - "movl %%eax,%%fs;" - "movl %%eax,%%gs;" - "movl %%eax,%%ss" : : "a" (DATA_SELECTOR)); - - __asm__ __volatile__ ("ljmp %0,$1f; 1:" : : "i" (CODE_SELECTOR)); - - __asm__ __volatile__ ("ltr %%ax" : : "a" (TSS_SELECTOR)); -} - -void -set_intr_gate(int i, unsigned handler) -{ - unsigned long long addr = handler; - - idt[i] = ((addr & 0xFFFF0000ULL) << 32) | (0x8E00ULL << 32) | - (addr & 0xFFFFULL) | (CODE_SELECTOR << 16); -} - -void -setup_idt(void) -{ - int i; - - for (i = 0; i < NR_TRAPS; i++) - set_intr_gate(i, trap_handlers[i]); - __asm__ __volatile__ ("lidt %0" : : "m" (idtr)); -} - -void -setup_pic(void) -{ - /* mask all interrupts */ - outb(PIC_MASTER + PIC_IMR, 0xFF); - outb(PIC_SLAVE + PIC_IMR, 0xFF); - - /* setup master PIC */ - outb(PIC_MASTER + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */ - outb(PIC_MASTER + PIC_IMR, NR_EXCEPTION_HANDLER); - outb(PIC_MASTER + PIC_IMR, 1 << 2); /* slave on channel 2 */ - outb(PIC_MASTER + PIC_IMR, 0x01); - - /* setup slave PIC */ - outb(PIC_SLAVE + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */ - outb(PIC_SLAVE + PIC_IMR, NR_EXCEPTION_HANDLER + 8); - outb(PIC_SLAVE + PIC_IMR, 0x02); /* slave identity is 2 */ - outb(PIC_SLAVE + PIC_IMR, 0x01); - - /* enable all interrupts */ - outb(PIC_MASTER + PIC_IMR, 0); - outb(PIC_SLAVE + PIC_IMR, 0); -} - -void -setiomap(int port) -{ - tss.iomap[port >> 3] |= 1 << (port & 7); -} - -void -enter_real_mode(struct regs *regs) -{ - /* mask off TSS busy bit */ - gdt[TSS_SELECTOR / sizeof(gdt[0])] &= ~0x0000020000000000ULL; - - /* start 8086 emulation of BIOS */ - if (initialize_real_mode) { - initialize_real_mode = 0; - regs->eflags |= EFLAGS_VM | 0x02; - regs->ves = regs->vds = regs->vfs = regs->vgs = 0xF000; - if (booting_cpu == 0) { - regs->cs = 0xF000; /* ROM BIOS POST entry point */ - regs->eip = 0xFFF0; - } else { - regs->cs = booting_vector << 8; /* AP entry point */ - regs->eip = 0; - } - - regs->uesp = regs->uss = 0; - regs->eax = regs->ecx = regs->edx = regs->ebx = 0; - regs->esp = regs->ebp = regs->esi = regs->edi = 0; - - /* intercept accesses to the PIC */ - setiomap(PIC_MASTER+PIC_CMD); - setiomap(PIC_MASTER+PIC_IMR); - setiomap(PIC_SLAVE+PIC_CMD); - setiomap(PIC_SLAVE+PIC_IMR); - - printf("Starting emulated 16-bit real-mode: ip=%04x:%04x\n", - regs->cs, regs->eip); - - mode = VM86_REAL; /* becomes previous mode */ - set_mode(regs, VM86_REAL); - - /* this should get us into 16-bit mode */ - return; - } - - /* go from protected to real mode */ - set_mode(regs, VM86_PROTECTED_TO_REAL); - emulate(regs); - if (mode != VM86_REAL) - panic("failed to emulate between clear PE and long jump.\n"); -} - -/* - * Setup the environment for VMX assist. - * This environment consists of flat segments (code and data), - * its own gdt, idt, and tr. - */ -void -setup_ctx(void) -{ - struct vmx_assist_context *c = &newctx; - - memset(c, 0, sizeof(*c)); - c->eip = (unsigned long) switch_to_real_mode; - c->esp = (unsigned) stack_top; - c->eflags = 0x2; /* no interrupts, please */ - - /* - * Obviously, vmx assist is not running with CR0_PE disabled. - * The reason why the vmx assist cr0 has CR0.PE disabled is - * that a transtion to CR0.PE causes a world switch. It seems - * more natural to enable CR0.PE to cause a world switch to - * protected mode rather than disabling it. - */ - c->cr0 = (get_cr0() | CR0_NE) & ~CR0_PE; - c->cr3 = 0; - c->cr4 = get_cr4(); - - c->idtr_limit = sizeof(idt)-1; - c->idtr_base = (unsigned long) &idt; - - c->gdtr_limit = sizeof(gdt)-1; - c->gdtr_base = (unsigned long) &gdt; - - c->cs_sel = CODE_SELECTOR; - c->cs_limit = 0xFFFFFFFF; - c->cs_base = 0; - c->cs_arbytes.fields.seg_type = 0xb; - c->cs_arbytes.fields.s = 1; - c->cs_arbytes.fields.dpl = 0; - c->cs_arbytes.fields.p = 1; - c->cs_arbytes.fields.avl = 0; - c->cs_arbytes.fields.default_ops_size = 1; - c->cs_arbytes.fields.g = 1; - - c->ds_sel = DATA_SELECTOR; - c->ds_limit = 0xFFFFFFFF; - c->ds_base = 0; - c->ds_arbytes = c->cs_arbytes; - c->ds_arbytes.fields.seg_type = 0x3; - - c->es_sel = DATA_SELECTOR; - c->es_limit = 0xFFFFFFFF; - c->es_base = 0; - c->es_arbytes = c->ds_arbytes; - - c->ss_sel = DATA_SELECTOR; - c->ss_limit = 0xFFFFFFFF; - c->ss_base = 0; - c->ss_arbytes = c->ds_arbytes; - - c->fs_sel = DATA_SELECTOR; - c->fs_limit = 0xFFFFFFFF; - c->fs_base = 0; - c->fs_arbytes = c->ds_arbytes; - - c->gs_sel = DATA_SELECTOR; - c->gs_limit = 0xFFFFFFFF; - c->gs_base = 0; - c->gs_arbytes = c->ds_arbytes; - - c->tr_sel = TSS_SELECTOR; - c->tr_limit = sizeof(tss) - 1; - c->tr_base = (unsigned long) &tss; - c->tr_arbytes.fields.seg_type = 0xb; /* 0x9 | 0x2 (busy) */ - c->tr_arbytes.fields.s = 0; - c->tr_arbytes.fields.dpl = 0; - c->tr_arbytes.fields.p = 1; - c->tr_arbytes.fields.avl = 0; - c->tr_arbytes.fields.default_ops_size = 0; - c->tr_arbytes.fields.g = 0; - - c->ldtr_sel = 0; - c->ldtr_limit = 0; - c->ldtr_base = 0; - c->ldtr_arbytes = c->ds_arbytes; - c->ldtr_arbytes.fields.seg_type = 0x2; - c->ldtr_arbytes.fields.s = 0; - c->ldtr_arbytes.fields.dpl = 0; - c->ldtr_arbytes.fields.p = 1; - c->ldtr_arbytes.fields.avl = 0; - c->ldtr_arbytes.fields.default_ops_size = 0; - c->ldtr_arbytes.fields.g = 0; -} - -/* - * Start BIOS by causing a world switch to vmxassist, which causes - * VM8086 to be enabled and control is transfered to F000:FFF0. - */ -void -start_bios(void) -{ - if (booting_cpu == 0) - printf("Start BIOS ...\n"); - else - printf("Start AP %d from %08x ...\n", - booting_cpu, booting_vector << 12); - - initialize_real_mode = 1; - set_cr0(get_cr0() & ~CR0_PE); - panic("vmxassist returned"); /* "cannot happen" */ -} - -int -main(void) -{ - if (booting_cpu == 0) - banner(); - - setup_gdt(); - setup_idt(); - - set_cr4(get_cr4() | CR4_VME); - - setup_ctx(); - - if (booting_cpu == 0) - setup_pic(); - - start_bios(); - - return 0; -} diff --git a/tools/firmware/vmxassist/trap.S b/tools/firmware/vmxassist/trap.S deleted file mode 100644 index d5ece3e143..0000000000 --- a/tools/firmware/vmxassist/trap.S +++ /dev/null @@ -1,179 +0,0 @@ -/* - * trap.S: Trap and world switch handlers - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#include "machine.h" -#include "vm86.h" -#include "offsets.h" - -/* - * All processor exception/faults/interrupts end up here. - * - * On an exception/fault, the processor pushes CS:EIP, SS, ESP and an - * optional error code onto the stack. The common_trap routine - * below saves the processor context and transfers control to trap() - * whose job it is to virtualize and pass on the trap. - */ - .macro TRAP_HANDLER trapno error - .text - .align 16 -1: .if \error == 0 - pushl $0 /* dummy error code */ - .endif - pushl $\trapno - jmp common_trap - .section .rodata - .long 1b - .text - .endm - - .section .rodata - .code32 - .align 4 - .global trap_handlers -trap_handlers: - TRAP_HANDLER 0, 0 /* divide error */ - TRAP_HANDLER 1, 0 /* debug */ - TRAP_HANDLER 2, 0 /* NMI interrupt */ - TRAP_HANDLER 3, 0 /* breakpoint */ - TRAP_HANDLER 4, 0 /* overflow */ - TRAP_HANDLER 5, 0 /* BOUND range exceeded */ - TRAP_HANDLER 6, 0 /* invalid opcode */ - TRAP_HANDLER 7, 0 /* device not available */ - TRAP_HANDLER 8, 1 /* double fault */ - TRAP_HANDLER 9, 0 /* coprocessor segment overrun */ - TRAP_HANDLER 10, 1 /* invalid TSS */ - TRAP_HANDLER 11, 1 /* segment not present */ - TRAP_HANDLER 12, 1 /* stack-segment fault */ - TRAP_HANDLER 13, 1 /* general protection */ - TRAP_HANDLER 14, 1 /* page fault */ - TRAP_HANDLER 15, 0 /* reserved */ - TRAP_HANDLER 16, 0 /* FPU floating-point error */ - TRAP_HANDLER 17, 1 /* alignment check */ - TRAP_HANDLER 18, 0 /* machine check */ - TRAP_HANDLER 19, 0 /* SIMD floating-point error */ - TRAP_HANDLER 20, 0 /* reserved */ - TRAP_HANDLER 21, 0 /* reserved */ - TRAP_HANDLER 22, 0 /* reserved */ - TRAP_HANDLER 23, 0 /* reserved */ - TRAP_HANDLER 24, 0 /* reserved */ - TRAP_HANDLER 25, 0 /* reserved */ - TRAP_HANDLER 26, 0 /* reserved */ - TRAP_HANDLER 27, 0 /* reserved */ - TRAP_HANDLER 28, 0 /* reserved */ - TRAP_HANDLER 29, 0 /* reserved */ - TRAP_HANDLER 30, 0 /* reserved */ - TRAP_HANDLER 31, 0 /* reserved */ - TRAP_HANDLER 32, 0 /* irq 0 */ - TRAP_HANDLER 33, 0 /* irq 1 */ - TRAP_HANDLER 34, 0 /* irq 2 */ - TRAP_HANDLER 35, 0 /* irq 3 */ - TRAP_HANDLER 36, 0 /* irq 4 */ - TRAP_HANDLER 37, 0 /* irq 5 */ - TRAP_HANDLER 38, 0 /* irq 6 */ - TRAP_HANDLER 39, 0 /* irq 7 */ - TRAP_HANDLER 40, 0 /* irq 8 */ - TRAP_HANDLER 41, 0 /* irq 9 */ - TRAP_HANDLER 42, 0 /* irq 10 */ - TRAP_HANDLER 43, 0 /* irq 11 */ - TRAP_HANDLER 44, 0 /* irq 12 */ - TRAP_HANDLER 45, 0 /* irq 13 */ - TRAP_HANDLER 46, 0 /* irq 14 */ - TRAP_HANDLER 47, 0 /* irq 15 */ - - .text - .code32 - .align 16 -common_trap: /* common trap handler */ - pushal - - movl $(DATA_SELECTOR), %eax /* make sure these are sane */ - movl %eax, %ds - movl %eax, %es - movl %eax, %fs - movl %eax, %gs - movl %esp, %ebp - - pushl %ebp - pushl 36(%ebp) - pushl 32(%ebp) - call trap /* trap(trapno, errno, regs) */ - addl $12, %esp - -trap_return: - popal - addl $8, %esp /* skip trapno, errno */ - iret - /* NOT REACHED */ - - -/* - * A world switch to real mode occured. The hypervisor saved the - * executing context into "oldctx" and instantiated "newctx", which - * gets us here. Here we push a stack frame that is compatible with - * a trap frame (see above) so that we can handle this event as a - * regular trap. - */ - .text - .align 16 - .globl switch_to_real_mode -switch_to_real_mode: - pushl oldctx+VMX_ASSIST_CTX_GS_SEL /* 16 to 32-bit transition */ - pushl oldctx+VMX_ASSIST_CTX_FS_SEL - pushl oldctx+VMX_ASSIST_CTX_DS_SEL - pushl oldctx+VMX_ASSIST_CTX_ES_SEL - pushl oldctx+VMX_ASSIST_CTX_SS_SEL - pushl oldctx+VMX_ASSIST_CTX_ESP - pushl oldctx+VMX_ASSIST_CTX_EFLAGS - pushl oldctx+VMX_ASSIST_CTX_CS_SEL - pushl oldctx+VMX_ASSIST_CTX_EIP - pushl $-1 /* trapno, errno */ - pushl $-1 - pushal - - movl %esp, %ebp - pushl %ebp - call enter_real_mode - addl $4, %esp - - jmp trap_return - /* NOT REACHED */ - - -/* - * Switch to protected mode. At this point all the registers have - * been reloaded by trap_return and all we have to do is cause a - * world switch by turning on CR0.PE. - */ - .text - .align 16 - .globl switch_to_protected_mode -switch_to_protected_mode: - movl oldctx+VMX_ASSIST_CTX_CR0, %esp - movl %esp, %cr0 /* actual world switch ! */ - - /* NOT REACHED */ - pushl $switch_failed - call panic - jmp . - - .data - .align 4 -switch_failed: - .asciz "World switch to protected mode failed\n" - diff --git a/tools/firmware/vmxassist/util.c b/tools/firmware/vmxassist/util.c deleted file mode 100644 index c7d71703ed..0000000000 --- a/tools/firmware/vmxassist/util.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * util.c: Commonly used utility functions. - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#include - -#include "util.h" -#include "machine.h" - -#define isdigit(c) ((c) >= '0' && (c) <= '9') -#define min(a, b) ((a) < (b) ? (a) : (b)) - -static void putchar(int); -static char *printnum(char *, unsigned long, int); -static void _doprint(void (*)(int), const char *, va_list); - -void -cpuid_addr_value(uint64_t addr, uint64_t *value) -{ - uint32_t addr_low = (uint32_t)addr; - uint32_t addr_high = (uint32_t)(addr >> 32); - uint32_t value_low, value_high; - static unsigned int addr_leaf; - - if (!addr_leaf) { - unsigned int eax, ebx, ecx, edx; - __asm__ __volatile__( - "cpuid" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "0" (0x40000000)); - addr_leaf = eax + 1; - } - - __asm__ __volatile__( - "cpuid" - : "=c" (value_low), "=d" (value_high) - : "a" (addr_leaf), "0" (addr_low), "1" (addr_high) - : "ebx"); - - *value = (uint64_t)value_high << 32 | value_low; -} - -void -dump_regs(struct regs *regs) -{ - printf("eax %8x ecx %8x edx %8x ebx %8x\n", - regs->eax, regs->ecx, regs->edx, regs->ebx); - printf("esp %8x ebp %8x esi %8x edi %8x\n", - regs->esp, regs->ebp, regs->esi, regs->edi); - printf("trapno %8x errno %8x\n", regs->trapno, regs->errno); - printf("eip %8x cs %8x eflags %8x\n", - regs->eip, regs->cs, regs->eflags); - printf("uesp %8x uss %8x\n", - regs->uesp, regs->uss); - printf("ves %8x vds %8x vfs %8x vgs %8x\n", - regs->ves, regs->vds, regs->vfs, regs->vgs); - - printf("cr0 %8lx cr2 %8x cr3 %8lx cr4 %8lx\n\n", - (long)oldctx.cr0, get_cr2(), - (long)oldctx.cr3, (long)oldctx.cr4); -} - -#ifdef DEBUG -void -hexdump(unsigned char *data, int sz) -{ - unsigned char *d; - int i; - - for (d = data; sz > 0; d += 16, sz -= 16) { - int n = sz > 16 ? 16 : sz; - - printf("%08x: ", (unsigned)d); - for (i = 0; i < n; i++) - printf("%02x%c", d[i], i == 7 ? '-' : ' '); - for (; i < 16; i++) - printf(" %c", i == 7 ? '-' : ' '); - printf(" "); - for (i = 0; i < n; i++) - printf("%c", d[i] >= ' ' && d[i] <= '~' ? d[i] : '.'); - printf("\n"); - } -} - -void -print_e820_map(struct e820entry *map, int entries) -{ - struct e820entry *m; - - if (entries > 32) - entries = 32; - - for (m = map; m < &map[entries]; m++) { - printf("%08lx%08lx - %08lx%08lx ", - (unsigned long) (m->addr >> 32), - (unsigned long) (m->addr), - (unsigned long) ((m->addr+m->size) >> 32), - (unsigned long) ((m->addr+m->size))); - - switch (m->type) { - case E820_RAM: - printf("(RAM)\n"); break; - case E820_RESERVED: - printf("(Reserved)\n"); break; - case E820_ACPI: - printf("(ACPI Data)\n"); break; - case E820_NVS: - printf("(ACPI NVS)\n"); break; - default: - printf("(Type %ld)\n", m->type); break; - } - } -} - -void -dump_dtr(unsigned long addr, unsigned long size) -{ - unsigned long long entry; - unsigned long base, limit; - int i; - - for (i = 0; i < size; i += 8) { - entry = ((unsigned long long *) addr)[i >> 3]; - base = (((entry >> (56-24)) & 0xFF000000) | - ((entry >> (32-16)) & 0x00FF0000) | - ((entry >> ( 16)) & 0x0000FFFF)); - limit = (((entry >> (48-16)) & 0x000F0000) | - ((entry ) & 0x0000FFFF)); - if (entry & (1ULL << (23+32))) /* G */ - limit = (limit << 12) | 0xFFF; - - printf("[0x%x] = 0x%08x%08x, base 0x%lx, limit 0x%lx\n", i, - (unsigned)(entry >> 32), (unsigned)(entry), - base, limit); - } -} - -void -dump_vmx_context(struct vmx_assist_context *c) -{ - printf("eip 0x%lx, esp 0x%lx, eflags 0x%lx\n", - (long) c->eip, (long) c->esp, (long) c->eflags); - - printf("cr0 0x%lx, cr3 0x%lx, cr4 0x%lx\n", - (long)c->cr0, (long)c->cr3, (long)c->cr4); - - printf("idtr: limit 0x%lx, base 0x%lx\n", - (long)c->idtr_limit, (long)c->idtr_base); - - printf("gdtr: limit 0x%lx, base 0x%lx\n", - (long)c->gdtr_limit, (long)c->gdtr_base); - - printf("cs: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->cs_sel, (long)c->cs_limit, (long)c->cs_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->cs_arbytes.fields.seg_type, - c->cs_arbytes.fields.s, - c->cs_arbytes.fields.dpl, - c->cs_arbytes.fields.p, - c->cs_arbytes.fields.avl, - c->cs_arbytes.fields.default_ops_size, - c->cs_arbytes.fields.g, - c->cs_arbytes.fields.null_bit); - - printf("ds: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->ds_sel, (long)c->ds_limit, (long)c->ds_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->ds_arbytes.fields.seg_type, - c->ds_arbytes.fields.s, - c->ds_arbytes.fields.dpl, - c->ds_arbytes.fields.p, - c->ds_arbytes.fields.avl, - c->ds_arbytes.fields.default_ops_size, - c->ds_arbytes.fields.g, - c->ds_arbytes.fields.null_bit); - - printf("es: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->es_sel, (long)c->es_limit, (long)c->es_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->es_arbytes.fields.seg_type, - c->es_arbytes.fields.s, - c->es_arbytes.fields.dpl, - c->es_arbytes.fields.p, - c->es_arbytes.fields.avl, - c->es_arbytes.fields.default_ops_size, - c->es_arbytes.fields.g, - c->es_arbytes.fields.null_bit); - - printf("ss: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->ss_sel, (long)c->ss_limit, (long)c->ss_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->ss_arbytes.fields.seg_type, - c->ss_arbytes.fields.s, - c->ss_arbytes.fields.dpl, - c->ss_arbytes.fields.p, - c->ss_arbytes.fields.avl, - c->ss_arbytes.fields.default_ops_size, - c->ss_arbytes.fields.g, - c->ss_arbytes.fields.null_bit); - - printf("fs: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->fs_sel, (long)c->fs_limit, (long)c->fs_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->fs_arbytes.fields.seg_type, - c->fs_arbytes.fields.s, - c->fs_arbytes.fields.dpl, - c->fs_arbytes.fields.p, - c->fs_arbytes.fields.avl, - c->fs_arbytes.fields.default_ops_size, - c->fs_arbytes.fields.g, - c->fs_arbytes.fields.null_bit); - - printf("gs: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->gs_sel, (long)c->gs_limit, (long)c->gs_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->gs_arbytes.fields.seg_type, - c->gs_arbytes.fields.s, - c->gs_arbytes.fields.dpl, - c->gs_arbytes.fields.p, - c->gs_arbytes.fields.avl, - c->gs_arbytes.fields.default_ops_size, - c->gs_arbytes.fields.g, - c->gs_arbytes.fields.null_bit); - - printf("tr: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->tr_sel, (long)c->tr_limit, (long)c->tr_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->tr_arbytes.fields.seg_type, - c->tr_arbytes.fields.s, - c->tr_arbytes.fields.dpl, - c->tr_arbytes.fields.p, - c->tr_arbytes.fields.avl, - c->tr_arbytes.fields.default_ops_size, - c->tr_arbytes.fields.g, - c->tr_arbytes.fields.null_bit); - - printf("ldtr: sel 0x%lx, limit 0x%lx, base 0x%lx\n", - (long)c->ldtr_sel, (long)c->ldtr_limit, (long)c->ldtr_base); - printf("\ttype %d, s %d, dpl %d, p %d, avl %d, ops %d, g %d, nul %d\n", - c->ldtr_arbytes.fields.seg_type, - c->ldtr_arbytes.fields.s, - c->ldtr_arbytes.fields.dpl, - c->ldtr_arbytes.fields.p, - c->ldtr_arbytes.fields.avl, - c->ldtr_arbytes.fields.default_ops_size, - c->ldtr_arbytes.fields.g, - c->ldtr_arbytes.fields.null_bit); - - printf("GDTR <0x%lx,0x%lx>:\n", - (long)c->gdtr_base, (long)c->gdtr_limit); - dump_dtr(c->gdtr_base, c->gdtr_limit); -} -#endif /* DEBUG */ - -/* - * Lightweight printf that doesn't drag in everything under the sun. - */ -int -printf(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - _doprint(putchar, fmt, ap); - va_end(ap); - return 0; /* for gcc compat */ -} - -int -vprintf(const char *fmt, va_list ap) -{ - _doprint(putchar, fmt, ap); - return 0; /* for gcc compat */ -} - -void -panic(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - _doprint(putchar, fmt, ap); - putchar('\n'); - va_end(ap); - halt(); -} - -unsigned -strlen(const char *s) -{ - const char *q = s; - - while (*s++) - /* void */; - return s - q - 1; -} - -static void -putchar(int ch) -{ - outb(0xE9, ch); -} - -/* - * A stripped down version of doprint, - * but still powerful enough for most tasks. - */ -static void -_doprint(void (*put)(int), const char *fmt, va_list ap) -{ - register char *str, c; - int lflag, zflag, nflag; - char buffer[17]; - unsigned value; - int i, slen, pad; - - for ( ; *fmt != '\0'; fmt++) { - pad = zflag = nflag = lflag = 0; - if (*fmt == '%') { - c = *++fmt; - if (c == '-' || isdigit(c)) { - if (c == '-') { - nflag = 1; - c = *++fmt; - } - zflag = c == '0'; - for (pad = 0; isdigit(c); c = *++fmt) - pad = (pad * 10) + c - '0'; - } - if (c == 'l') { /* long extension */ - lflag = 1; - c = *++fmt; - } - if (c == 'd' || c == 'u' || c == 'o' || c == 'x') { - if (lflag) - value = va_arg(ap, unsigned); - else - value = (unsigned) va_arg(ap, unsigned int); - str = buffer; - printnum(str, value, - c == 'o' ? 8 : (c == 'x' ? 16 : 10)); - goto printn; - } else if (c == 'O' || c == 'D' || c == 'X') { - value = va_arg(ap, unsigned); - str = buffer; - printnum(str, value, - c == 'O' ? 8 : (c == 'X' ? 16 : 10)); - printn: - slen = strlen(str); - for (i = pad - slen; i > 0; i--) - put(zflag ? '0' : ' '); - while (*str) put(*str++); - } else if (c == 's') { - str = va_arg(ap, char *); - slen = strlen(str); - if (nflag == 0) - for (i = pad - slen; i > 0; i--) put(' '); - while (*str) put(*str++); - if (nflag) - for (i = pad - slen; i > 0; i--) put(' '); - } else if (c == 'c') - put(va_arg(ap, int)); - else - put(*fmt); - } else - put(*fmt); - } -} - -static char * -printnum(char *p, unsigned long num, int base) -{ - unsigned long n; - - if ((n = num/base) > 0) - p = printnum(p, n, base); - *p++ = "0123456789ABCDEF"[(int)(num % base)]; - *p = '\0'; - return p; -} - -void * -memset(void *s, int c, unsigned n) -{ - int t0, t1; - - __asm__ __volatile__ ("cld; rep; stosb" - : "=&c" (t0), "=&D" (t1) - : "a" (c), "1" (s), "0" (n) - : "memory"); - return s; -} - -void * -memcpy(void *dest, const void *src, unsigned n) -{ - int t0, t1, t2; - - __asm__ __volatile__( - "cld\n" - "rep; movsl\n" - "testb $2,%b4\n" - "je 1f\n" - "movsw\n" - "1: testb $1,%b4\n" - "je 2f\n" - "movsb\n" - "2:" - : "=&c" (t0), "=&D" (t1), "=&S" (t2) - : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src) - : "memory" - ); - return dest; -} - diff --git a/tools/firmware/vmxassist/util.h b/tools/firmware/vmxassist/util.h deleted file mode 100644 index 5ef3d69a02..0000000000 --- a/tools/firmware/vmxassist/util.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * util.h: Useful utility functions. - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#ifndef __UTIL_H__ -#define __UTIL_H__ - -#include -#include - -#define offsetof(type, member) ((unsigned) &((type *)0)->member) - -struct vmx_assist_context; - -#include "../hvmloader/e820.h" - -extern void cpuid_addr_value(uint64_t addr, uint64_t *value); -extern void hexdump(unsigned char *, int); -extern void dump_regs(struct regs *); -extern void dump_vmx_context(struct vmx_assist_context *); -extern void print_e820_map(struct e820entry *, int); -extern void dump_dtr(unsigned long, unsigned long); -extern void *memcpy(void *, const void *, unsigned); -extern void *memset(void *, int, unsigned); -extern int printf(const char *fmt, ...); -extern int vprintf(const char *fmt, va_list ap); -extern void panic(const char *format, ...); -extern void halt(void); - -#endif /* __UTIL_H__ */ diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c deleted file mode 100644 index d511ed4faa..0000000000 --- a/tools/firmware/vmxassist/vm86.c +++ /dev/null @@ -1,1992 +0,0 @@ -/* - * vm86.c: A vm86 emulator. The main purpose of this emulator is to do as - * little work as possible. - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005-2006, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#include "vm86.h" -#include "util.h" -#include "machine.h" - -#define HIGHMEM (1 << 20) /* 1MB */ -#define MASK16(v) ((v) & 0xFFFF) - -#define DATA32 0x0001 -#define ADDR32 0x0002 -#define SEG_CS 0x0004 -#define SEG_DS 0x0008 -#define SEG_ES 0x0010 -#define SEG_SS 0x0020 -#define SEG_FS 0x0040 -#define SEG_GS 0x0080 -#define REP 0x0100 - -static unsigned prev_eip = 0; -enum vm86_mode mode = 0; - -static struct regs saved_rm_regs; - -#ifdef DEBUG -int traceset = 0; - -char *states[] = { - "", - "", - "", - "" -}; - -static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; -#endif /* DEBUG */ - -#define PDE_PS (1 << 7) -#define PT_ENTRY_PRESENT 0x1 - -/* We only support access to <=4G physical memory due to 1:1 mapping */ -static uint64_t -guest_linear_to_phys(uint32_t base) -{ - uint32_t gcr3 = oldctx.cr3; - uint64_t l2_mfn; - uint64_t l1_mfn; - uint64_t l0_mfn; - - if (!(oldctx.cr0 & CR0_PG)) - return base; - - if (!(oldctx.cr4 & CR4_PAE)) { - l1_mfn = ((uint32_t *)(long)gcr3)[(base >> 22) & 0x3ff]; - if (!(l1_mfn & PT_ENTRY_PRESENT)) - panic("l2 entry not present\n"); - - if ((oldctx.cr4 & CR4_PSE) && (l1_mfn & PDE_PS)) { - l0_mfn = l1_mfn & 0xffc00000; - return l0_mfn + (base & 0x3fffff); - } - - l1_mfn &= 0xfffff000; - - l0_mfn = ((uint32_t *)(long)l1_mfn)[(base >> 12) & 0x3ff]; - if (!(l0_mfn & PT_ENTRY_PRESENT)) - panic("l1 entry not present\n"); - l0_mfn &= 0xfffff000; - - return l0_mfn + (base & 0xfff); - } else { - l2_mfn = ((uint64_t *)(long)gcr3)[(base >> 30) & 0x3]; - if (!(l2_mfn & PT_ENTRY_PRESENT)) - panic("l3 entry not present\n"); - l2_mfn &= 0xffffff000ULL; - - if (l2_mfn & 0xf00000000ULL) { - printf("l2 page above 4G\n"); - cpuid_addr_value(l2_mfn + 8 * ((base >> 21) & 0x1ff), &l1_mfn); - } else - l1_mfn = ((uint64_t *)(long)l2_mfn)[(base >> 21) & 0x1ff]; - if (!(l1_mfn & PT_ENTRY_PRESENT)) - panic("l2 entry not present\n"); - - if (l1_mfn & PDE_PS) { /* CR4.PSE is ignored in PAE mode */ - l0_mfn = l1_mfn & 0xfffe00000ULL; - return l0_mfn + (base & 0x1fffff); - } - - l1_mfn &= 0xffffff000ULL; - - if (l1_mfn & 0xf00000000ULL) { - printf("l1 page above 4G\n"); - cpuid_addr_value(l1_mfn + 8 * ((base >> 12) & 0x1ff), &l0_mfn); - } else - l0_mfn = ((uint64_t *)(long)l1_mfn)[(base >> 12) & 0x1ff]; - if (!(l0_mfn & PT_ENTRY_PRESENT)) - panic("l1 entry not present\n"); - - l0_mfn &= 0xffffff000ULL; - - return l0_mfn + (base & 0xfff); - } -} - -static unsigned -address(struct regs *regs, unsigned seg, unsigned off) -{ - uint64_t gdt_phys_base; - unsigned long long entry; - unsigned seg_base, seg_limit; - unsigned entry_low, entry_high; - - if (seg == 0) { - if (mode == VM86_REAL || mode == VM86_REAL_TO_PROTECTED) - return off; - else - panic("segment is zero, but not in real mode!\n"); - } - - if (mode == VM86_REAL || seg > oldctx.gdtr_limit || - (mode == VM86_REAL_TO_PROTECTED && regs->cs == seg)) - return ((seg & 0xFFFF) << 4) + off; - - gdt_phys_base = guest_linear_to_phys(oldctx.gdtr_base); - if (gdt_phys_base != (uint32_t)gdt_phys_base) { - printf("gdt base address above 4G\n"); - cpuid_addr_value(gdt_phys_base + 8 * (seg >> 3), &entry); - } else - entry = ((unsigned long long *)(long)gdt_phys_base)[seg >> 3]; - - entry_high = entry >> 32; - entry_low = entry & 0xFFFFFFFF; - - seg_base = (entry_high & 0xFF000000) | ((entry >> 16) & 0xFFFFFF); - seg_limit = (entry_high & 0xF0000) | (entry_low & 0xFFFF); - - if (entry_high & 0x8000 && - ((entry_high & 0x800000 && off >> 12 <= seg_limit) || - (!(entry_high & 0x800000) && off <= seg_limit))) - return seg_base + off; - - panic("should never reach here in function address():\n\t" - "entry=0x%08x%08x, mode=%d, seg=0x%08x, offset=0x%08x\n", - entry_high, entry_low, mode, seg, off); - - return 0; -} - -#ifdef DEBUG -void -trace(struct regs *regs, int adjust, char *fmt, ...) -{ - unsigned off = regs->eip - adjust; - va_list ap; - - if ((traceset & (1 << mode)) && - (mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) { - /* 16-bit, seg:off addressing */ - unsigned addr = address(regs, regs->cs, off); - printf("0x%08x: 0x%x:0x%04x ", addr, regs->cs, off); - printf("(%d) ", mode); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); - } - if ((traceset & (1 << mode)) && - (mode == VM86_PROTECTED_TO_REAL || mode == VM86_PROTECTED)) { - /* 16-bit, gdt addressing */ - unsigned addr = address(regs, regs->cs, off); - printf("0x%08x: 0x%x:0x%08x ", addr, regs->cs, off); - printf("(%d) ", mode); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); - } -} -#endif /* DEBUG */ - -static inline unsigned -read32(unsigned addr) -{ - return *(unsigned long *) addr; -} - -static inline unsigned -read16(unsigned addr) -{ - return *(unsigned short *) addr; -} - -static inline unsigned -read8(unsigned addr) -{ - return *(unsigned char *) addr; -} - -static inline void -write32(unsigned addr, unsigned value) -{ - *(unsigned long *) addr = value; -} - -static inline void -write16(unsigned addr, unsigned value) -{ - *(unsigned short *) addr = value; -} - -static inline void -write8(unsigned addr, unsigned value) -{ - *(unsigned char *) addr = value; -} - -static inline void -push32(struct regs *regs, unsigned value) -{ - regs->uesp -= 4; - write32(address(regs, regs->uss, MASK16(regs->uesp)), value); -} - -static inline void -push16(struct regs *regs, unsigned value) -{ - regs->uesp -= 2; - write16(address(regs, regs->uss, MASK16(regs->uesp)), value); -} - -static inline unsigned -pop32(struct regs *regs) -{ - unsigned value = read32(address(regs, regs->uss, MASK16(regs->uesp))); - regs->uesp += 4; - return value; -} - -static inline unsigned -pop16(struct regs *regs) -{ - unsigned value = read16(address(regs, regs->uss, MASK16(regs->uesp))); - regs->uesp += 2; - return value; -} - -static inline unsigned -fetch32(struct regs *regs) -{ - unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); - - regs->eip += 4; - return read32(addr); -} - -static inline unsigned -fetch16(struct regs *regs) -{ - unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); - - regs->eip += 2; - return read16(addr); -} - -static inline unsigned -fetch8(struct regs *regs) -{ - unsigned addr = address(regs, regs->cs, MASK16(regs->eip)); - - regs->eip++; - return read8(addr); -} - -static unsigned -getreg32(struct regs *regs, int r) -{ - switch (r & 7) { - case 0: return regs->eax; - case 1: return regs->ecx; - case 2: return regs->edx; - case 3: return regs->ebx; - case 4: return regs->uesp; - case 5: return regs->ebp; - case 6: return regs->esi; - case 7: return regs->edi; - } - return ~0; -} - -static unsigned -getreg16(struct regs *regs, int r) -{ - return MASK16(getreg32(regs, r)); -} - -static unsigned -getreg8(struct regs *regs, int r) -{ - switch (r & 7) { - case 0: return regs->eax & 0xFF; /* al */ - case 1: return regs->ecx & 0xFF; /* cl */ - case 2: return regs->edx & 0xFF; /* dl */ - case 3: return regs->ebx & 0xFF; /* bl */ - case 4: return (regs->eax >> 8) & 0xFF; /* ah */ - case 5: return (regs->ecx >> 8) & 0xFF; /* ch */ - case 6: return (regs->edx >> 8) & 0xFF; /* dh */ - case 7: return (regs->ebx >> 8) & 0xFF; /* bh */ - } - return ~0; -} - -static void -setreg32(struct regs *regs, int r, unsigned v) -{ - switch (r & 7) { - case 0: regs->eax = v; break; - case 1: regs->ecx = v; break; - case 2: regs->edx = v; break; - case 3: regs->ebx = v; break; - case 4: regs->uesp = v; break; - case 5: regs->ebp = v; break; - case 6: regs->esi = v; break; - case 7: regs->edi = v; break; - } -} - -static void -setreg16(struct regs *regs, int r, unsigned v) -{ - setreg32(regs, r, (getreg32(regs, r) & ~0xFFFF) | MASK16(v)); -} - -static void -setreg8(struct regs *regs, int r, unsigned v) -{ - v &= 0xFF; - switch (r & 7) { - case 0: regs->eax = (regs->eax & ~0xFF) | v; break; - case 1: regs->ecx = (regs->ecx & ~0xFF) | v; break; - case 2: regs->edx = (regs->edx & ~0xFF) | v; break; - case 3: regs->ebx = (regs->ebx & ~0xFF) | v; break; - case 4: regs->eax = (regs->eax & ~0xFF00) | (v << 8); break; - case 5: regs->ecx = (regs->ecx & ~0xFF00) | (v << 8); break; - case 6: regs->edx = (regs->edx & ~0xFF00) | (v << 8); break; - case 7: regs->ebx = (regs->ebx & ~0xFF00) | (v << 8); break; - } -} - -static unsigned -segment(unsigned prefix, struct regs *regs, unsigned seg) -{ - if (prefix & SEG_ES) - seg = regs->ves; - if (prefix & SEG_DS) - seg = regs->vds; - if (prefix & SEG_CS) - seg = regs->cs; - if (prefix & SEG_SS) - seg = regs->uss; - if (prefix & SEG_FS) - seg = regs->vfs; - if (prefix & SEG_GS) - seg = regs->vgs; - return seg; -} - -static unsigned -sib(struct regs *regs, int mod, unsigned byte) -{ - unsigned scale = (byte >> 6) & 3; - int index = (byte >> 3) & 7; - int base = byte & 7; - unsigned addr = 0; - - switch (mod) { - case 0: - if (base == 5) - addr = fetch32(regs); - else - addr = getreg32(regs, base); - break; - case 1: - addr = getreg32(regs, base) + (char) fetch8(regs); - break; - case 2: - addr = getreg32(regs, base) + fetch32(regs); - break; - } - - if (index != 4) - addr += getreg32(regs, index) << scale; - - return addr; -} - -/* - * Operand (modrm) decode - */ -static unsigned -operand(unsigned prefix, struct regs *regs, unsigned modrm) -{ - int mod, disp = 0, seg; - - seg = segment(prefix, regs, regs->vds); - - if (prefix & ADDR32) { /* 32-bit addressing */ - switch ((mod = (modrm >> 6) & 3)) { - case 0: - switch (modrm & 7) { - case 0: return address(regs, seg, regs->eax); - case 1: return address(regs, seg, regs->ecx); - case 2: return address(regs, seg, regs->edx); - case 3: return address(regs, seg, regs->ebx); - case 4: return address(regs, seg, - sib(regs, mod, fetch8(regs))); - case 5: return address(regs, seg, fetch32(regs)); - case 6: return address(regs, seg, regs->esi); - case 7: return address(regs, seg, regs->edi); - } - break; - case 1: - case 2: - if ((modrm & 7) != 4) { - if (mod == 1) - disp = (char) fetch8(regs); - else - disp = (int) fetch32(regs); - } - switch (modrm & 7) { - case 0: return address(regs, seg, regs->eax + disp); - case 1: return address(regs, seg, regs->ecx + disp); - case 2: return address(regs, seg, regs->edx + disp); - case 3: return address(regs, seg, regs->ebx + disp); - case 4: return address(regs, seg, - sib(regs, mod, fetch8(regs))); - case 5: return address(regs, seg, regs->ebp + disp); - case 6: return address(regs, seg, regs->esi + disp); - case 7: return address(regs, seg, regs->edi + disp); - } - break; - case 3: - return getreg32(regs, modrm); - } - } else { /* 16-bit addressing */ - switch ((mod = (modrm >> 6) & 3)) { - case 0: - switch (modrm & 7) { - case 0: return address(regs, seg, MASK16(regs->ebx) + - MASK16(regs->esi)); - case 1: return address(regs, seg, MASK16(regs->ebx) + - MASK16(regs->edi)); - case 2: return address(regs, seg, MASK16(regs->ebp) + - MASK16(regs->esi)); - case 3: return address(regs, seg, MASK16(regs->ebp) + - MASK16(regs->edi)); - case 4: return address(regs, seg, MASK16(regs->esi)); - case 5: return address(regs, seg, MASK16(regs->edi)); - case 6: return address(regs, seg, fetch16(regs)); - case 7: return address(regs, seg, MASK16(regs->ebx)); - } - break; - case 1: - case 2: - if (mod == 1) - disp = (char) fetch8(regs); - else - disp = (int) fetch16(regs); - switch (modrm & 7) { - case 0: return address(regs, seg, MASK16(regs->ebx) + - MASK16(regs->esi) + disp); - case 1: return address(regs, seg, MASK16(regs->ebx) + - MASK16(regs->edi) + disp); - case 2: return address(regs, seg, MASK16(regs->ebp) + - MASK16(regs->esi) + disp); - case 3: return address(regs, seg, MASK16(regs->ebp) + - MASK16(regs->edi) + disp); - case 4: return address(regs, seg, - MASK16(regs->esi) + disp); - case 5: return address(regs, seg, - MASK16(regs->edi) + disp); - case 6: return address(regs, seg, - MASK16(regs->ebp) + disp); - case 7: return address(regs, seg, - MASK16(regs->ebx) + disp); - } - break; - case 3: - return getreg16(regs, modrm); - } - } - - return 0; -} - -/* - * Load new IDT - */ -static int -lidt(struct regs *regs, unsigned prefix, unsigned modrm) -{ - unsigned eip = regs->eip - 3; - unsigned addr = operand(prefix, regs, modrm); - - oldctx.idtr_limit = ((struct dtr *) addr)->size; - if ((prefix & DATA32) == 0) - oldctx.idtr_base = ((struct dtr *) addr)->base & 0xFFFFFF; - else - oldctx.idtr_base = ((struct dtr *) addr)->base; - TRACE((regs, regs->eip - eip, "lidt 0x%x <%d, 0x%x>", - addr, oldctx.idtr_limit, oldctx.idtr_base)); - - return 1; -} - -/* - * Load new GDT - */ -static int -lgdt(struct regs *regs, unsigned prefix, unsigned modrm) -{ - unsigned eip = regs->eip - 3; - unsigned addr = operand(prefix, regs, modrm); - - oldctx.gdtr_limit = ((struct dtr *) addr)->size; - if ((prefix & DATA32) == 0) - oldctx.gdtr_base = ((struct dtr *) addr)->base & 0xFFFFFF; - else - oldctx.gdtr_base = ((struct dtr *) addr)->base; - TRACE((regs, regs->eip - eip, "lgdt 0x%x <%d, 0x%x>", - addr, oldctx.gdtr_limit, oldctx.gdtr_base)); - - return 1; -} - -/* - * Modify CR0 either through an lmsw instruction. - */ -static int -lmsw(struct regs *regs, unsigned prefix, unsigned modrm) -{ - unsigned eip = regs->eip - 3; - unsigned ax = operand(prefix, regs, modrm) & 0xF; - unsigned cr0 = (oldctx.cr0 & 0xFFFFFFF0) | ax; - - TRACE((regs, regs->eip - eip, "lmsw 0x%x", ax)); - oldctx.cr0 = cr0 | CR0_PE | CR0_NE; - if (cr0 & CR0_PE) - set_mode(regs, VM86_REAL_TO_PROTECTED); - - return 1; -} - -/* - * We need to handle moves that address memory beyond the 64KB segment - * limit that VM8086 mode enforces. - */ -static int -movr(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 1; - unsigned modrm = fetch8(regs); - unsigned addr = operand(prefix, regs, modrm); - unsigned val, r = (modrm >> 3) & 7; - - if ((modrm & 0xC0) == 0xC0) { - /* - * Emulate all guest instructions in protected to real mode. - */ - if (mode != VM86_PROTECTED_TO_REAL) - return 0; - } - - switch (opc) { - case 0x88: /* addr32 mov r8, r/m8 */ - val = getreg8(regs, r); - TRACE((regs, regs->eip - eip, - "movb %%e%s, *0x%x", rnames[r], addr)); - write8(addr, val); - return 1; - - case 0x8A: /* addr32 mov r/m8, r8 */ - TRACE((regs, regs->eip - eip, - "movb *0x%x, %%%s", addr, rnames[r])); - setreg8(regs, r, read8(addr)); - return 1; - - case 0x89: /* addr32 mov r16, r/m16 */ - val = getreg32(regs, r); - if ((modrm & 0xC0) == 0xC0) { - if (prefix & DATA32) - setreg32(regs, modrm & 7, val); - else - setreg16(regs, modrm & 7, MASK16(val)); - return 1; - } - - if (prefix & DATA32) { - TRACE((regs, regs->eip - eip, - "movl %%e%s, *0x%x", rnames[r], addr)); - write32(addr, val); - } else { - TRACE((regs, regs->eip - eip, - "movw %%%s, *0x%x", rnames[r], addr)); - write16(addr, MASK16(val)); - } - return 1; - - case 0x8B: /* mov r/m16, r16 */ - if ((modrm & 0xC0) == 0xC0) { - if (prefix & DATA32) - setreg32(regs, r, addr); - else - setreg16(regs, r, MASK16(addr)); - return 1; - } - - if (prefix & DATA32) { - TRACE((regs, regs->eip - eip, - "movl *0x%x, %%e%s", addr, rnames[r])); - setreg32(regs, r, read32(addr)); - } else { - TRACE((regs, regs->eip - eip, - "movw *0x%x, %%%s", addr, rnames[r])); - setreg16(regs, r, read16(addr)); - } - return 1; - - case 0xC6: /* addr32 movb $imm, r/m8 */ - if ((modrm >> 3) & 7) - return 0; - val = fetch8(regs); - write8(addr, val); - TRACE((regs, regs->eip - eip, "movb $0x%x, *0x%x", - val, addr)); - return 1; - } - return 0; -} - -/* - * We need to handle string moves that address memory beyond the 64KB segment - * limit that VM8086 mode enforces. - */ -static inline int -movs(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 1; - unsigned sseg = segment(prefix, regs, regs->vds); - unsigned dseg = regs->ves; - unsigned saddr, daddr; - unsigned count = 1; - int incr = ((regs->eflags & EFLAGS_DF) == 0) ? 1 : -1; - - saddr = address(regs, sseg, regs->esi); - daddr = address(regs, dseg, regs->edi); - - if ((prefix & REP) != 0) { - count = regs->ecx; - regs->ecx = 0; - } - - switch (opc) { - case 0xA4: /* movsb */ - regs->esi += (incr * count); - regs->edi += (incr * count); - - while (count-- != 0) { - write8(daddr, read8(saddr)); - daddr += incr; - saddr += incr; - } - TRACE((regs, regs->eip - eip, "movsb (%%esi),%%es:(%%edi)")); - break; - - case 0xA5: /* movsw */ - if ((prefix & DATA32) == 0) { - incr = 2 * incr; - regs->esi += (incr * count); - regs->edi += (incr * count); - - while (count-- != 0) { - write16(daddr, read16(saddr)); - daddr += incr; - saddr += incr; - } - } else { - incr = 4 * incr; - regs->esi += (incr * count); - regs->edi += (incr * count); - - while (count-- != 0) { - write32(daddr, read32(saddr)); - daddr += incr; - saddr += incr; - } - } - TRACE((regs, regs->eip - eip, "movsw %s(%%esi),%%es:(%%edi)")); - break; - } - - return 1; -} - -static inline int -lods(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 1; - unsigned seg = segment(prefix, regs, regs->vds); - unsigned addr = address(regs, seg, regs->esi); - unsigned count = 1; - int incr = ((regs->eflags & EFLAGS_DF) == 0) ? 1 : -1; - - if ((prefix & REP) != 0) { - count = regs->ecx; - regs->ecx = 0; - } - - switch (opc) { - case 0xAD: /* lodsw */ - if ((prefix & DATA32) == 0) { - incr = 2 * incr; - regs->esi += (incr * count); - while (count-- != 0) { - setreg16(regs, 0, read16(addr)); - addr += incr; - } - - TRACE((regs, regs->eip - eip, "lodsw (%%esi),%%ax")); - } else { - incr = 4 * incr; - regs->esi += (incr * count); - while (count-- != 0) { - setreg32(regs, 0, read32(addr)); - addr += incr; - } - TRACE((regs, regs->eip - eip, "lodsw (%%esi),%%eax")); - } - break; - } - return 1; -} -/* - * Move to and from a control register. - */ -static int -movcr(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 2; - unsigned modrm = fetch8(regs); - unsigned cr = (modrm >> 3) & 7; - - if ((modrm & 0xC0) != 0xC0) /* only registers */ - return 0; - - switch (opc) { - case 0x20: /* mov Rd, Cd */ - TRACE((regs, regs->eip - eip, "movl %%cr%d, %%eax", cr)); - switch (cr) { - case 0: - setreg32(regs, modrm, - oldctx.cr0 & ~(CR0_PE | CR0_NE)); - break; - case 2: - setreg32(regs, modrm, get_cr2()); - break; - case 3: - setreg32(regs, modrm, oldctx.cr3); - break; - case 4: - setreg32(regs, modrm, oldctx.cr4); - break; - } - break; - case 0x22: /* mov Cd, Rd */ - TRACE((regs, regs->eip - eip, "movl %%eax, %%cr%d", cr)); - switch (cr) { - case 0: - oldctx.cr0 = getreg32(regs, modrm) | (CR0_PE | CR0_NE); - if (getreg32(regs, modrm) & CR0_PE) - set_mode(regs, VM86_REAL_TO_PROTECTED); - else - set_mode(regs, VM86_REAL); - break; - case 3: - oldctx.cr3 = getreg32(regs, modrm); - break; - case 4: - oldctx.cr4 = getreg32(regs, modrm); - break; - } - break; - } - - return 1; -} - -static inline void set_eflags_ZF(unsigned mask, unsigned v1, struct regs *regs) -{ - if ((v1 & mask) == 0) - regs->eflags |= EFLAGS_ZF; - else - regs->eflags &= ~EFLAGS_ZF; -} - -static void set_eflags_add(unsigned hi_bit_mask, unsigned v1, unsigned v2, - unsigned result, struct regs *regs) -{ - int bit_count; - unsigned tmp; - unsigned full_mask; - unsigned nonsign_mask; - - /* Carry out of high order bit? */ - if ( v1 & v2 & hi_bit_mask ) - regs->eflags |= EFLAGS_CF; - else - regs->eflags &= ~EFLAGS_CF; - - /* Even parity in least significant byte? */ - tmp = result & 0xff; - for (bit_count = 0; tmp != 0; bit_count++) - tmp &= (tmp - 1); - - if (bit_count & 1) - regs->eflags &= ~EFLAGS_PF; - else - regs->eflags |= EFLAGS_PF; - - /* Carry out of least significant BCD digit? */ - if ( v1 & v2 & (1<<3) ) - regs->eflags |= EFLAGS_AF; - else - regs->eflags &= ~EFLAGS_AF; - - /* Result is zero? */ - full_mask = (hi_bit_mask - 1) | hi_bit_mask; - set_eflags_ZF(full_mask, result, regs); - - /* Sign of result? */ - if ( result & hi_bit_mask ) - regs->eflags |= EFLAGS_SF; - else - regs->eflags &= ~EFLAGS_SF; - - /* Carry out of highest non-sign bit? */ - nonsign_mask = (hi_bit_mask >> 1) & ~hi_bit_mask; - if ( v1 & v2 & hi_bit_mask ) - regs->eflags |= EFLAGS_OF; - else - regs->eflags &= ~EFLAGS_OF; - -} - -/* - * We need to handle cmp opcodes that address memory beyond the 64KB - * segment limit that VM8086 mode enforces. - */ -static int -cmp(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 1; - unsigned modrm = fetch8(regs); - unsigned addr = operand(prefix, regs, modrm); - unsigned diff, val, r = (modrm >> 3) & 7; - - if ((modrm & 0xC0) == 0xC0) /* no registers */ - return 0; - - switch (opc) { - case 0x39: /* addr32 cmp r16, r/m16 */ - val = getreg32(regs, r); - if (prefix & DATA32) { - diff = read32(addr) - val; - set_eflags_ZF(~0, diff, regs); - - TRACE((regs, regs->eip - eip, - "cmp %%e%s, *0x%x (0x%x)", - rnames[r], addr, diff)); - } else { - diff = read16(addr) - val; - set_eflags_ZF(0xFFFF, diff, regs); - - TRACE((regs, regs->eip - eip, - "cmp %%%s, *0x%x (0x%x)", - rnames[r], addr, diff)); - } - break; - - /* other cmp opcodes ... */ - } - return 1; -} - -/* - * We need to handle test opcodes that address memory beyond the 64KB - * segment limit that VM8086 mode enforces. - */ -static int -test(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 1; - unsigned modrm = fetch8(regs); - unsigned addr = operand(prefix, regs, modrm); - unsigned val, diff; - - if ((modrm & 0xC0) == 0xC0) /* no registers */ - return 0; - - switch (opc) { - case 0xF6: /* testb $imm, r/m8 */ - if ((modrm >> 3) & 7) - return 0; - val = fetch8(regs); - diff = read8(addr) & val; - set_eflags_ZF(0xFF, diff, regs); - - TRACE((regs, regs->eip - eip, "testb $0x%x, *0x%x (0x%x)", - val, addr, diff)); - break; - - /* other test opcodes ... */ - } - - return 1; -} - -/* - * We need to handle add opcodes that address memory beyond the 64KB - * segment limit that VM8086 mode enforces. - */ -static int -add(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 1; - unsigned modrm = fetch8(regs); - unsigned addr = operand(prefix, regs, modrm); - unsigned r = (modrm >> 3) & 7; - - unsigned val1 = 0; - unsigned val2 = 0; - unsigned result = 0; - unsigned hi_bit; - - if ((modrm & 0xC0) == 0xC0) /* no registers */ - return 0; - - switch (opc) { - case 0x00: /* addr32 add r8, r/m8 */ - val1 = getreg8(regs, r); - val2 = read8(addr); - result = val1 + val2; - write8(addr, result); - TRACE((regs, regs->eip - eip, - "addb %%e%s, *0x%x", rnames[r], addr)); - break; - - case 0x01: /* addr32 add r16, r/m16 */ - if (prefix & DATA32) { - val1 = getreg32(regs, r); - val2 = read32(addr); - result = val1 + val2; - write32(addr, result); - TRACE((regs, regs->eip - eip, - "addl %%e%s, *0x%x", rnames[r], addr)); - } else { - val1 = getreg16(regs, r); - val2 = read16(addr); - result = val1 + val2; - write16(addr, result); - TRACE((regs, regs->eip - eip, - "addw %%e%s, *0x%x", rnames[r], addr)); - } - break; - - case 0x03: /* addr32 add r/m16, r16 */ - if (prefix & DATA32) { - val1 = getreg32(regs, r); - val2 = read32(addr); - result = val1 + val2; - setreg32(regs, r, result); - TRACE((regs, regs->eip - eip, - "addl *0x%x, %%e%s", addr, rnames[r])); - } else { - val1 = getreg16(regs, r); - val2 = read16(addr); - result = val1 + val2; - setreg16(regs, r, result); - TRACE((regs, regs->eip - eip, - "addw *0x%x, %%%s", addr, rnames[r])); - } - break; - } - - if (opc == 0x00) - hi_bit = (1<<7); - else - hi_bit = (prefix & DATA32) ? (1<<31) : (1<<15); - set_eflags_add(hi_bit, val1, val2, result, regs); - - return 1; -} - -/* - * We need to handle pop opcodes that address memory beyond the 64KB - * segment limit that VM8086 mode enforces. - */ -static int -pop(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned eip = regs->eip - 1; - unsigned modrm = fetch8(regs); - unsigned addr = operand(prefix, regs, modrm); - - if ((modrm & 0xC0) == 0xC0) /* no registers */ - return 0; - - switch (opc) { - case 0x8F: /* pop r/m16 */ - if ((modrm >> 3) & 7) - return 0; - if (prefix & DATA32) - write32(addr, pop32(regs)); - else - write16(addr, pop16(regs)); - TRACE((regs, regs->eip - eip, "pop *0x%x", addr)); - break; - - /* other pop opcodes ... */ - } - - return 1; -} - -static int -mov_to_seg(struct regs *regs, unsigned prefix, unsigned opc) -{ - unsigned modrm = fetch8(regs); - - /* - * Emulate segment loads in: - * 1) real->protected mode. - * 2) protected->real mode. - */ - if (mode != VM86_REAL_TO_PROTECTED && - mode != VM86_PROTECTED_TO_REAL) - return 0; - - /* Register source only. */ - if ((modrm & 0xC0) != 0xC0) - goto fail; - - switch ((modrm & 0x38) >> 3) { - case 0: /* es */ - regs->ves = getreg16(regs, modrm); - if (mode == VM86_PROTECTED_TO_REAL) - return 1; - saved_rm_regs.ves = 0; - oldctx.es_sel = regs->ves; - return 1; - - /* case 1: cs */ - - case 2: /* ss */ - regs->uss = getreg16(regs, modrm); - if (mode == VM86_PROTECTED_TO_REAL) - return 1; - saved_rm_regs.uss = 0; - oldctx.ss_sel = regs->uss; - return 1; - case 3: /* ds */ - regs->vds = getreg16(regs, modrm); - if (mode == VM86_PROTECTED_TO_REAL) - return 1; - saved_rm_regs.vds = 0; - oldctx.ds_sel = regs->vds; - return 1; - case 4: /* fs */ - regs->vfs = getreg16(regs, modrm); - if (mode == VM86_PROTECTED_TO_REAL) - return 1; - saved_rm_regs.vfs = 0; - oldctx.fs_sel = regs->vfs; - return 1; - case 5: /* gs */ - regs->vgs = getreg16(regs, modrm); - if (mode == VM86_PROTECTED_TO_REAL) - return 1; - saved_rm_regs.vgs = 0; - oldctx.gs_sel = regs->vgs; - return 1; - } - - fail: - printf("%s:%d: missed opcode %02x %02x\n", - __FUNCTION__, __LINE__, opc, modrm); - return 0; -} - -/* - * Emulate a segment load in protected mode - */ -static int -load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes) -{ - uint64_t gdt_phys_base; - unsigned long long entry; - - /* protected mode: use seg as index into gdt */ - if (sel > oldctx.gdtr_limit) - return 0; - - if (sel == 0) { - arbytes->fields.null_bit = 1; - return 1; - } - - gdt_phys_base = guest_linear_to_phys(oldctx.gdtr_base); - if (gdt_phys_base != (uint32_t)gdt_phys_base) { - printf("gdt base address above 4G\n"); - cpuid_addr_value(gdt_phys_base + 8 * (sel >> 3), &entry); - } else - entry = ((unsigned long long *)(long)gdt_phys_base)[sel >> 3]; - - /* Check the P bit first */ - if (!((entry >> (15+32)) & 0x1) && sel != 0) - return 0; - - *base = (((entry >> (56-24)) & 0xFF000000) | - ((entry >> (32-16)) & 0x00FF0000) | - ((entry >> ( 16)) & 0x0000FFFF)); - *limit = (((entry >> (48-16)) & 0x000F0000) | - (entry & 0x0000FFFF)); - - arbytes->bytes = 0; - arbytes->fields.seg_type = (entry >> (8+32)) & 0xF; /* TYPE */ - arbytes->fields.s = (entry >> (12+32)) & 0x1; /* S */ - if (arbytes->fields.s) - arbytes->fields.seg_type |= 1; /* accessed */ - arbytes->fields.dpl = (entry >> (13+32)) & 0x3; /* DPL */ - arbytes->fields.p = (entry >> (15+32)) & 0x1; /* P */ - arbytes->fields.avl = (entry >> (20+32)) & 0x1; /* AVL */ - arbytes->fields.default_ops_size = (entry >> (22+32)) & 0x1; /* D */ - - if (entry & (1ULL << (23+32))) { /* G */ - arbytes->fields.g = 1; - *limit = (*limit << 12) | 0xFFF; - } - - return 1; -} - -/* - * Emulate a protected mode segment load, falling back to clearing it if - * the descriptor was invalid. - */ -static void -load_or_clear_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes) -{ - if (!load_seg(sel, base, limit, arbytes)) - load_seg(0, base, limit, arbytes); -} - -static unsigned char rm_irqbase[2]; - -/* - * Transition to protected mode - */ -static void -protected_mode(struct regs *regs) -{ - extern char stack_top[]; - - oldctx.rm_irqbase[0] = rm_irqbase[0]; - oldctx.rm_irqbase[1] = rm_irqbase[1]; - - regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM); - - oldctx.eip = regs->eip; - oldctx.esp = regs->uesp; - oldctx.eflags = regs->eflags; - - /* reload all segment registers */ - if (!load_seg(regs->cs, &oldctx.cs_base, - &oldctx.cs_limit, &oldctx.cs_arbytes)) - panic("Invalid %%cs=0x%x for protected mode\n", regs->cs); - oldctx.cs_sel = regs->cs; - - load_or_clear_seg(oldctx.es_sel, &oldctx.es_base, - &oldctx.es_limit, &oldctx.es_arbytes); - load_or_clear_seg(oldctx.ss_sel, &oldctx.ss_base, - &oldctx.ss_limit, &oldctx.ss_arbytes); - load_or_clear_seg(oldctx.ds_sel, &oldctx.ds_base, - &oldctx.ds_limit, &oldctx.ds_arbytes); - load_or_clear_seg(oldctx.fs_sel, &oldctx.fs_base, - &oldctx.fs_limit, &oldctx.fs_arbytes); - load_or_clear_seg(oldctx.gs_sel, &oldctx.gs_base, - &oldctx.gs_limit, &oldctx.gs_arbytes); - - /* initialize jump environment to warp back to protected mode */ - regs->uss = DATA_SELECTOR; - regs->uesp = (unsigned long)stack_top; - regs->cs = CODE_SELECTOR; - regs->eip = (unsigned long)switch_to_protected_mode; - - /* this should get us into 32-bit mode */ -} - -/* - * Start real-mode emulation - */ -static void -real_mode(struct regs *regs) -{ - regs->eflags |= EFLAGS_VM | 0x02; - - /* - * When we transition from protected to real-mode and we - * have not reloaded the segment descriptors yet, they are - * interpreted as if they were in protect mode. - * We emulate this behavior by assuming that these memory - * reference are below 1MB and set %ss, %ds, %es accordingly. - */ - if (regs->uss != 0) { - if (regs->uss >= HIGHMEM) - panic("%%ss 0x%lx higher than 1MB", regs->uss); - regs->uss = address(regs, regs->uss, 0) >> 4; - } else { - regs->uss = saved_rm_regs.uss; - } - if (regs->vds != 0) { - if (regs->vds >= HIGHMEM) - panic("%%ds 0x%lx higher than 1MB", regs->vds); - regs->vds = address(regs, regs->vds, 0) >> 4; - } else { - regs->vds = saved_rm_regs.vds; - } - if (regs->ves != 0) { - if (regs->ves >= HIGHMEM) - panic("%%es 0x%lx higher than 1MB", regs->ves); - regs->ves = address(regs, regs->ves, 0) >> 4; - } else { - regs->ves = saved_rm_regs.ves; - } - - /* this should get us into 16-bit mode */ -} - -/* - * This is the smarts of the emulator and handles the mode transitions. The - * emulator handles 4 different modes. 1) VM86_REAL: emulated real-mode, - * Just handle those instructions that are not supported under VM8086. - * 2) VM86_REAL_TO_PROTECTED: going from real-mode to protected mode. In - * this we single step through the instructions until we reload the - * new %cs (some OSes do a lot of computations before reloading %cs). 2) - * VM86_PROTECTED_TO_REAL when we are going from protected to real mode. In - * this case we emulate the instructions by hand. Finally, 4) VM86_PROTECTED - * when we transitioned to protected mode and we should abandon the - * emulator. No instructions are emulated when in VM86_PROTECTED mode. - */ -void -set_mode(struct regs *regs, enum vm86_mode newmode) -{ - switch (newmode) { - case VM86_REAL: - if (mode == VM86_PROTECTED_TO_REAL || - mode == VM86_REAL_TO_PROTECTED) { - regs->eflags &= ~EFLAGS_TF; - real_mode(regs); - } else if (mode != VM86_REAL) - panic("unexpected real mode transition"); - break; - - case VM86_REAL_TO_PROTECTED: - if (mode == VM86_REAL) { - regs->eflags |= EFLAGS_TF; - saved_rm_regs.vds = regs->vds; - saved_rm_regs.ves = regs->ves; - saved_rm_regs.vfs = regs->vfs; - saved_rm_regs.vgs = regs->vgs; - saved_rm_regs.uss = regs->uss; - oldctx.ds_sel = 0; - oldctx.es_sel = 0; - oldctx.fs_sel = 0; - oldctx.gs_sel = 0; - oldctx.ss_sel = 0; - } else if (mode != VM86_REAL_TO_PROTECTED) - panic("unexpected real-to-protected mode transition"); - break; - - case VM86_PROTECTED_TO_REAL: - if (mode != VM86_PROTECTED) - panic("unexpected protected-to-real mode transition"); - break; - - case VM86_PROTECTED: - if (mode != VM86_REAL_TO_PROTECTED) - panic("unexpected protected mode transition"); - protected_mode(regs); - break; - } - - mode = newmode; - if (mode != VM86_PROTECTED) - TRACE((regs, 0, states[mode])); -} - -static void -jmpl(struct regs *regs, int prefix) -{ - unsigned n = regs->eip; - unsigned cs, eip; - - eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs); - cs = fetch16(regs); - - TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); - - regs->cs = cs; - regs->eip = eip; - - if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ - set_mode(regs, VM86_PROTECTED); - else if (mode == VM86_PROTECTED_TO_REAL) /* jump to real mode */ - set_mode(regs, VM86_REAL); - else - panic("jmpl"); -} - -static void -jmpl_indirect(struct regs *regs, int prefix, unsigned modrm) -{ - unsigned n = regs->eip; - unsigned cs, eip; - unsigned addr; - - addr = operand(prefix, regs, modrm); - - eip = (prefix & DATA32) ? read32(addr) : read16(addr); - addr += (prefix & DATA32) ? 4 : 2; - cs = read16(addr); - - TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); - - regs->cs = cs; - regs->eip = eip; - - if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ - set_mode(regs, VM86_PROTECTED); - else if (mode == VM86_PROTECTED_TO_REAL) /* jump to real mode */ - set_mode(regs, VM86_REAL); - else - panic("jmpl"); -} - -static void -retl(struct regs *regs, int prefix) -{ - unsigned cs, eip; - - if (prefix & DATA32) { - eip = pop32(regs); - cs = MASK16(pop32(regs)); - } else { - eip = pop16(regs); - cs = pop16(regs); - } - - TRACE((regs, 1, "retl (to 0x%x:0x%x)", cs, eip)); - - regs->cs = cs; - regs->eip = eip; - - if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ - set_mode(regs, VM86_PROTECTED); - else if (mode == VM86_PROTECTED_TO_REAL) /* jump to real mode */ - set_mode(regs, VM86_REAL); - else - panic("retl"); -} - -static void -interrupt(struct regs *regs, int n) -{ - TRACE((regs, 0, "external interrupt %d", n)); - push16(regs, regs->eflags); - push16(regs, regs->cs); - push16(regs, regs->eip); - regs->eflags &= ~EFLAGS_IF; - regs->eip = read16(address(regs, 0, n * 4)); - regs->cs = read16(address(regs, 0, n * 4 + 2)); -} - -/* - * Most port I/O operations are passed unmodified. We do have to be - * careful and make sure the emulated program isn't remapping the - * interrupt vectors. The following simple state machine catches - * these attempts and rewrites them. - */ -static int -outbyte(struct regs *regs, unsigned prefix, unsigned opc) -{ - static char icw2[2] = { 0 }; - int al, port; - - switch (opc) { - case 0xE6: /* outb port, al */ - port = fetch8(regs); - break; - case 0xEE: /* outb (%dx), al */ - port = MASK16(regs->edx); - break; - default: - return 0; - } - - al = regs->eax & 0xFF; - - switch (port) { - case PIC_MASTER + PIC_CMD: - if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */ - icw2[0] = 1; - break; - case PIC_MASTER + PIC_IMR: - if (icw2[0]) { - icw2[0] = 0; - printf("Remapping master: ICW2 0x%x -> 0x%x\n", - al, NR_EXCEPTION_HANDLER); - rm_irqbase[0] = al; - al = NR_EXCEPTION_HANDLER; - } - break; - - case PIC_SLAVE + PIC_CMD: - if (al & (1 << 4)) /* A0=0,D4=1 -> ICW1 */ - icw2[1] = 1; - break; - case PIC_SLAVE + PIC_IMR: - if (icw2[1]) { - icw2[1] = 0; - printf("Remapping slave: ICW2 0x%x -> 0x%x\n", - al, NR_EXCEPTION_HANDLER+8); - rm_irqbase[1] = al; - al = NR_EXCEPTION_HANDLER+8; - } - break; - } - - outb(port, al); - return 1; -} - -static int -inbyte(struct regs *regs, unsigned prefix, unsigned opc) -{ - int port; - - switch (opc) { - case 0xE4: /* inb al, port */ - port = fetch8(regs); - break; - case 0xEC: /* inb al, (%dx) */ - port = MASK16(regs->edx); - break; - default: - return 0; - } - - regs->eax = (regs->eax & ~0xFF) | inb(port); - return 1; -} - -static void -pushrm(struct regs *regs, int prefix, unsigned modrm) -{ - unsigned n = regs->eip; - unsigned addr; - unsigned data; - - addr = operand(prefix, regs, modrm); - - if (prefix & DATA32) { - data = read32(addr); - push32(regs, data); - } else { - data = read16(addr); - push16(regs, data); - } - - TRACE((regs, (regs->eip - n) + 1, "push *0x%x", addr)); -} - -enum { OPC_INVALID, OPC_EMULATED }; - -#define rdmsr(msr,val1,val2) \ - __asm__ __volatile__( \ - "rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) - -#define wrmsr(msr,val1,val2) \ - __asm__ __volatile__( \ - "wrmsr" \ - : /* no outputs */ \ - : "c" (msr), "a" (val1), "d" (val2)) - -/* - * Emulate a single instruction, including all its prefixes. We only implement - * a small subset of the opcodes, and not all opcodes are implemented for each - * of the four modes we can operate in. - */ -static int -opcode(struct regs *regs) -{ - unsigned eip = regs->eip; - unsigned opc, modrm, disp; - unsigned prefix = 0; - - if (mode == VM86_PROTECTED_TO_REAL && - oldctx.cs_arbytes.fields.default_ops_size) { - prefix |= DATA32; - prefix |= ADDR32; - } - - for (;;) { - switch ((opc = fetch8(regs))) { - - case 0x00: /* addr32 add r8, r/m8 */ - case 0x01: /* addr32 add r16, r/m16 */ - case 0x03: /* addr32 add r/m16, r16 */ - if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) - goto invalid; - if ((prefix & ADDR32) == 0) - goto invalid; - if (!add(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0x07: /* pop %es */ - regs->ves = (prefix & DATA32) ? - pop32(regs) : pop16(regs); - TRACE((regs, regs->eip - eip, "pop %%es")); - if (mode == VM86_REAL_TO_PROTECTED) { - saved_rm_regs.ves = 0; - oldctx.es_sel = regs->ves; - } - return OPC_EMULATED; - - case 0x0F: /* two byte opcode */ - if (mode == VM86_PROTECTED) - goto invalid; - switch ((opc = fetch8(regs))) { - case 0x01: - switch (((modrm = fetch8(regs)) >> 3) & 7) { - case 0: /* sgdt */ - case 1: /* sidt */ - goto invalid; - case 2: /* lgdt */ - if (!lgdt(regs, prefix, modrm)) - goto invalid; - return OPC_EMULATED; - case 3: /* lidt */ - if (!lidt(regs, prefix, modrm)) - goto invalid; - return OPC_EMULATED; - case 4: /* smsw */ - goto invalid; - case 5: - goto invalid; - case 6: /* lmsw */ - if (!lmsw(regs, prefix, modrm)) - goto invalid; - return OPC_EMULATED; - case 7: /* invlpg */ - goto invalid; - } - break; - case 0x06: /* clts */ - oldctx.cr0 &= ~CR0_TS; - return OPC_EMULATED; - case 0x09: /* wbinvd */ - return OPC_EMULATED; - case 0x20: /* mov Rd, Cd (1h) */ - case 0x22: - if (!movcr(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - case 0x30: /* WRMSR */ - wrmsr(regs->ecx, regs->eax, regs->edx); - return OPC_EMULATED; - case 0x32: /* RDMSR */ - rdmsr(regs->ecx, regs->eax, regs->edx); - return OPC_EMULATED; - default: - goto invalid; - } - goto invalid; - - case 0x1F: /* pop %ds */ - regs->vds = (prefix & DATA32) ? - pop32(regs) : pop16(regs); - TRACE((regs, regs->eip - eip, "pop %%ds")); - if (mode == VM86_REAL_TO_PROTECTED) { - saved_rm_regs.vds = 0; - oldctx.ds_sel = regs->vds; - } - return OPC_EMULATED; - - case 0x26: - TRACE((regs, regs->eip - eip, "%%es:")); - prefix |= SEG_ES; - continue; - - case 0x2E: - TRACE((regs, regs->eip - eip, "%%cs:")); - prefix |= SEG_CS; - continue; - - case 0x36: - TRACE((regs, regs->eip - eip, "%%ss:")); - prefix |= SEG_SS; - continue; - - case 0x39: /* addr32 cmp r16, r/m16 */ - case 0x3B: /* addr32 cmp r/m16, r16 */ - if (mode == VM86_PROTECTED_TO_REAL || !(prefix & ADDR32)) - goto invalid; - if (!cmp(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0x3E: - TRACE((regs, regs->eip - eip, "%%ds:")); - prefix |= SEG_DS; - continue; - - case 0x64: - TRACE((regs, regs->eip - eip, "%%fs:")); - prefix |= SEG_FS; - continue; - - case 0x65: - TRACE((regs, regs->eip - eip, "%%gs:")); - prefix |= SEG_GS; - continue; - - case 0x66: - if (mode == VM86_PROTECTED_TO_REAL && - oldctx.cs_arbytes.fields.default_ops_size) { - TRACE((regs, regs->eip - eip, "data16")); - prefix &= ~DATA32; - } else { - TRACE((regs, regs->eip - eip, "data32")); - prefix |= DATA32; - } - continue; - - case 0x67: - if (mode == VM86_PROTECTED_TO_REAL && - oldctx.cs_arbytes.fields.default_ops_size) { - TRACE((regs, regs->eip - eip, "addr16")); - prefix &= ~ADDR32; - } else { - TRACE((regs, regs->eip - eip, "addr32")); - prefix |= ADDR32; - } - continue; - - case 0x88: /* addr32 mov r8, r/m8 */ - case 0x8A: /* addr32 mov r/m8, r8 */ - if (mode == VM86_PROTECTED_TO_REAL || !(prefix & ADDR32)) - goto invalid; - if (!movr(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0x89: /* mov r16, r/m16 */ - case 0x8B: /* mov r/m16, r16 */ - if (mode != VM86_PROTECTED_TO_REAL && !(prefix & ADDR32)) - goto invalid; - if (!movr(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0x8E: /* mov r16, sreg */ - if (!mov_to_seg(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0x8F: /* addr32 pop r/m16 */ - if (!(prefix & ADDR32)) - goto invalid; - if (!pop(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0x90: /* nop */ - TRACE((regs, regs->eip - eip, "nop")); - return OPC_EMULATED; - - case 0x9C: /* pushf */ - TRACE((regs, regs->eip - eip, "pushf")); - if (prefix & DATA32) - push32(regs, regs->eflags & ~EFLAGS_VM); - else - push16(regs, regs->eflags & ~EFLAGS_VM); - return OPC_EMULATED; - - case 0x9D: /* popf */ - TRACE((regs, regs->eip - eip, "popf")); - if (prefix & DATA32) - regs->eflags = pop32(regs); - else - regs->eflags = (regs->eflags & 0xFFFF0000L) | - pop16(regs); - regs->eflags |= EFLAGS_VM; - return OPC_EMULATED; - - case 0xA1: /* mov ax, r/m16 */ - { - int addr, data; - int seg = segment(prefix, regs, regs->vds); - int offset = prefix & ADDR32 ? fetch32(regs) : fetch16(regs); - - if (prefix & DATA32) { - addr = address(regs, seg, offset); - data = read32(addr); - setreg32(regs, 0, data); - } else { - addr = address(regs, seg, offset); - data = read16(addr); - setreg16(regs, 0, data); - } - TRACE((regs, regs->eip - eip, "mov *0x%x, %%ax", addr)); - return OPC_EMULATED; - } - - case 0xA4: /* movsb */ - case 0xA5: /* movsw */ - if ((prefix & ADDR32) == 0) - goto invalid; - if (!movs(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xAD: /* lodsw */ - if ((prefix & ADDR32) == 0) - goto invalid; - if (!lods(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xBB: /* mov bx, imm16 */ - { - int data; - if (prefix & DATA32) { - data = fetch32(regs); - setreg32(regs, 3, data); - } else { - data = fetch16(regs); - setreg16(regs, 3, data); - } - TRACE((regs, regs->eip - eip, "mov $0x%x, %%bx", data)); - return OPC_EMULATED; - } - - case 0xC6: /* addr32 movb $imm, r/m8 */ - if (!(prefix & ADDR32)) - goto invalid; - if (!movr(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xCB: /* retl */ - if (mode == VM86_REAL_TO_PROTECTED || - mode == VM86_PROTECTED_TO_REAL) { - retl(regs, prefix); - return OPC_INVALID; - } - goto invalid; - - case 0xCD: /* int $n */ - TRACE((regs, regs->eip - eip, "int")); - interrupt(regs, fetch8(regs)); - return OPC_EMULATED; - - case 0xCF: /* iret */ - if (prefix & DATA32) { - TRACE((regs, regs->eip - eip, "data32 iretd")); - regs->eip = pop32(regs); - regs->cs = pop32(regs); - regs->eflags = pop32(regs); - } else { - TRACE((regs, regs->eip - eip, "iret")); - regs->eip = pop16(regs); - regs->cs = pop16(regs); - regs->eflags = (regs->eflags & 0xFFFF0000L) | - pop16(regs); - } - return OPC_EMULATED; - - case 0xE4: /* inb al, port */ - if (!inbyte(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xE6: /* outb port, al */ - if (!outbyte(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xEA: /* jmpl */ - if (mode == VM86_REAL_TO_PROTECTED || - mode == VM86_PROTECTED_TO_REAL) { - jmpl(regs, prefix); - return OPC_INVALID; - } - goto invalid; - - case 0xFF: - { - unsigned modrm = fetch8(regs); - switch((modrm >> 3) & 7) { - case 5: /* jmpl (indirect) */ - if (mode == VM86_REAL_TO_PROTECTED || - mode == VM86_PROTECTED_TO_REAL) { - jmpl_indirect(regs, prefix, modrm); - return OPC_INVALID; - } - goto invalid; - - case 6: /* push r/m16 */ - pushrm(regs, prefix, modrm); - return OPC_EMULATED; - - default: - goto invalid; - } - } - - case 0xEB: /* short jump */ - if (mode == VM86_REAL_TO_PROTECTED || - mode == VM86_PROTECTED_TO_REAL) { - disp = (char) fetch8(regs); - TRACE((regs, 2, "jmp 0x%x", regs->eip + disp)); - regs->eip += disp; - return OPC_EMULATED; - } - goto invalid; - - case 0xEC: /* inb al, (%dx) */ - if (!inbyte(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xEE: /* outb (%dx), al */ - if (!outbyte(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xF0: /* lock */ - TRACE((regs, regs->eip - eip, "lock")); - continue; - - case 0xF4: /* hlt */ - TRACE((regs, regs->eip - eip, "hlt")); - /* Do something power-saving here! */ - return OPC_EMULATED; - - case 0xF3: /* rep/repe/repz */ - TRACE((regs, regs->eip - eip, "rep")); - prefix |= REP; - continue; - - case 0xF6: /* addr32 testb $imm, r/m8 */ - if (!(prefix & ADDR32)) - goto invalid; - if (!test(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; - - case 0xFA: /* cli */ - TRACE((regs, regs->eip - eip, "cli")); - regs->eflags &= ~EFLAGS_IF; - return OPC_EMULATED; - - case 0xFB: /* sti */ - TRACE((regs, regs->eip - eip, "sti")); - regs->eflags |= EFLAGS_IF; - return OPC_EMULATED; - - default: - goto invalid; - } - } - -invalid: - regs->eip = eip; - TRACE((regs, regs->eip - eip, "opc 0x%x", opc)); - return OPC_INVALID; -} - -void -emulate(struct regs *regs) -{ - unsigned flteip; - int nemul = 0; - unsigned ip; - - /* emulate as many instructions as possible */ - while (opcode(regs) != OPC_INVALID) - nemul++; - - /* detect the case where we are not making progress */ - if (nemul == 0 && prev_eip == regs->eip) { - flteip = address(regs, MASK16(regs->cs), regs->eip); - - printf("Undecoded sequence: \n"); - for (ip=flteip; ip < flteip+16; ip++) - printf("0x%02x ", read8(ip)); - printf("\n"); - - panic("Unknown opcode at %04x:%04x=0x%x", - MASK16(regs->cs), regs->eip, flteip); - } else - prev_eip = regs->eip; -} - -void -trap(int trapno, int errno, struct regs *regs) -{ - /* emulate device interrupts */ - if (trapno >= NR_EXCEPTION_HANDLER) { - int irq = trapno - NR_EXCEPTION_HANDLER; - if (irq < 8) - interrupt(regs, irq + 8); - else - interrupt(regs, 0x70 + (irq - 8)); - return; - } - - switch (trapno) { - case 1: /* Debug */ - if (regs->eflags & EFLAGS_VM) { - /* emulate any 8086 instructions */ - if (mode == VM86_REAL) - return; - if (mode != VM86_REAL_TO_PROTECTED) - panic("not in real-to-protected mode"); - emulate(regs); - return; - } - goto invalid; - - case 13: /* GPF */ - if (regs->eflags & EFLAGS_VM) { - /* emulate any 8086 instructions */ - if (mode == VM86_PROTECTED) - panic("unexpected protected mode"); - emulate(regs); - return; - } - goto invalid; - - default: - invalid: - printf("Trap (0x%x) while in %s mode\n", - trapno, regs->eflags & EFLAGS_VM ? "real" : "protected"); - if (trapno == 14) - printf("Page fault address 0x%x\n", get_cr2()); - dump_regs(regs); - halt(); - } -} diff --git a/tools/firmware/vmxassist/vm86.h b/tools/firmware/vmxassist/vm86.h deleted file mode 100644 index 2cf3c0f7a5..0000000000 --- a/tools/firmware/vmxassist/vm86.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * vm86.h: vm86 emulator definitions. - * - * Leendert van Doorn, leendert@watson.ibm.com - * Copyright (c) 2005, International Business Machines Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - */ -#ifndef __VM86_H__ -#define __VM86_H__ - -#ifndef __ASSEMBLY__ -#include -#endif - -#include - -#ifndef __ASSEMBLY__ - -struct regs { - unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax; - unsigned trapno, errno; - unsigned eip, cs, eflags, uesp, uss; - unsigned ves, vds, vfs, vgs; -}; - -enum vm86_mode { - VM86_REAL = 0, - VM86_REAL_TO_PROTECTED, - VM86_PROTECTED_TO_REAL, - VM86_PROTECTED -}; - -#ifdef DEBUG -#define TRACE(a) trace a -#else -#define TRACE(a) -#endif - -extern enum vm86_mode prevmode, mode; -extern struct vmx_assist_context oldctx; - -extern void emulate(struct regs *); -extern void dump_regs(struct regs *); -extern void trace(struct regs *, int, char *, ...); - -extern void set_mode(struct regs *, enum vm86_mode); -extern void switch_to_real_mode(void); -extern void switch_to_protected_mode(void); - -#endif /* __ASSEMBLY__ */ - -#endif /* __VM86_H__ */ diff --git a/tools/firmware/vmxassist/vmxassist.ld b/tools/firmware/vmxassist/vmxassist.ld deleted file mode 100644 index 088519b698..0000000000 --- a/tools/firmware/vmxassist/vmxassist.ld +++ /dev/null @@ -1,32 +0,0 @@ -/* - * vmxassist.ld - */ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -ENTRY(_start) - -SECTIONS -{ - _btext = .; - .text TEXTADDR : - { - *(.text) - *(.rodata) - *(.rodata.*) - } - _etext = .; - - _bdata = .; - .data : - { - *(.data) - } - _edata = .; - - _bbss = .; - .bss : - { - *(.bss) - } - _ebss = .; -} - -- cgit v1.2.3