[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] merge with xen-unstable.hg
# HG changeset patch # User Isaku Yamahata <yamahata@xxxxxxxxxxxxx> # Date 1230090754 -32400 # Node ID 07f26e047fbfef8d3be9ceb0c878d294fb9d945b # Parent 9837303a4708cf0bd558efb6676cef095f9c4406 # Parent e2f36d066b7b66a538bbe240d46f49bede51d9ed merge with xen-unstable.hg --- xen/arch/x86/cpu/mcheck/p4.c | 270 xen/arch/x86/cpu/mcheck/p6.c | 118 xen/arch/x86/rwlock.c | 28 xen/include/asm-x86/rwlock.h | 71 extras/mini-os/Makefile | 8 extras/mini-os/arch/x86/mm.c | 13 extras/mini-os/fs-front.c | 14 extras/mini-os/include/xenbus.h | 3 extras/mini-os/kernel.c | 26 extras/mini-os/xenbus/xenbus.c | 11 tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in | 2 tools/firmware/hvmloader/hvmloader.c | 24 tools/firmware/rombios/rombios.c | 4030 +++++----- tools/firmware/rombios/rombios.h | 70 tools/libxc/xc_dom_core.c | 1 tools/libxc/xc_dom_x86.c | 6 tools/libxc/xc_domain.c | 14 tools/libxc/xc_domain_restore.c | 16 tools/libxc/xc_domain_save.c | 26 tools/libxc/xc_pm.c | 138 tools/libxc/xc_private.h | 3 tools/libxc/xc_ptrace.c | 41 tools/libxc/xenctrl.h | 48 tools/libxc/xg_private.c | 1 tools/misc/xen-detect.c | 24 tools/misc/xenpm.c | 744 + tools/python/xen/lowlevel/acm/acm.c | 2 tools/python/xen/lowlevel/flask/flask.c | 1 tools/python/xen/lowlevel/xc/xc.c | 11 tools/python/xen/lowlevel/xs/xs.c | 17 tools/python/xen/xend/XendCheckpoint.py | 2 tools/python/xen/xend/XendConfig.py | 8 tools/python/xen/xend/XendDomainInfo.py | 9 tools/python/xen/xend/balloon.py | 36 tools/python/xen/xend/server/blkif.py | 13 tools/xcutils/xc_save.c | 12 tools/xenpmd/xenpmd.c | 6 tools/xenstat/xentop/xentop.c | 2 unmodified_drivers/linux-2.6/Makefile | 1 unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h | 2 unmodified_drivers/linux-2.6/overrides.mk | 1 unmodified_drivers/linux-2.6/scsifront/Kbuild | 6 unmodified_drivers/linux-2.6/scsifront/Makefile | 3 xen/arch/ia64/xen/cpufreq/cpufreq.c | 1 xen/arch/x86/Makefile | 1 xen/arch/x86/acpi/cpu_idle.c | 49 xen/arch/x86/acpi/cpufreq/cpufreq.c | 73 xen/arch/x86/acpi/cpufreq/powernow.c | 11 xen/arch/x86/apic.c | 33 xen/arch/x86/cpu/amd.c | 4 xen/arch/x86/cpu/intel.c | 4 xen/arch/x86/cpu/mcheck/Makefile | 3 xen/arch/x86/cpu/mcheck/amd_k8.c | 4 xen/arch/x86/cpu/mcheck/k7.c | 5 xen/arch/x86/cpu/mcheck/mce.c | 34 xen/arch/x86/cpu/mcheck/mce.h | 17 xen/arch/x86/cpu/mcheck/mce_intel.c | 632 + xen/arch/x86/cpu/mcheck/non-fatal.c | 25 xen/arch/x86/cpu/mcheck/p5.c | 1 xen/arch/x86/cpu/mcheck/x86_mca.h | 19 xen/arch/x86/domctl.c | 45 xen/arch/x86/hvm/hvm.c | 26 xen/arch/x86/hvm/svm/intr.c | 3 xen/arch/x86/hvm/vmx/entry.S | 14 xen/arch/x86/hvm/vmx/intr.c | 15 xen/arch/x86/hvm/vmx/realmode.c | 45 xen/arch/x86/hvm/vmx/vmcs.c | 61 xen/arch/x86/hvm/vmx/vmx.c | 304 xen/arch/x86/i8259.c | 1 xen/arch/x86/io_apic.c | 14 xen/arch/x86/irq.c | 67 xen/arch/x86/mm/shadow/common.c | 9 xen/arch/x86/mm/shadow/multi.c | 9 xen/arch/x86/msi.c | 215 xen/arch/x86/oprofile/nmi_int.c | 9 xen/arch/x86/physdev.c | 24 xen/arch/x86/platform_hypercall.c | 10 xen/arch/x86/setup.c | 8 xen/arch/x86/smpboot.c | 25 xen/arch/x86/time.c | 126 xen/arch/x86/traps.c | 20 xen/arch/x86/x86_32/asm-offsets.c | 4 xen/arch/x86/x86_64/asm-offsets.c | 6 xen/arch/x86/x86_64/compat/entry.S | 1 xen/arch/x86/x86_emulate/x86_emulate.h | 1 xen/common/domain.c | 35 xen/common/schedule.c | 46 xen/common/spinlock.c | 6 xen/common/sysctl.c | 25 xen/drivers/acpi/pmstat.c | 306 xen/drivers/cpufreq/Makefile | 1 xen/drivers/cpufreq/cpufreq.c | 48 xen/drivers/cpufreq/cpufreq_misc_governors.c | 158 xen/drivers/cpufreq/cpufreq_ondemand.c | 143 xen/drivers/passthrough/amd/pci_amd_iommu.c | 20 xen/drivers/passthrough/io.c | 35 xen/drivers/passthrough/iommu.c | 59 xen/drivers/passthrough/pci.c | 95 xen/drivers/passthrough/vtd/iommu.c | 292 xen/drivers/video/vesa.c | 18 xen/drivers/video/vga.c | 19 xen/include/acpi/cpufreq/cpufreq.h | 21 xen/include/asm-ia64/linux-xen/asm/spinlock.h | 2 xen/include/asm-x86/apicdef.h | 2 xen/include/asm-x86/config.h | 2 xen/include/asm-x86/cpufeature.h | 1 xen/include/asm-x86/hvm/hvm.h | 2 xen/include/asm-x86/hvm/trace.h | 1 xen/include/asm-x86/hvm/vcpu.h | 1 xen/include/asm-x86/hvm/vmx/vmcs.h | 16 xen/include/asm-x86/hvm/vmx/vmx.h | 1 xen/include/asm-x86/irq.h | 1 xen/include/asm-x86/mach-default/irq_vectors.h | 4 xen/include/asm-x86/msi.h | 9 xen/include/asm-x86/msr-index.h | 6 xen/include/asm-x86/perfc_defn.h | 3 xen/include/asm-x86/processor.h | 2 xen/include/asm-x86/spinlock.h | 54 xen/include/asm-x86/system.h | 22 xen/include/asm-x86/time.h | 2 xen/include/asm-x86/x86_32/system.h | 10 xen/include/asm-x86/x86_64/system.h | 10 xen/include/public/arch-x86/xen-mca.h | 15 xen/include/public/domctl.h | 12 xen/include/public/hvm/params.h | 5 xen/include/public/physdev.h | 9 xen/include/public/sysctl.h | 86 xen/include/public/trace.h | 1 xen/include/xen/iommu.h | 2 xen/include/xen/lib.h | 2 xen/include/xen/pci.h | 12 xen/include/xen/sched.h | 1 xen/include/xen/spinlock.h | 6 xen/include/xen/time.h | 1 134 files changed, 6259 insertions(+), 3231 deletions(-) diff -r 9837303a4708 -r 07f26e047fbf extras/mini-os/Makefile --- a/extras/mini-os/Makefile Wed Dec 24 12:50:57 2008 +0900 +++ b/extras/mini-os/Makefile Wed Dec 24 12:52:34 2008 +0900 @@ -93,8 +93,12 @@ endif $(OBJ_DIR)/$(TARGET)_app.o: $(APP_OBJS) app.lds $(LD) -r -d $(LDFLAGS) -\( $^ -\) $(APP_LDLIBS) --undefined main -o $@ -$(OBJ_DIR)/$(TARGET): links $(OBJS) $(OBJ_DIR)/$(TARGET)_app.o arch_lib - $(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(OBJ_DIR)/$(TARGET)_app.o $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o +ifneq ($(APP_OBJS),) +APP_O=$(OBJ_DIR)/$(TARGET)_app.o +endif + +$(OBJ_DIR)/$(TARGET): links $(OBJS) $(APP_O) arch_lib + $(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(APP_O) $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o $(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o $(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@ gzip -f -9 -c $@ >$@.gz diff -r 9837303a4708 -r 07f26e047fbf extras/mini-os/arch/x86/mm.c --- a/extras/mini-os/arch/x86/mm.c Wed Dec 24 12:50:57 2008 +0900 +++ b/extras/mini-os/arch/x86/mm.c Wed Dec 24 12:52:34 2008 +0900 @@ -420,7 +420,9 @@ static unsigned long demand_map_area_sta #define DEMAND_MAP_PAGES ((2ULL << 30) / PAGE_SIZE) #endif -#ifdef HAVE_LIBC +#ifndef HAVE_LIBC +#define HEAP_PAGES 0 +#else unsigned long heap, brk, heap_mapped, heap_end; #ifdef __x86_64__ #define HEAP_PAGES ((128ULL << 30) / PAGE_SIZE) @@ -591,7 +593,7 @@ void arch_init_mm(unsigned long* start_p void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p) { - unsigned long start_pfn, max_pfn; + unsigned long start_pfn, max_pfn, virt_pfns; printk(" _text: %p\n", &_text); printk(" _etext: %p\n", &_etext); @@ -604,7 +606,12 @@ void arch_init_mm(unsigned long* start_p start_pfn = PFN_UP(to_phys(start_info.pt_base)) + start_info.nr_pt_frames + 3; max_pfn = start_info.nr_pages; - + + /* We need room for demand mapping and heap, clip available memory */ + virt_pfns = DEMAND_MAP_PAGES + HEAP_PAGES; + if (max_pfn + virt_pfns + 1 < max_pfn) + max_pfn = -(virt_pfns + 1); + printk(" start_pfn: %lx\n", start_pfn); printk(" max_pfn: %lx\n", max_pfn); diff -r 9837303a4708 -r 07f26e047fbf extras/mini-os/fs-front.c --- a/extras/mini-os/fs-front.c Wed Dec 24 12:50:57 2008 +0900 +++ b/extras/mini-os/fs-front.c Wed Dec 24 12:52:34 2008 +0900 @@ -867,18 +867,6 @@ moretodo: if(more) goto moretodo; in_irq = 0; -} - -/* Small utility function to figure out our domain id */ -static domid_t get_self_id(void) -{ - char *dom_id; - domid_t ret; - - BUG_ON(xenbus_read(XBT_NIL, "domid", &dom_id)); - sscanf(dom_id, "%d", &ret); - - return ret; } static void alloc_request_table(struct fs_import *import) @@ -1066,7 +1054,7 @@ static int init_fs_import(struct fs_impo unmask_evtchn(import->local_port); - self_id = get_self_id(); + self_id = xenbus_get_self_id(); /* Write the frontend info to a node in our Xenbus */ sprintf(nodename, "/local/domain/%d/device/vfs/%d", self_id, import->import_id); diff -r 9837303a4708 -r 07f26e047fbf extras/mini-os/include/xenbus.h --- a/extras/mini-os/include/xenbus.h Wed Dec 24 12:50:57 2008 +0900 +++ b/extras/mini-os/include/xenbus.h Wed Dec 24 12:52:34 2008 +0900 @@ -91,6 +91,9 @@ char* xenbus_printf(xenbus_transaction_t const char* fmt, ...) __attribute__((__format__(printf, 4, 5))); +/* Utility function to figure out our domain id */ +domid_t xenbus_get_self_id(void); + /* Reset the XenBus system. */ void fini_xenbus(void); diff -r 9837303a4708 -r 07f26e047fbf extras/mini-os/kernel.c --- a/extras/mini-os/kernel.c Wed Dec 24 12:50:57 2008 +0900 +++ b/extras/mini-os/kernel.c Wed Dec 24 12:52:34 2008 +0900 @@ -434,25 +434,25 @@ static void kbdfront_thread(void *p) static struct pcifront_dev *pci_dev; +static void print_pcidev(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun) +{ + unsigned int vendor, device, rev, class; + + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x00, 2, &vendor); + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x02, 2, &device); + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x08, 1, &rev); + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x0a, 2, &class); + + printk("%04x:%02x:%02x.%02x %04x: %04x:%04x (rev %02x)\n", domain, bus, slot, fun, class, vendor, device, rev); +} + static void pcifront_thread(void *p) { - void print(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun) - { - unsigned int vendor, device, rev, class; - - pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x00, 2, &vendor); - pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x02, 2, &device); - pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x08, 1, &rev); - pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x0a, 2, &class); - - printk("%04x:%02x:%02x.%02x %04x: %04x:%04x (rev %02x)\n", domain, bus, slot, fun, class, vendor, device, rev); - } - pci_dev = init_pcifront(NULL); if (!pci_dev) return; printk("PCI devices:\n"); - pcifront_scan(pci_dev, print); + pcifront_scan(pci_dev, print_pcidev); } static void fs_thread(void *p) diff -r 9837303a4708 -r 07f26e047fbf extras/mini-os/xenbus/xenbus.c --- a/extras/mini-os/xenbus/xenbus.c Wed Dec 24 12:50:57 2008 +0900 +++ b/extras/mini-os/xenbus/xenbus.c Wed Dec 24 12:52:34 2008 +0900 @@ -666,6 +666,17 @@ char* xenbus_printf(xenbus_transaction_t return xenbus_write(xbt,fullpath,val); } +domid_t xenbus_get_self_id(void) +{ + char *dom_id; + domid_t ret; + + BUG_ON(xenbus_read(XBT_NIL, "domid", &dom_id)); + sscanf(dom_id, "%d", &ret); + + return ret; +} + static void do_ls_test(const char *pre) { char **dirs, *msg; diff -r 9837303a4708 -r 07f26e047fbf tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in --- a/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/debugger/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in Wed Dec 24 12:52:34 2008 +0900 @@ -83,7 +83,7 @@ READLINE_DEP = $$(READLINE_DIR) # -I. for config files. # -I${srcdir} for our headers. # -I$(srcdir)/../regformats for regdef.h. -INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) -I../../../../../libxc/ +INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) -I../../../../../libxc/ -I../../../../../include/ # M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS # from the config/ directory. diff -r 9837303a4708 -r 07f26e047fbf tools/firmware/hvmloader/hvmloader.c --- a/tools/firmware/hvmloader/hvmloader.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/firmware/hvmloader/hvmloader.c Wed Dec 24 12:52:34 2008 +0900 @@ -269,6 +269,11 @@ static void pci_setup(void) printf("pci dev %02x:%x INT%c->IRQ%u\n", devfn>>3, devfn&7, 'A'+pin-1, isa_irq); } + + /* Enable bus mastering. */ + cmd = pci_readw(devfn, PCI_COMMAND); + cmd |= PCI_COMMAND_MASTER; + pci_writew(devfn, PCI_COMMAND, cmd); } /* Assign iomem and ioport resources in descending order of size. */ @@ -534,6 +539,23 @@ static uint16_t init_xen_platform_io_bas } return bios_info->xen_pfiob; +} + +/* Set up an empty TSS area for virtual 8086 mode to use. + * The only important thing is that it musn't have any bits set + * in the interrupt redirection bitmap, so all zeros will do. */ +static void init_vm86_tss(void) +{ + uint32_t tss; + struct xen_hvm_param p; + + tss = e820_malloc(128, 128); + memset((char *)tss, 0, 128); + p.domid = DOMID_SELF; + p.index = HVM_PARAM_VM86_TSS; + p.value = tss; + hypercall_hvm_op(HVMOP_set_param, &p); + printf("vm86 TSS at %08x\n", tss); } int main(void) @@ -605,6 +627,8 @@ int main(void) printf("Loading ACPI ...\n"); acpi_build_tables(); } + + init_vm86_tss(); cmos_write_memory_size(); diff -r 9837303a4708 -r 07f26e047fbf tools/firmware/rombios/rombios.c --- a/tools/firmware/rombios/rombios.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/firmware/rombios/rombios.c Wed Dec 24 12:52:34 2008 +0900 @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $ +// $Id: rombios.c,v 1.221 2008/12/07 17:32:29 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2002 MandrakeSoft S.A. @@ -22,9 +22,9 @@ // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -// ROM BIOS for use with Bochs/Plex x86 emulation environment +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +// ROM BIOS for use with Bochs/Plex86/QEMU emulation environment #define uint8_t unsigned char #define uint16_t unsigned short @@ -81,10 +81,10 @@ // // NOTES for El-Torito Boot (cbbochs@xxxxxxx) // - CD-ROM booting is only available if ATA/ATAPI Driver is available -// - Current code is only able to boot mono-session cds +// - Current code is only able to boot mono-session cds // - Current code can not boot and emulate a hard-disk // the bios will panic otherwise -// - Current code also use memory in EBDA segement. +// - Current code also use memory in EBDA segement. // - I used cmos byte 0x3D to store extended information on boot-device // - Code has to be modified modified to handle multiple cdrom drives // - Here are the cdrom boot failure codes: @@ -102,13 +102,13 @@ // 12 : can not read cd - boot image // // ATA driver -// - EBDA segment. +// - EBDA segment. // I used memory starting at 0x121 in the segment // - the translation policy is defined in cmos regs 0x39 & 0x3a // // TODO : // -// int74 +// int74 // - needs to be reworked. Uses direct [bp] offsets. (?) // // int13: @@ -128,13 +128,13 @@ // - Implement remaining int13_cdemu functions (as defined by El-Torito specs) // - cdrom drive is hardcoded to ide 0 device 1 in several places. see "FIXME ElTorito Hardcoded" // - int13 Fix DL when emulating a cd. In that case DL is decremented before calling real int13. -// This is ok. But DL should be reincremented afterwards. +// This is ok. But DL should be reincremented afterwards. // - Fix all "FIXME ElTorito Various" // - should be able to boot any cdrom instead of the first one // // BCC Bug: find a generic way to handle the bug of #asm after an "if" (fixed in 0.16.7) -#define DEBUG_ROMBIOS 0 +#include "rombios.h" #define DEBUG_ATA 0 #define DEBUG_INT13_HD 0 @@ -159,7 +159,7 @@ #define BX_USE_ATADRV 1 #define BX_ELTORITO_BOOT 1 -#define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */ +#define BX_TCGBIOS 0 /* main switch for TCG BIOS ext. */ #define BX_MAX_ATA_INTERFACES 4 #define BX_MAX_ATA_DEVICES (BX_MAX_ATA_INTERFACES*2) @@ -183,14 +183,18 @@ #define EBDA_SIZE 1 // In KiB #define BASE_MEM_IN_K (640 - EBDA_SIZE) - // Define the application NAME -#ifdef HVMASSIST -# define BX_APPNAME "HVMAssist" -#elif PLEX86 -# define BX_APPNAME "Plex86" -#else -# define BX_APPNAME "Bochs" -#endif +/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */ +#define IPL_TABLE_OFFSET 0x0300 /* offset from EBDA */ +#define IPL_TABLE_ENTRIES 8 +#define IPL_COUNT_OFFSET 0x0380 /* u16: number of valid table entries */ +#define IPL_SEQUENCE_OFFSET 0x0382 /* u16: next boot device */ +#define IPL_BOOTFIRST_OFFSET 0x0384 /* u16: user selected device */ +#define IPL_SIZE 0xff +#define IPL_TYPE_FLOPPY 0x01 +#define IPL_TYPE_HARDDISK 0x02 +#define IPL_TYPE_CDROM 0x03 +#define IPL_TYPE_BEV 0x80 + // Sanity Checks #if BX_USE_ATADRV && BX_CPU<3 @@ -209,15 +213,10 @@ # error APM BIOS can only be used with 386+ cpu #endif -#ifndef BX_SMP_PROCESSORS -#define BX_SMP_PROCESSORS 1 -# warning BX_SMP_PROCESSORS not defined, defaulting to 1 -#endif - -#define PANIC_PORT 0x400 -#define PANIC_PORT2 0x401 -#define INFO_PORT 0x402 -#define DEBUG_PORT 0x403 +// define this if you want to make PCIBIOS working on a specific bridge only +// undef enables PCIBIOS when at least one PCI device is found +// i440FX is emulated by Bochs and QEMU +#define PCI_FIXED_HOST_BRIDGE 0x12378086 ;; i440FX PCI bridge // #20 is dec 20 // #$20 is hex 20 = 32 @@ -250,7 +249,7 @@ use16 286 MACRO HALT ;; the HALT macro is called with the line number of the HALT call. - ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex + ;; The line number is then sent to the PANIC_PORT, causing Bochs/Plex ;; to print a BX_PANIC message. This will normally halt the simulation ;; with a message such as "BIOS panic at rombios.c, line 4091". ;; However, users can choose to make panics non-fatal and continue. @@ -289,9 +288,9 @@ typedef unsigned long Bit32u; void memsetb(seg,offset,value,count); void memcpyb(dseg,doffset,sseg,soffset,count); void memcpyd(dseg,doffset,sseg,soffset,count); - + // memset of count bytes - void + void memsetb(seg,offset,value,count) Bit16u seg; Bit16u offset; @@ -301,14 +300,14 @@ typedef unsigned long Bit32u; ASM_START push bp mov bp, sp - + push ax push cx push es push di - + mov cx, 10[bp] ; count - cmp cx, #0x00 + test cx, cx je memsetb_end mov ax, 4[bp] ; segment mov es, ax @@ -318,19 +317,19 @@ typedef unsigned long Bit32u; cld rep stosb - + memsetb_end: pop di pop es pop cx pop ax - + pop bp ASM_END } - + // memcpy of count bytes - void + void memcpyb(dseg,doffset,sseg,soffset,count) Bit16u dseg; Bit16u doffset; @@ -341,16 +340,16 @@ typedef unsigned long Bit32u; ASM_START push bp mov bp, sp - + push ax push cx push es push di push ds push si - + mov cx, 12[bp] ; count - cmp cx, #0x0000 + test cx, cx je memcpyb_end mov ax, 4[bp] ; dsegment mov es, ax @@ -363,7 +362,7 @@ typedef unsigned long Bit32u; cld rep movsb - + memcpyb_end: pop si pop ds @@ -371,14 +370,13 @@ typedef unsigned long Bit32u; pop es pop cx pop ax - + pop bp ASM_END } -#if 0 // memcpy of count dword - void + void memcpyd(dseg,doffset,sseg,soffset,count) Bit16u dseg; Bit16u doffset; @@ -389,16 +387,16 @@ typedef unsigned long Bit32u; ASM_START push bp mov bp, sp - + push ax push cx push es push di push ds push si - + mov cx, 12[bp] ; count - cmp cx, #0x0000 + test cx, cx je memcpyd_end mov ax, 4[bp] ; dsegment mov es, ax @@ -411,7 +409,7 @@ typedef unsigned long Bit32u; cld rep movsd - + memcpyd_end: pop si pop ds @@ -419,16 +417,15 @@ typedef unsigned long Bit32u; pop es pop cx pop ax - + pop bp ASM_END } -#endif // read_dword and write_dword functions static Bit32u read_dword(); static void write_dword(); - + Bit32u read_dword(seg, offset) Bit16u seg; @@ -437,25 +434,24 @@ typedef unsigned long Bit32u; ASM_START push bp mov bp, sp - + push bx push ds mov ax, 4[bp] ; segment mov ds, ax mov bx, 6[bp] ; offset mov ax, [bx] - inc bx - inc bx + add bx, #2 mov dx, [bx] ;; ax = return value (word) ;; dx = return value (word) pop ds pop bx - + pop bp ASM_END } - + void write_dword(seg, offset, data) Bit16u seg; @@ -465,7 +461,7 @@ typedef unsigned long Bit32u; ASM_START push bp mov bp, sp - + push ax push bx push ds @@ -474,50 +470,49 @@ typedef unsigned long Bit32u; mov bx, 6[bp] ; offset mov ax, 8[bp] ; data word mov [bx], ax ; write data word - inc bx - inc bx + add bx, #2 mov ax, 10[bp] ; data word mov [bx], ax ; write data word pop ds pop bx pop ax - + pop bp ASM_END } - + // Bit32u (unsigned long) and long helper functions ASM_START - + ;; and function landl: landul: - SEG SS + SEG SS and ax,[di] - SEG SS + SEG SS and bx,2[di] ret - + ;; add function laddl: laddul: - SEG SS + SEG SS add ax,[di] - SEG SS + SEG SS adc bx,2[di] ret - + ;; cmp function lcmpl: lcmpul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx shr ebx, #16 SEG SS cmp eax, dword ptr [di] ret - + ;; sub function lsubl: lsubul: @@ -526,26 +521,26 @@ typedef unsigned long Bit32u; SEG SS sbb bx,2[di] ret - + ;; mul function lmull: lmulul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx SEG SS mul eax, dword ptr [di] mov ebx, eax shr ebx, #16 ret - + ;; dec function ldecl: ldecul: SEG SS dec dword ptr [bx] ret - + ;; or function lorl: lorul: @@ -554,31 +549,31 @@ typedef unsigned long Bit32u; SEG SS or bx,2[di] ret - + ;; inc function lincl: lincul: SEG SS inc dword ptr [bx] ret - + ;; tst function ltstl: ltstul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx shr ebx, #16 test eax, eax ret - + ;; sr function lsrul: mov cx,di jcxz lsr_exit and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx lsr_loop: shr eax, #1 loop lsr_loop @@ -586,7 +581,7 @@ typedef unsigned long Bit32u; shr ebx, #16 lsr_exit: ret - + ;; sl function lsll: lslul: @@ -594,15 +589,15 @@ typedef unsigned long Bit32u; jcxz lsl_exit and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx - lsl_loop: + or eax, ebx + lsl_loop: shl eax, #1 loop lsl_loop mov ebx, eax shr ebx, #16 lsl_exit: ret - + idiv_: cwd idiv bx @@ -616,7 +611,7 @@ typedef unsigned long Bit32u; ldivul: and eax, #0x0000FFFF shl ebx, #16 - add eax, ebx + or eax, ebx xor edx, edx SEG SS mov bx, 2[di] @@ -665,7 +660,7 @@ typedef struct { Bit8u revision; Bit8u checksum; } dpte_t; - + typedef struct { Bit8u iface; // ISA or PCI Bit16u iobase1; // IO Base 1 @@ -678,15 +673,15 @@ typedef struct { Bit8u device; // Detected type of attached devices (hd/cd/none) Bit8u removable; // Removable device flag Bit8u lock; // Locks for removable devices - // Bit8u lba_capable; // LBA capable flag - always yes for bochs devices - Bit8u mode; // transfert mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA + Bit8u mode; // transfer mode : PIO 16/32 bits - IRQ - ISADMA - PCIDMA Bit16u blksize; // block size Bit8u translation; // type of translation chs_t lchs; // Logical CHS chs_t pchs; // Physical CHS - Bit32u sectors; // Total sectors count + Bit32u sectors_low; // Total sectors count + Bit32u sectors_high; } ata_device_t; typedef struct { @@ -697,10 +692,10 @@ typedef struct { ata_device_t devices[BX_MAX_ATA_DEVICES]; // // map between (bios hd id - 0x80) and ata channels - Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES]; + Bit8u hdcount, hdidmap[BX_MAX_ATA_DEVICES]; // map between (bios cd id - 0xE0) and ata channels - Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES]; + Bit8u cdcount, cdidmap[BX_MAX_ATA_DEVICES]; // Buffer for DPTE table dpte_t dpte; @@ -710,9 +705,9 @@ typedef struct { Bit32u trsfbytes; } ata_t; - + #if BX_ELTORITO_BOOT - // ElTorito Device Emulation data + // ElTorito Device Emulation data typedef struct { Bit8u active; Bit8u media; @@ -723,20 +718,20 @@ typedef struct { Bit16u buffer_segment; Bit16u load_segment; Bit16u sector_count; - + // Virtual device chs_t vdevice; } cdemu_t; #endif // BX_ELTORITO_BOOT - + #include "32bitgateway.h" // for access to EBDA area - // The EBDA structure should conform to - // http://www.cybertrails.com/~fys/rombios.htm document + // The EBDA structure should conform to + // http://www.frontiernet.net/~fys/rombios.htm document // I made the ata and cdemu structs begin at 0x121 in the EBDA seg - // EBDA must be at most 768 bytes; it lives at 0x9fc00, and the boot - // device tables are at 0x9ff00 -- 0x9ffff + // EBDA must be at most 768 bytes; it lives at EBDA_SEG, and the boot + // device tables are at EBDA_SEG:IPL_TABLE_OFFSET typedef struct { unsigned char ebda_size; unsigned char cmos_shutdown_status; @@ -758,7 +753,7 @@ typedef struct { upcall_t upcall; } ebda_data_t; - + #define EBDA_CMOS_SHUTDOWN_STATUS_OFFSET 1 #define EbdaData ((ebda_data_t *) 0) @@ -772,7 +767,7 @@ typedef struct { Bit32u lba1; Bit32u lba2; } int13ext_t; - + #define Int13Ext ((int13ext_t *) 0) // Disk Physical Table definition @@ -798,7 +793,7 @@ typedef struct { Bit8u reserved3; Bit8u checksum; } dpt_t; - + #define Int13DPT ((dpt_t *) 0) #endif // BX_USE_ATADRV @@ -828,9 +823,9 @@ typedef struct { } r16; struct { Bit32u filler[4]; - Bit8u bl, bh; + Bit8u bl, bh; Bit16u filler1; - Bit8u dl, dh; + Bit8u dl, dh; Bit16u filler2; Bit8u cl, ch; Bit16u filler3; @@ -863,6 +858,14 @@ typedef struct { Bit16u cs; flags_t flags; } iret_addr_t; + +typedef struct { + Bit16u type; + Bit16u flags; + Bit32u vector; + Bit32u description; + Bit32u reserved; + } ipl_entry_t; @@ -903,8 +906,6 @@ static void int70_function(); static void int70_function(); static void int74_function(); static Bit16u get_CS(); -//static Bit16u get_DS(); -//static void set_DS(); static Bit16u get_SS(); static unsigned int enqueue_key(); static unsigned int dequeue_key(); @@ -923,7 +924,10 @@ static void keyboard_panic(); static void keyboard_panic(); static void shutdown_status_panic(); static void nmi_handler_msg(); - +static void delay_ticks(); +static void delay_ticks_and_check_for_keystroke(); + +static void interactive_bootkey(); static void print_bios_banner(); static void print_boot_device(); static void print_boot_failure(); @@ -957,33 +961,9 @@ Bit16u cdrom_boot(); #endif // BX_ELTORITO_BOOT -static char bios_cvs_version_string[] = "$Revision: 1.138 $"; -static char bios_date_string[] = "$Date: 2005/05/07 15:55:26 $"; - -static char CVSID[] = "$Id: rombios.c,v 1.138 2005/05/07 15:55:26 vruppert Exp $"; - -/* Offset to skip the CVS $Id: prefix */ -#define bios_version_string (CVSID + 4) - -#define BIOS_PRINTF_HALT 1 -#define BIOS_PRINTF_SCREEN 2 -#define BIOS_PRINTF_INFO 4 -#define BIOS_PRINTF_DEBUG 8 -#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO) -#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT) - -#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p) - -// Defines the output macros. -// BX_DEBUG goes to INFO port until we can easily choose debug info on a -// per-device basis. Debug info are sent only in debug mode -#if DEBUG_ROMBIOS -# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) -#else -# define BX_DEBUG(format, p...) -#endif -#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) -#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p) +static char bios_cvs_version_string[] = "$Revision: 1.221 $ $Date: 2008/12/07 17:32:29 $"; + +#define BIOS_COPYRIGHT_STRING "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team." #if DEBUG_ATA # define BX_DEBUG_ATA(a...) BX_DEBUG(a) @@ -1156,9 +1136,9 @@ static struct { { 0x5100, 0x5133, 0x7600, none, 0x20 }, /* 3 PgDn */ { 0x5200, 0x5230, none, none, 0x20 }, /* 0 Ins */ { 0x5300, 0x532e, none, none, 0x20 }, /* Del */ - { none, none, none, none, none }, /* ??? */ - { none, none, none, none, none }, /* ??? */ - { none, none, none, none, none }, /* ??? */ + { none, none, none, none, none }, + { none, none, none, none, none }, + { 0x565c, 0x567c, none, none, none }, /* \| */ { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */ { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */ }; @@ -1415,31 +1395,6 @@ ASM_END ASM_END } -// Bit16u -//get_DS() -//{ -//ASM_START -// mov ax, ds -//ASM_END -//} -// -// void -//set_DS(ds_selector) -// Bit16u ds_selector; -//{ -//ASM_START -// push bp -// mov bp, sp -// -// push ax -// mov ax, 4[bp] ; ds_selector -// mov ds, ax -// pop ax -// -// pop bp -//ASM_END -//} - Bit16u get_SS() { @@ -1455,7 +1410,7 @@ copy_e820_table() Bit8u nr_entries = read_byte(0x9000, 0x1e8); Bit32u base_mem; if (nr_entries > 32) - nr_entries = 32; + nr_entries = 32; write_word(0xe000, 0x8, nr_entries); memcpyb(0xe000, 0x10, 0x9000, 0x2d0, nr_entries * 0x14); /* Report the proper base memory size at address 0x0413: otherwise @@ -1563,7 +1518,7 @@ wrch(c) pop bp ASM_END } - + void send(action, c) Bit16u action; @@ -1619,14 +1574,121 @@ put_uint(action, val, width, neg) send(action, val - (nval * 10) + '0'); } + void +put_luint(action, val, width, neg) + Bit16u action; + unsigned long val; + short width; + bx_bool neg; +{ + unsigned long nval = val / 10; + if (nval) + put_luint(action, nval, width - 1, neg); + else { + while (--width > 0) send(action, ' '); + if (neg) send(action, '-'); + } + send(action, val - (nval * 10) + '0'); +} + +void put_str(action, segment, offset) + Bit16u action; + Bit16u segment; + Bit16u offset; +{ + Bit8u c; + + while (c = read_byte(segment, offset)) { + send(action, c); + offset++; + } +} + + void +delay_ticks(ticks) + Bit16u ticks; +{ + long ticks_to_wait, delta; + Bit32u prev_ticks, t; + + /* + * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock. + * We also have to be careful about interrupt storms. + */ +ASM_START + pushf + sti +ASM_END + ticks_to_wait = ticks; + prev_ticks = read_dword(0x0, 0x46c); + do + { +ASM_START + hlt +ASM_END + t = read_dword(0x0, 0x46c); + if (t > prev_ticks) + { + delta = t - prev_ticks; /* The temp var is required or bcc screws up. */ + ticks_to_wait -= delta; + } + else if (t < prev_ticks) + { + ticks_to_wait -= t; /* wrapped */ + } + + prev_ticks = t; + } while (ticks_to_wait > 0); +ASM_START + cli + popf +ASM_END +} + + Bit8u +check_for_keystroke() +{ +ASM_START + mov ax, #0x100 + int #0x16 + jz no_key + mov al, #1 + jmp done +no_key: + xor al, al +done: +ASM_END +} + + Bit8u +get_keystroke() +{ +ASM_START + mov ax, #0x0 + int #0x16 + xchg ah, al +ASM_END +} + + void +delay_ticks_and_check_for_keystroke(ticks, count) + Bit16u ticks, count; +{ + Bit16u i; + for (i = 1; i <= count; i++) { + delay_ticks(ticks); + if (check_for_keystroke()) + break; + } +} + //-------------------------------------------------------------------------- // bios_printf() -// A compact variable argument printf function which prints its output via -// an I/O port so that it can be logged by Bochs/Plex. -// Currently, only %x is supported (or %02x, %04x, etc). +// A compact variable argument printf function. // -// Supports %[format_width][format] -// where format can be d,x,c,s +// Supports %[format_width][length]format +// where format can be x,X,u,d,s,S,c +// and the optional length modifier is l (ell) //-------------------------------------------------------------------------- void bios_printf(action, s) @@ -1637,7 +1699,7 @@ bios_printf(action, s) bx_bool in_format; short i; Bit16u *arg_ptr; - Bit16u arg_seg, arg, nibble, shift_count, format_width; + Bit16u arg_seg, arg, nibble, hibyte, shift_count, format_width, hexadd; arg_ptr = &s; arg_seg = get_SS(); @@ -1664,16 +1726,48 @@ bios_printf(action, s) else { arg_ptr++; // increment to next arg arg = read_word(arg_seg, arg_ptr); - if (c == 'x') { + if (c == 'x' || c == 'X') { if (format_width == 0) format_width = 4; + if (c == 'x') + hexadd = 'a'; + else + hexadd = 'A'; for (i=format_width-1; i>=0; i--) { nibble = (arg >> (4 * i)) & 0x000f; - send (action, (nibble<=9)? (nibble+'0') : (nibble-10+'A')); + send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd)); } } else if (c == 'u') { put_uint(action, arg, format_width, 0); + } + else if (c == 'l') { + s++; + c = read_byte(get_CS(), s); /* is it ld,lx,lu? */ + arg_ptr++; /* increment to next arg */ + hibyte = read_word(arg_seg, arg_ptr); + if (c == 'd') { + if (hibyte & 0x8000) + put_luint(action, 0L-(((Bit32u) hibyte << 16) | arg), format_width-1, 1); + else + put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0); + } + else if (c == 'u') { + put_luint(action, ((Bit32u) hibyte << 16) | arg, format_width, 0); + } + else if (c == 'x' || c == 'X') + { + if (format_width == 0) + format_width = 8; + if (c == 'x') + hexadd = 'a'; + else + hexadd = 'A'; + for (i=format_width-1; i>=0; i--) { + nibble = ((((Bit32u) hibyte <<16) | arg) >> (4 * i)) & 0x000f; + send (action, (nibble<=9)? (nibble+'0') : (nibble-10+hexadd)); + } + } } else if (c == 'd') { if (arg & 0x8000) @@ -1682,7 +1776,13 @@ bios_printf(action, s) put_int(action, arg, format_width, 0); } else if (c == 's') { - bios_printf(action & (~BIOS_PRINTF_HALT), arg); + put_str(action, get_CS(), arg); + } + else if (c == 'S') { + hibyte = arg; + arg_ptr++; + arg = read_word(arg_seg, arg_ptr); + put_str(action, hibyte, arg); } else if (c == 'c') { send(action, arg); @@ -1699,7 +1799,7 @@ bios_printf(action, s) } if (action & BIOS_PRINTF_HALT) { - // freeze in a busy loop. + // freeze in a busy loop. ASM_START cli halt2_loop: @@ -1733,8 +1833,8 @@ keyboard_init() max = 0x2000; } } - - // Due to timer issues, and if the IPS setting is > 15000000, + + // Due to timer issues, and if the IPS setting is > 15000000, // the incoming keys might not be flushed here. That will // cause a panic a few lines below. See sourceforge bug report : // [ 642031 ] FATAL: Keyboard RESET error:993 @@ -1871,12 +1971,11 @@ keyboard_panic(status) keyboard_panic(status) Bit16u status; { - // If you're getting a 993 keyboard panic here, + // If you're getting a 993 keyboard panic here, // please see the comment in keyboard_init - + BX_PANIC("Keyboard error:%u\n",status); } - #define CMOS_SHUTDOWN_S3 0xFE //-------------------------------------------------------------------------- @@ -1932,6 +2031,11 @@ shutdown_status_panic(status) BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status); } +void s3_resume_panic() +{ + BX_PANIC("Returned from s3_resume.\n"); +} + //-------------------------------------------------------------------------- // print_bios_banner // displays a the bios version @@ -1939,108 +2043,197 @@ void void print_bios_banner() { - printf(BX_APPNAME" BIOS, %d cpu%s, ", BX_SMP_PROCESSORS, BX_SMP_PROCESSORS>1?"s":""); - printf("%s %s\n", bios_cvs_version_string, bios_date_string); + printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ", + BIOS_BUILD_DATE, bios_cvs_version_string); + printf( +#if BX_APM + "apmbios " +#endif +#if BX_PCIBIOS + "pcibios " +#endif +#if BX_ELTORITO_BOOT + "eltorito " +#endif +#if BX_ROMBIOS32 + "rombios32 " +#endif #if BX_TCGBIOS - printf("TCG-enabled BIOS.\n"); + "TCG-enabled" #endif - printf("\n"); + "\n\n"); } - //-------------------------------------------------------------------------- // BIOS Boot Specification 1.0.1 compatibility // -// Very basic support for the BIOS Boot Specification, which allows expansion -// ROMs to register themselves as boot devices, instead of just stealing the +// Very basic support for the BIOS Boot Specification, which allows expansion +// ROMs to register themselves as boot devices, instead of just stealing the // INT 19h boot vector. -// +// // This is a hack: to do it properly requires a proper PnP BIOS and we aren't -// one; we just lie to the option ROMs to make them behave correctly. -// We also don't support letting option ROMs register as bootable disk -// drives (BCVs), only as bootable devices (BEVs). +// one; we just lie to the option ROMs to make them behave correctly. +// We also don't support letting option ROMs register as bootable disk +// drives (BCVs), only as bootable devices (BEVs). // // http://www.phoenix.com/en/Customer+Services/White+Papers-Specs/pc+industry+specifications.htm //-------------------------------------------------------------------------- -/* 256 bytes at 0x9ff00 -- 0x9ffff is used for the IPL boot table. */ -#define IPL_SEG 0x9ff0 -#define IPL_TABLE_OFFSET 0x0000 -#define IPL_TABLE_ENTRIES 8 -#define IPL_COUNT_OFFSET 0x0080 /* u16: number of valid table entries */ -#define IPL_SEQUENCE_OFFSET 0x0082 /* u16: next boot device */ - -struct ipl_entry { - Bit16u type; - Bit16u flags; - Bit32u vector; - Bit32u description; - Bit32u reserved; -}; - -static void -init_boot_vectors() +static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"}; + +static void +init_boot_vectors() { - struct ipl_entry e; + ipl_entry_t e; Bit16u count = 0; Bit16u ss = get_SS(); + Bit16u ebda_seg = read_word(0x0040, 0x000E); /* Clear out the IPL table. */ - memsetb(IPL_SEG, IPL_TABLE_OFFSET, 0, 0xff); + memsetb(ebda_seg, IPL_TABLE_OFFSET, 0, IPL_SIZE); + + /* User selected device not set */ + write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF); /* Floppy drive */ - e.type = 1; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; - memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); + e.type = IPL_TYPE_FLOPPY; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; + memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); count++; /* First HDD */ - e.type = 2; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; - memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); + e.type = IPL_TYPE_HARDDISK; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; + memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); count++; #if BX_ELTORITO_BOOT /* CDROM */ - e.type = 3; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; - memcpyb(IPL_SEG, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); + e.type = IPL_TYPE_CDROM; e.flags = 0; e.vector = 0; e.description = 0; e.reserved = 0; + memcpyb(ebda_seg, IPL_TABLE_OFFSET + count * sizeof (e), ss, &e, sizeof (e)); count++; -#endif +#endif /* Remember how many devices we have */ - write_word(IPL_SEG, IPL_COUNT_OFFSET, count); + write_word(ebda_seg, IPL_COUNT_OFFSET, count); /* Not tried booting anything yet */ - write_word(IPL_SEG, IPL_SEQUENCE_OFFSET, 0xffff); + write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xffff); } static Bit8u get_boot_vector(i, e) -Bit16u i; struct ipl_entry *e; +Bit16u i; ipl_entry_t *e; { Bit16u count; Bit16u ss = get_SS(); + Bit16u ebda_seg = read_word(0x0040, 0x000E); /* Get the count of boot devices, and refuse to overrun the array */ - count = read_word(IPL_SEG, IPL_COUNT_OFFSET); + count = read_word(ebda_seg, IPL_COUNT_OFFSET); if (i >= count) return 0; /* OK to read this device */ - memcpyb(ss, e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e)); + memcpyb(ss, e, ebda_seg, IPL_TABLE_OFFSET + i * sizeof (*e), sizeof (*e)); return 1; } +#if BX_ELTORITO_BOOT + void +interactive_bootkey() +{ + ipl_entry_t e; + Bit16u count; + char description[33]; + Bit8u scan_code; + Bit8u i; + Bit16u ss = get_SS(); + Bit16u valid_choice = 0; + Bit16u ebda_seg = read_word(0x0040, 0x000E); + + while (check_for_keystroke()) + get_keystroke(); + + printf("\nPress F12 for boot menu.\n\n"); + + delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */ + if (check_for_keystroke()) + { + scan_code = get_keystroke(); + if (scan_code == 0x86) /* F12 */ + { + while (check_for_keystroke()) + get_keystroke(); + + printf("Select boot device:\n\n"); + + count = read_word(ebda_seg, IPL_COUNT_OFFSET); + for (i = 0; i < count; i++) + { + memcpyb(ss, &e, ebda_seg, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e)); + printf("%d. ", i+1); + switch(e.type) + { + case IPL_TYPE_FLOPPY: + case IPL_TYPE_HARDDISK: + case IPL_TYPE_CDROM: + printf("%s\n", drivetypes[e.type]); + break; + case IPL_TYPE_BEV: + printf("%s", drivetypes[4]); + if (e.description != 0) + { + memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32); + description[32] = 0; + printf(" [%S]", ss, description); + } + printf("\n"); + break; + } + } + + count++; + while (!valid_choice) { + scan_code = get_keystroke(); + if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */ + { + valid_choice = 1; + } + else if (scan_code <= count) + { + valid_choice = 1; + scan_code -= 1; + /* Set user selected device */ + write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, scan_code); + } + } + printf("\n"); + } + } +} +#endif // BX_ELTORITO_BOOT //-------------------------------------------------------------------------- // print_boot_device // displays the boot device //-------------------------------------------------------------------------- -static char drivetypes[][10]={"", "Floppy","Hard Disk","CD-Rom", "Network"}; - void -print_boot_device(type) +print_boot_device(e) + ipl_entry_t *e; +{ Bit16u type; -{ - /* NIC appears as type 0x80 */ - if (type == 0x80 ) type = 0x4; - if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n"); - printf("Booting from %s...\n", drivetypes[type]); + char description[33]; + Bit16u ss = get_SS(); + type = e->type; + /* NIC appears as type 0x80 */ + if (type == IPL_TYPE_BEV) type = 0x4; + if (type == 0 || type > 0x4) BX_PANIC("Bad drive type\n"); + printf("Booting from %s", drivetypes[type]); + /* print product string if BEV */ + if (type == 4 && e->description != 0) { + /* first 32 bytes are significant */ + memcpyb(ss, &description, (Bit16u)(e->description >> 16), (Bit16u)(e->description & 0xffff), 32); + /* terminate string */ + description[32] = 0; + printf(" [%S]", ss, description); + } + printf("...\n"); } //-------------------------------------------------------------------------- @@ -2051,17 +2244,17 @@ print_boot_failure(type, reason) print_boot_failure(type, reason) Bit16u type; Bit8u reason; { - if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n"); + if (type == 0 || type > 0x3) BX_PANIC("Bad drive type\n"); printf("Boot from %s failed", drivetypes[type]); if (type < 4) { /* Report the reason too */ - if (reason==0) - printf(": not a bootable disk"); - else - printf(": could not read the boot disk"); + if (reason==0) + printf(": not a bootable disk"); + else + printf(": could not read the boot disk"); } - printf("\n"); + printf("\n\n"); } //-------------------------------------------------------------------------- @@ -2073,218 +2266,9 @@ print_cdromboot_failure( code ) Bit16u code; { bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "CDROM boot failure code : %04x\n",code); - + return; } - -#define WAIT_HZ 18 -/** - * Check for keystroke. - * @returns True if keystroke available, False if not. - */ -Bit8u check_for_keystroke() -{ -ASM_START - mov ax, #0x100 - int #0x16 - jz no_key - mov al, #1 - jmp done -no_key: - xor al, al -done: -ASM_END -} - -/** - * Get keystroke. - * @returns BIOS scan code. - */ -Bit8u get_keystroke() -{ -ASM_START - mov ax, #0x0 - int #0x16 - xchg ah, al -ASM_END -} - -/** - * Waits (sleeps) for the given number of ticks. - * Checks for keystroke. - * - * @returns BIOS scan code if available, 0 if not. - * @param ticks Number of ticks to sleep. - * @param stop_on_key Whether to stop immediately upon keypress. - */ -Bit8u wait(ticks, stop_on_key) - Bit16u ticks; - Bit8u stop_on_key; -{ - long ticks_to_wait, delta; - Bit32u prev_ticks, t; - Bit8u scan_code = 0; - - /* - * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock. - * We also have to be careful about interrupt storms. - */ - ticks_to_wait = ticks; - prev_ticks = read_dword(0x0, 0x46c); - do - { - t = read_dword(0x0, 0x46c); - if (t > prev_ticks) - { - delta = t - prev_ticks; /* The temp var is required or bcc screws up. */ - ticks_to_wait -= delta; - } - else if (t < prev_ticks) - ticks_to_wait -= t; /* wrapped */ - prev_ticks = t; - - if (check_for_keystroke()) - { - scan_code = get_keystroke(); - bios_printf(BIOS_PRINTF_DEBUG, "Key pressed: %x\n", scan_code); - if (stop_on_key) - return scan_code; - } - } while (ticks_to_wait > 0); - return scan_code; -} - -static void clearscreen() { - /* Hide cursor, clear screen and move cursor to starting position */ -ASM_START - push bx - push cx - push dx - - mov ax, #0x100 - mov cx, #0x1000 - int #0x10 - - mov ax, #0x700 - mov bh, #7 - xor cx, cx - mov dx, #0x184f - int #0x10 - - mov ax, #0x200 - xor bx, bx - xor dx, dx - int #0x10 - - pop dx - pop cx - pop bx -ASM_END -} - -int bootmenu(selected) - int selected; -{ - Bit8u scode; - int max; - - /* get the number of boot devices */ - max = read_word(IPL_SEG, IPL_COUNT_OFFSET); - - for(;;) { - if (selected > max || selected < 1) selected = 1; - clearscreen(); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n\n\n\n\n\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " Select boot device\n\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 1. Floppy\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 2. Hard drive\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 3. CD-ROM\n"); - if (max == 4) - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 4. Network\n"); - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n Currently selected: %d\n", selected); - - do { - scode = wait(WAIT_HZ, 1); - } while (scode == 0); - switch(scode) { - case 0x02: - case 0x03: - case 0x04: - selected = scode - 1; - break; - case 0x05: - if (max == 4) - selected = scode -1 ; - else - scode = 0; - break; - case 0x48: - selected -= 1; - if (selected < 1) - selected = 1; - scode = 0; - break; - case 0x50: - selected += 1; - if (selected > max) - selected = max; - scode = 0; - break; - case 0x1c: - break; - default: - scode = 0; - break; - } - if (scode != 0) - break; - } - - switch (selected) { - case 1: - return 0x3D; - case 2: - return 0x3E; - case 3: - return 0x3F; - case 4: - return 0x58; - default: - return 0; - } -} - -void interactive_bootkey() -{ - Bit16u i; - Bit8u scan = 0; - - bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, - "\n\nPress F10 to select boot device.\n"); - - scan = wait(1, 0); - if (scan == 0x44) - scan = bootmenu(inb_cmos(0x3d) & 0x0f); - - /* set the default based on the keypress or menu */ - switch(scan) { - case 0x3D: - outb_cmos(0x3d, 0x01); - break; - case 0x3E: - outb_cmos(0x3d, 0x02); - break; - case 0x3F: - outb_cmos(0x3d, 0x03); - break; - case 0x58: - outb_cmos(0x3d, 0x04); - break; - default: - break; - } -} - void nmi_handler_msg() @@ -2304,7 +2288,7 @@ log_bios_start() #if BX_DEBUG_SERIAL outb(BX_DEBUG_PORT+UART_LCR, 0x03); /* setup for serial logging: 8N1 */ #endif - BX_INFO("%s\n", bios_version_string); + BX_INFO("%s\n", bios_cvs_version_string); } bx_bool @@ -2339,39 +2323,35 @@ debugger_off() outb(0xfedc, 0x00); } -void +int s3_resume() { Bit32u s3_wakeup_vector; - Bit16u s3_wakeup_ip, s3_wakeup_cs; - Bit8u cmos_shutdown_status; - + Bit8u s3_resume_flag; + + s3_resume_flag = read_byte(0x40, 0xb0); +#ifdef HVMASSIST + s3_wakeup_vector = get_s3_waking_vector(); +#else + s3_wakeup_vector = read_dword(0x40, 0xb2); +#endif + + BX_INFO("S3 resume called %x 0x%lx\n", s3_resume_flag, s3_wakeup_vector); + if (s3_resume_flag != CMOS_SHUTDOWN_S3 || !s3_wakeup_vector) + return 0; + + write_byte(0x40, 0xb0, 0); + + /* setup wakeup vector */ + write_word(0x40, 0xb6, (s3_wakeup_vector & 0xF)); /* IP */ + write_word(0x40, 0xb8, (s3_wakeup_vector >> 4)); /* CS */ + + BX_INFO("S3 resume jump to %x:%x\n", (s3_wakeup_vector >> 4), + (s3_wakeup_vector & 0xF)); ASM_START - push ds - push ax - mov ax, #EBDA_SEG - mov ds, ax - mov al, [EBDA_CMOS_SHUTDOWN_STATUS_OFFSET] - mov .s3_resume.cmos_shutdown_status[bp], al - pop ax - pop ds + jmpf [0x04b6] ASM_END - - if (cmos_shutdown_status != CMOS_SHUTDOWN_S3) - return; - - s3_wakeup_vector = get_s3_waking_vector(); - if (!s3_wakeup_vector) - return; - - s3_wakeup_ip = s3_wakeup_vector & 0xF; - s3_wakeup_cs = s3_wakeup_vector >> 4; - -ASM_START - push .s3_resume.s3_wakeup_cs[bp] - push .s3_resume.s3_wakeup_ip[bp] - retf -ASM_END + return 1; } #if BX_USE_ATADRV @@ -2421,6 +2401,7 @@ ASM_END // bits 7-4 of the device/head (CB_DH) reg #define ATA_CB_DH_DEV0 0xa0 // select device 0 #define ATA_CB_DH_DEV1 0xb0 // select device 1 +#define ATA_CB_DH_LBA 0x40 // use LBA // status reg (CB_STAT and CB_ASTAT) bits #define ATA_CB_STAT_BSY 0x80 // busy @@ -2470,6 +2451,7 @@ ASM_END #define ATA_CMD_READ_SECTORS 0x20 #define ATA_CMD_READ_VERIFY_SECTORS 0x40 #define ATA_CMD_RECALIBRATE 0x10 +#define ATA_CMD_REQUEST_SENSE 0x03 #define ATA_CMD_SEEK 0x70 #define ATA_CMD_SET_FEATURES 0xEF #define ATA_CMD_SET_MULTIPLE_MODE 0xC6 @@ -2514,7 +2496,7 @@ ASM_END #define ATA_DATA_NO 0x00 #define ATA_DATA_IN 0x01 #define ATA_DATA_OUT 0x02 - + // --------------------------------------------------------------------------- // ATA/ATAPI driver : initialization // --------------------------------------------------------------------------- @@ -2523,7 +2505,7 @@ void ata_init( ) Bit16u ebda_seg=read_word(0x0040,0x000E); Bit8u channel, device; - // Channels info init. + // Channels info init. for (channel=0; channel<BX_MAX_ATA_INTERFACES; channel++) { write_byte(ebda_seg,&EbdaData->ata.channels[channel].iface,ATA_IFACE_NONE); write_word(ebda_seg,&EbdaData->ata.channels[channel].iobase1,0x0); @@ -2531,7 +2513,7 @@ void ata_init( ) write_byte(ebda_seg,&EbdaData->ata.channels[channel].irq,0); } - // Devices info init. + // Devices info init. for (device=0; device<BX_MAX_ATA_DEVICES; device++) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE); write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_NONE); @@ -2546,11 +2528,12 @@ void ata_init( ) write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads,0); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders,0); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt,0); - - write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors,0L); + + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low,0L); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high,0L); } - // hdidmap and cdidmap init. + // hdidmap and cdidmap init. for (device=0; device<BX_MAX_ATA_DEVICES; device++) { write_byte(ebda_seg,&EbdaData->ata.hdidmap[device],BX_MAX_ATA_DEVICES); write_byte(ebda_seg,&EbdaData->ata.cdidmap[device],BX_MAX_ATA_DEVICES); @@ -2558,6 +2541,58 @@ void ata_init( ) write_byte(ebda_seg,&EbdaData->ata.hdcount,0); write_byte(ebda_seg,&EbdaData->ata.cdcount,0); +} + +#define TIMEOUT 0 +#define BSY 1 +#define NOT_BSY 2 +#define NOT_BSY_DRQ 3 +#define NOT_BSY_NOT_DRQ 4 +#define NOT_BSY_RDY 5 + +#define IDE_TIMEOUT 32000u //32 seconds max for IDE ops + +int await_ide(); +static int await_ide(when_done,base,timeout) + Bit8u when_done; + Bit16u base; + Bit16u timeout; +{ + Bit32u time=0,last=0; + Bit16u status; + Bit8u result; + status = inb(base + ATA_CB_STAT); // for the times you're supposed to throw one away + for(;;) { + status = inb(base+ATA_CB_STAT); + time++; + if (when_done == BSY) + result = status & ATA_CB_STAT_BSY; + else if (when_done == NOT_BSY) + result = !(status & ATA_CB_STAT_BSY); + else if (when_done == NOT_BSY_DRQ) + result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_DRQ); + else if (when_done == NOT_BSY_NOT_DRQ) + result = !(status & ATA_CB_STAT_BSY) && !(status & ATA_CB_STAT_DRQ); + else if (when_done == NOT_BSY_RDY) + result = !(status & ATA_CB_STAT_BSY) && (status & ATA_CB_STAT_RDY); + else if (when_done == TIMEOUT) + result = 0; + + if (result) return 0; + if (time>>16 != last) // mod 2048 each 16 ms + { + last = time >>16; + BX_DEBUG_ATA("await_ide: (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout); + } + if (status & ATA_CB_STAT_ERR) + { + BX_DEBUG_ATA("await_ide: ERROR (TIMEOUT,BSY,!BSY,!BSY_DRQ,!BSY_!DRQ,!BSY_RDY) %d time= %ld timeout= %d\n",when_done,time>>11, timeout); + return -1; + } + if ((timeout == 0) || ((time>>11) > timeout)) break; + } + BX_INFO("IDE time out\n"); + return -1; } // --------------------------------------------------------------------------- @@ -2600,7 +2635,7 @@ void ata_detect( ) // Device detection hdcount=cdcount=0; - + for(device=0; device<BX_MAX_ATA_DEVICES; device++) { Bit16u iobase1, iobase2; Bit8u channel, slave, shift; @@ -2630,33 +2665,34 @@ void ata_detect( ) if ( (sc == 0x55) && (sn == 0xaa) ) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_UNKNOWN); - + // reset the channel - ata_reset (device); - + ata_reset(device); + // check for ATA or ATAPI outb(iobase1+ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0); sc = inb(iobase1+ATA_CB_SC); sn = inb(iobase1+ATA_CB_SN); - if ( (sc==0x01) && (sn==0x01) ) { + if ((sc==0x01) && (sn==0x01)) { cl = inb(iobase1+ATA_CB_CL); ch = inb(iobase1+ATA_CB_CH); st = inb(iobase1+ATA_CB_STAT); - if ( (cl==0x14) && (ch==0xeb) ) { + if ((cl==0x14) && (ch==0xeb)) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATAPI); - } - else if ( (cl==0x00) && (ch==0x00) && (st!=0x00) ) { + } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) { write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_ATA); - } + } else if ((cl==0xff) && (ch==0xff)) { + write_byte(ebda_seg,&EbdaData->ata.devices[device].type,ATA_TYPE_NONE); } } + } type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type); - - // Now we send a IDENTIFY command to ATA device + + // Now we send a IDENTIFY command to ATA device if(type == ATA_TYPE_ATA) { - Bit32u sectors; + Bit32u sectors_low, sectors_high; Bit16u cylinders, heads, spt, blksize; Bit8u translation, removable, mode; @@ -2667,21 +2703,26 @@ void ata_detect( ) write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD); write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16); - if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, get_SS(),buffer) !=0 ) + if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) !=0 ) BX_PANIC("ata-detect: Failed to detect ATA device\n"); removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; -#ifndef NO_PIO32 +#ifndef NO_PIO32 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; #endif - blksize = read_word(get_SS(),buffer+10); - + cylinders = read_word(get_SS(),buffer+(1*2)); // word 1 heads = read_word(get_SS(),buffer+(3*2)); // word 3 spt = read_word(get_SS(),buffer+(6*2)); // word 6 - sectors = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61 + if (read_word(get_SS(),buffer+(83*2)) & (1 << 10)) { // word 83 - lba48 support + sectors_low = read_dword(get_SS(),buffer+(100*2)); // word 100 and word 101 + sectors_high = read_dword(get_SS(),buffer+(102*2)); // word 102 and word 103 + } else { + sectors_low = read_dword(get_SS(),buffer+(60*2)); // word 60 and word 61 + sectors_high = 0; + } write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_HD); write_byte(ebda_seg,&EbdaData->ata.devices[device].removable, removable); @@ -2690,7 +2731,8 @@ void ata_detect( ) write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.heads, heads); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.cylinders, cylinders); write_word(ebda_seg,&EbdaData->ata.devices[device].pchs.spt, spt); - write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors, sectors); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors_low); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high, sectors_high); BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt); translation = inb_cmos(0x39 + channel/2); @@ -2718,14 +2760,14 @@ void ata_detect( ) break; case ATA_TRANSLATION_LBA: spt = 63; - sectors /= 63; - heads = sectors / 1024; + sectors_low /= 63; + heads = sectors_low / 1024; if (heads>128) heads = 255; else if (heads>64) heads = 128; else if (heads>32) heads = 64; else if (heads>16) heads = 32; else heads=16; - cylinders = sectors / heads; + cylinders = sectors_low / heads; break; case ATA_TRANSLATION_RECHS: // Take care not to overflow @@ -2752,15 +2794,15 @@ void ata_detect( ) write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.heads, heads); write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.cylinders, cylinders); write_word(ebda_seg,&EbdaData->ata.devices[device].lchs.spt, spt); - - // fill hdidmap + + // fill hdidmap write_byte(ebda_seg,&EbdaData->ata.hdidmap[hdcount], device); hdcount++; } - + // Now we send a IDENTIFY command to ATAPI device if(type == ATA_TYPE_ATAPI) { - + Bit8u type, removable, mode; Bit16u blksize; @@ -2771,12 +2813,12 @@ void ata_detect( ) write_byte(ebda_seg,&EbdaData->ata.devices[device].device,ATA_DEVICE_CDROM); write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, ATA_MODE_PIO16); - if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, get_SS(),buffer) != 0) + if (ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET, 1, 0, 0, 0, 0L, 0L, get_SS(),buffer) != 0) BX_PANIC("ata-detect: Failed to detect ATAPI device\n"); type = read_byte(get_SS(),buffer+1) & 0x1f; removable = (read_byte(get_SS(),buffer+0) & 0x80) ? 1 : 0; -#ifndef NO_PIO32 +#ifndef NO_PIO32 mode = read_byte(get_SS(),buffer+96) ? ATA_MODE_PIO32 : ATA_MODE_PIO16; #endif blksize = 2048; @@ -2786,24 +2828,24 @@ void ata_detect( ) write_byte(ebda_seg,&EbdaData->ata.devices[device].mode, mode); write_word(ebda_seg,&EbdaData->ata.devices[device].blksize, blksize); - // fill cdidmap + // fill cdidmap write_byte(ebda_seg,&EbdaData->ata.cdidmap[cdcount], device); cdcount++; } - + { Bit32u sizeinmb; Bit16u ataversion; Bit8u c, i, version, model[41]; - + switch (type) { case ATA_TYPE_ATA: - sizeinmb = read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors); - sizeinmb >>= 11; + sizeinmb = (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_high) << 21) + | (read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low) >> 11); case ATA_TYPE_ATAPI: // Read ATA/ATAPI version ataversion=((Bit16u)(read_byte(get_SS(),buffer+161))<<8)|read_byte(get_SS(),buffer+160); - for(version=15;version>0;version--) { + for(version=15;version>0;version--) { if((ataversion&(1<<version))!=0) break; } @@ -2812,7 +2854,7 @@ void ata_detect( ) for(i=0;i<20;i++){ write_byte(get_SS(),model+(i*2),read_byte(get_SS(),buffer+(i*2)+54+1)); write_byte(get_SS(),model+(i*2)+1,read_byte(get_SS(),buffer+(i*2)+54)); - } + } // Reformat write_byte(get_SS(),model+40,0x00); @@ -2820,7 +2862,13 @@ void ata_detect( ) if(read_byte(get_SS(),model+i)==0x20) write_byte(get_SS(),model+i,0x00); else break; + } + if (i>36) { + write_byte(get_SS(),model+36,0x00); + for(i=35;i>32;i--){ + write_byte(get_SS(),model+i,0x2E); } + } break; } @@ -2828,10 +2876,10 @@ void ata_detect( ) case ATA_TYPE_ATA: printf("ata%d %s: ",channel,slave?" slave":"master"); i=0; while(c=read_byte(get_SS(),model+i++)) printf("%c",c); - if (sizeinmb < 1UL<<16) - printf(" ATA-%d Hard-Disk (%04u MBytes)\n",version,(Bit16u)sizeinmb); - else - printf(" ATA-%d Hard-Disk (%04u GBytes)\n",version,(Bit16u)(sizeinmb>>10)); + if (sizeinmb < (1UL<<16)) + printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (Bit16u)sizeinmb); + else + printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (Bit16u)(sizeinmb>>10)); break; case ATA_TYPE_ATAPI: printf("ata%d %s: ",channel,slave?" slave":"master"); @@ -2852,17 +2900,17 @@ void ata_detect( ) write_byte(ebda_seg,&EbdaData->ata.hdcount, hdcount); write_byte(ebda_seg,&EbdaData->ata.cdcount, cdcount); write_byte(0x40,0x75, hdcount); - + printf("\n"); // FIXME : should use bios=cmos|auto|disable bits // FIXME : should know about translation bits - // FIXME : move hard_drive_post here - + // FIXME : move hard_drive_post here + } // --------------------------------------------------------------------------- -// ATA/ATAPI driver : software reset +// ATA/ATAPI driver : software reset // --------------------------------------------------------------------------- // ATA-3 // 8.2.1 Software reset - Device 0 @@ -2872,7 +2920,8 @@ Bit16u device; { Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u iobase1, iobase2; - Bit8u channel, slave, sn, sc; + Bit8u channel, slave, sn, sc; + Bit8u type; Bit16u max; channel = device / 2; @@ -2887,16 +2936,13 @@ Bit16u device; outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST); // 8.2.1 (b) -- wait for BSY - max=0xff; - while(--max>0) { - Bit8u status = inb(iobase1+ATA_CB_STAT); - if ((status & ATA_CB_STAT_BSY) != 0) break; - } + await_ide(BSY, iobase1, 20); // 8.2.1 (f) -- clear SRST outb(iobase2+ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); - if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_NONE) { + type=read_byte(ebda_seg,&EbdaData->ata.devices[device].type); + if (type != ATA_TYPE_NONE) { // 8.2.1 (g) -- check for sc==sn==0x01 // select device @@ -2905,21 +2951,14 @@ Bit16u device; sn = inb(iobase1+ATA_CB_SN); if ( (sc==0x01) && (sn==0x01) ) { + if (type == ATA_TYPE_ATA) //ATA + await_ide(NOT_BSY_RDY, iobase1, IDE_TIMEOUT); + else //ATAPI + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); + } // 8.2.1 (h) -- wait for not BSY - max=0xff; - while(--max>0) { - Bit8u status = inb(iobase1+ATA_CB_STAT); - if ((status & ATA_CB_STAT_BSY) == 0) break; - } - } - } - -// 8.2.1 (i) -- wait for DRDY - max=0xfff; - while(--max>0) { - Bit8u status = inb(iobase1+ATA_CB_STAT); - if ((status & ATA_CB_STAT_RDY) != 0) break; + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); } // Enable interrupts @@ -2927,7 +2966,7 @@ Bit16u device; } // --------------------------------------------------------------------------- -// ATA/ATAPI driver : execute a non data command +// ATA/ATAPI driver : execute a non data command // --------------------------------------------------------------------------- Bit16u ata_cmd_non_data() @@ -2945,9 +2984,9 @@ Bit16u ata_cmd_non_data() // 5 : more sectors to read/verify // 6 : no sectors left to write // 7 : more sectors to write -Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba, segment, offset) +Bit16u ata_cmd_data_in(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset) Bit16u device, command, count, cylinder, head, sector, segment, offset; -Bit32u lba; +Bit32u lba_low, lba_high; { Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u iobase1, iobase2, blksize; @@ -2976,22 +3015,20 @@ Bit32u lba; // sector will be 0 only on lba access. Convert to lba-chs if (sector == 0) { - if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) { + if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) { outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff); - outb(iobase1 + ATA_CB_SN, lba >> 24); - outb(iobase1 + ATA_CB_CL, 0); - outb(iobase1 + ATA_CB_CH, 0); + outb(iobase1 + ATA_CB_SN, lba_low >> 24); + outb(iobase1 + ATA_CB_CL, lba_high & 0xff); + outb(iobase1 + ATA_CB_CH, lba_high >> 8); command |= 0x04; count &= (1UL << 8) - 1; - lba &= (1UL << 24) - 1; + lba_low &= (1UL << 24) - 1; } - sector = (Bit16u) (lba & 0x000000ffL); - lba >>= 8; - cylinder = (Bit16u) (lba & 0x0000ffffL); - lba >>= 16; - head = ((Bit16u) (lba & 0x0000000fL)) | 0x40; - } + sector = (Bit16u) (lba_low & 0x000000ffL); + cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL); + head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA; + } outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, count); @@ -3001,10 +3038,8 @@ Bit32u lba; outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head ); outb(iobase1 + ATA_CB_CMD, command); - while (1) { - status = inb(iobase1 + ATA_CB_STAT); - if ( !(status & ATA_CB_STAT_BSY) ) break; - } + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_data_in : read error\n"); @@ -3025,12 +3060,12 @@ ASM_START ASM_START push bp mov bp, sp - mov di, _ata_cmd_data_in.offset + 2[bp] - mov ax, _ata_cmd_data_in.segment + 2[bp] - mov cx, _ata_cmd_data_in.blksize + 2[bp] + mov di, _ata_cmd_data_in.offset + 2[bp] + mov ax, _ata_cmd_data_in.segment + 2[bp] + mov cx, _ata_cmd_data_in.blksize + 2[bp] ;; adjust if there will be an overrun. 2K max sector size - cmp di, #0xf800 ;; + cmp di, #0xf800 ;; jbe ata_in_no_adjust ata_in_adjust: @@ -3042,7 +3077,7 @@ ata_in_no_adjust: mov dx, _ata_cmd_data_in.iobase1 + 2[bp] ;; ATA data read port - mov ah, _ata_cmd_data_in.mode + 2[bp] + mov ah, _ata_cmd_data_in.mode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_in_32 @@ -3064,9 +3099,10 @@ ASM_END current++; write_word(ebda_seg, &EbdaData->ata.trsfsectors,current); count--; + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); status = inb(iobase1 + ATA_CB_STAT); if (count == 0) { - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != ATA_CB_STAT_RDY ) { BX_DEBUG_ATA("ata_cmd_data_in : no sectors left (status %02x)\n", (unsigned) status); return 4; @@ -3074,7 +3110,7 @@ ASM_END break; } else { - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { BX_DEBUG_ATA("ata_cmd_data_in : more sectors left (status %02x)\n", (unsigned) status); return 5; @@ -3099,9 +3135,9 @@ ASM_END // 5 : more sectors to read/verify // 6 : no sectors left to write // 7 : more sectors to write -Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba, segment, offset) +Bit16u ata_cmd_data_out(device, command, count, cylinder, head, sector, lba_low, lba_high, segment, offset) Bit16u device, command, count, cylinder, head, sector, segment, offset; -Bit32u lba; +Bit32u lba_low, lba_high; { Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u iobase1, iobase2, blksize; @@ -3130,22 +3166,20 @@ Bit32u lba; // sector will be 0 only on lba access. Convert to lba-chs if (sector == 0) { - if ((count >= 1 << 8) || (lba + count >= 1UL << 28)) { + if ((count >= 1 << 8) || lba_high || (lba_low + count >= 1UL << 28)) { outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, (count >> 8) & 0xff); - outb(iobase1 + ATA_CB_SN, lba >> 24); - outb(iobase1 + ATA_CB_CL, 0); - outb(iobase1 + ATA_CB_CH, 0); + outb(iobase1 + ATA_CB_SN, lba_low >> 24); + outb(iobase1 + ATA_CB_CL, lba_high & 0xff); + outb(iobase1 + ATA_CB_CH, lba_high >> 8); command |= 0x04; count &= (1UL << 8) - 1; - lba &= (1UL << 24) - 1; + lba_low &= (1UL << 24) - 1; } - sector = (Bit16u) (lba & 0x000000ffL); - lba >>= 8; - cylinder = (Bit16u) (lba & 0x0000ffffL); - lba >>= 16; - head = ((Bit16u) (lba & 0x0000000fL)) | 0x40; - } + sector = (Bit16u) (lba_low & 0x000000ffL); + cylinder = (Bit16u) ((lba_low>>8) & 0x0000ffffL); + head = ((Bit16u) ((lba_low>>24) & 0x0000000fL)) | ATA_CB_DH_LBA; + } outb(iobase1 + ATA_CB_FR, 0x00); outb(iobase1 + ATA_CB_SC, count); @@ -3155,10 +3189,8 @@ Bit32u lba; outb(iobase1 + ATA_CB_DH, (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0) | (Bit8u) head ); outb(iobase1 + ATA_CB_CMD, command); - while (1) { - status = inb(iobase1 + ATA_CB_STAT); - if ( !(status & ATA_CB_STAT_BSY) ) break; - } + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_data_out : read error\n"); @@ -3179,12 +3211,12 @@ ASM_START ASM_START push bp mov bp, sp - mov si, _ata_cmd_data_out.offset + 2[bp] - mov ax, _ata_cmd_data_out.segment + 2[bp] - mov cx, _ata_cmd_data_out.blksize + 2[bp] + mov si, _ata_cmd_data_out.offset + 2[bp] + mov ax, _ata_cmd_data_out.segment + 2[bp] + mov cx, _ata_cmd_data_out.blksize + 2[bp] ;; adjust if there will be an overrun. 2K max sector size - cmp si, #0xf800 ;; + cmp si, #0xf800 ;; jbe ata_out_no_adjust ata_out_adjust: @@ -3196,7 +3228,7 @@ ata_out_no_adjust: mov dx, _ata_cmd_data_out.iobase1 + 2[bp] ;; ATA data write port - mov ah, _ata_cmd_data_out.mode + 2[bp] + mov ah, _ata_cmd_data_out.mode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_out_32 @@ -3222,7 +3254,7 @@ ASM_END count--; status = inb(iobase1 + ATA_CB_STAT); if (count == 0) { - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != ATA_CB_STAT_RDY ) { BX_DEBUG_ATA("ata_cmd_data_out : no sectors left (status %02x)\n", (unsigned) status); return 6; @@ -3230,7 +3262,7 @@ ASM_END break; } else { - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { BX_DEBUG_ATA("ata_cmd_data_out : more sectors left (status %02x)\n", (unsigned) status); return 7; @@ -3297,19 +3329,17 @@ Bit32u length; if (status & ATA_CB_STAT_BSY) return 2; outb(iobase2 + ATA_CB_DC, ATA_CB_DC_HD15 | ATA_CB_DC_NIEN); - // outb(iobase1 + ATA_CB_FR, 0x00); - // outb(iobase1 + ATA_CB_SC, 0x00); - // outb(iobase1 + ATA_CB_SN, 0x00); + outb(iobase1 + ATA_CB_FR, 0x00); + outb(iobase1 + ATA_CB_SC, 0x00); + outb(iobase1 + ATA_CB_SN, 0x00); outb(iobase1 + ATA_CB_CL, 0xfff0 & 0x00ff); outb(iobase1 + ATA_CB_CH, 0xfff0 >> 8); outb(iobase1 + ATA_CB_DH, slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0); outb(iobase1 + ATA_CB_CMD, ATA_CMD_PACKET); // Device should ok to receive command - while (1) { - status = inb(iobase1 + ATA_CB_STAT); - if ( !(status & ATA_CB_STAT_BSY) ) break; - } + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + status = inb(iobase1 + ATA_CB_STAT); if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_packet : error, status is %02x\n",status); @@ -3326,13 +3356,13 @@ Bit32u length; // Send command to device ASM_START sti ;; enable higher priority interrupts - + push bp mov bp, sp - - mov si, _ata_cmd_packet.cmdoff + 2[bp] - mov ax, _ata_cmd_packet.cmdseg + 2[bp] - mov cx, _ata_cmd_packet.cmdlen + 2[bp] + + mov si, _ata_cmd_packet.cmdoff + 2[bp] + mov ax, _ata_cmd_packet.cmdseg + 2[bp] + mov cx, _ata_cmd_packet.cmdlen + 2[bp] mov es, ax ;; segment in es mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data write port @@ -3345,32 +3375,38 @@ ASM_END ASM_END if (inout == ATA_DATA_NO) { + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); status = inb(iobase1 + ATA_CB_STAT); } else { + Bit16u loops = 0; + Bit8u sc; while (1) { + if (loops == 0) {//first time through + status = inb(iobase2 + ATA_CB_ASTAT); + await_ide(NOT_BSY_DRQ, iobase1, IDE_TIMEOUT); + } + else + await_ide(NOT_BSY, iobase1, IDE_TIMEOUT); + loops++; + status = inb(iobase1 + ATA_CB_STAT); + sc = inb(iobase1 + ATA_CB_SC); // Check if command completed - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ) ) ==0 ) break; + if(((inb(iobase1 + ATA_CB_SC)&0x7)==0x3) && + ((status & (ATA_CB_STAT_RDY | ATA_CB_STAT_ERR)) == ATA_CB_STAT_RDY)) break; if (status & ATA_CB_STAT_ERR) { BX_DEBUG_ATA("ata_cmd_packet : error (status %02x)\n",status); return 3; } - // Device must be ready to send data - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) - != (ATA_CB_STAT_RDY | ATA_CB_STAT_DRQ) ) { - BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", status); - return 4; - } - // Normalize address bufseg += (bufoff / 16); bufoff %= 16; - + // Get the byte count lcount = ((Bit16u)(inb(iobase1 + ATA_CB_CH))<<8)+inb(iobase1 + ATA_CB_CL); @@ -3431,10 +3467,10 @@ ASM_START mov dx, _ata_cmd_packet.iobase1 + 2[bp] ;; ATA data read port - mov cx, _ata_cmd_packet.lbefore + 2[bp] + mov cx, _ata_cmd_packet.lbefore + 2[bp] jcxz ata_packet_no_before - mov ah, _ata_cmd_packet.lmode + 2[bp] + mov ah, _ata_cmd_packet.lmode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_packet_in_before_32 @@ -3451,14 +3487,14 @@ ata_packet_in_before_32_loop: pop eax ata_packet_no_before: - mov cx, _ata_cmd_packet.lcount + 2[bp] + mov cx, _ata_cmd_packet.lcount + 2[bp] jcxz ata_packet_after - mov di, _ata_cmd_packet.bufoff + 2[bp] - mov ax, _ata_cmd_packet.bufseg + 2[bp] + mov di, _ata_cmd_packet.bufoff + 2[bp] + mov ax, _ata_cmd_packet.bufseg + 2[bp] mov es, ax - mov ah, _ata_cmd_packet.lmode + 2[bp] + mov ah, _ata_cmd_packet.lmode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_packet_in_32 @@ -3472,10 +3508,10 @@ ata_packet_in_32: insd ;; CX dwords transfered to port(DX) to ES:[DI] ata_packet_after: - mov cx, _ata_cmd_packet.lafter + 2[bp] + mov cx, _ata_cmd_packet.lafter + 2[bp] jcxz ata_packet_done - mov ah, _ata_cmd_packet.lmode + 2[bp] + mov ah, _ata_cmd_packet.lmode + 2[bp] cmp ah, #ATA_MODE_PIO32 je ata_packet_in_after_32 @@ -3505,7 +3541,7 @@ ASM_END } // Final check, device must be ready - if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) + if ( (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_RDY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR) ) != ATA_CB_STAT_RDY ) { BX_DEBUG_ATA("ata_cmd_packet : not ready (status %02x)\n", (unsigned) status); return 4; @@ -3524,55 +3560,108 @@ ASM_END // Start of ATA/ATAPI generic functions // --------------------------------------------------------------------------- - Bit16u -atapi_get_sense(device) + Bit16u +atapi_get_sense(device, seg, asc, ascq) Bit16u device; { Bit8u atacmd[12]; - Bit8u buffer[16]; + Bit8u buffer[18]; Bit8u i; memsetb(get_SS(),atacmd,0,12); - // Request SENSE - atacmd[0]=0x03; - atacmd[4]=0x20; - if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 16L, ATA_DATA_IN, get_SS(), buffer) != 0) + // Request SENSE + atacmd[0]=ATA_CMD_REQUEST_SENSE; + atacmd[4]=sizeof(buffer); + if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 18L, ATA_DATA_IN, get_SS(), buffer) != 0) return 0x0002; - if ((buffer[0] & 0x7e) == 0x70) { - return (((Bit16u)buffer[2]&0x0f)*0x100)+buffer[12]; - } + write_byte(seg,asc,buffer[12]); + write_byte(seg,ascq,buffer[13]); return 0; } - Bit16u + Bit16u atapi_is_ready(device) Bit16u device; { - Bit8u atacmd[12]; - Bit8u buffer[]; - - memsetb(get_SS(),atacmd,0,12); - - // Test Unit Ready - if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) - return 0x000f; - - if (atapi_get_sense(device) !=0 ) { - memsetb(get_SS(),atacmd,0,12); - - // try to send Test Unit Ready again - if (ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 0L, ATA_DATA_NO, get_SS(), buffer) != 0) - return 0x000f; - - return atapi_get_sense(device); + Bit8u packet[12]; + Bit8u buf[8]; + Bit32u block_len; + Bit32u sectors; + Bit32u timeout; //measured in ms + Bit32u time; + Bit8u asc, ascq; + Bit8u in_progress; + Bit16u ebda_seg = read_word(0x0040,0x000E); + if (read_byte(ebda_seg,&EbdaData->ata.devices[device].type) != ATA_TYPE_ATAPI) { + printf("not implemented for non-ATAPI device\n"); + return -1; + } + + BX_DEBUG_ATA("ata_detect_medium: begin\n"); + memsetb(get_SS(),packet, 0, sizeof packet); + packet[0] = 0x25; /* READ CAPACITY */ + + /* Retry READ CAPACITY 50 times unless MEDIUM NOT PRESENT + * is reported by the device. If the device reports "IN PROGRESS", + * 30 seconds is added. */ + timeout = 5000; + time = 0; + in_progress = 0; + while (time < timeout) { + if (ata_cmd_packet(device, sizeof(packet), get_SS(), packet, 0, 8L, ATA_DATA_IN, get_SS(), buf) == 0) + goto ok; + + if (atapi_get_sense(device, get_SS(), &asc, &ascq) == 0) { + if (asc == 0x3a) { /* MEDIUM NOT PRESENT */ + BX_DEBUG_ATA("Device reports MEDIUM NOT PRESENT\n"); + return -1; + } + + if (asc == 0x04 && ascq == 0x01 && !in_progress) { + /* IN PROGRESS OF BECOMING READY */ + printf("Waiting for device to detect medium... "); + /* Allow 30 seconds more */ + timeout = 30000; + in_progress = 1; + } } + time += 100; + } + BX_DEBUG_ATA("read capacity failed\n"); + return -1; +ok: + + block_len = (Bit32u) buf[4] << 24 + | (Bit32u) buf[5] << 16 + | (Bit32u) buf[6] << 8 + | (Bit32u) buf[7] << 0; + BX_DEBUG_ATA("block_len=%u\n", block_len); + + if (block_len!= 2048 && block_len!= 512) + { + printf("Unsupported sector size %u\n", block_len); + return -1; + } + write_dword(ebda_seg,&EbdaData->ata.devices[device].blksize, block_len); + + sectors = (Bit32u) buf[0] << 24 + | (Bit32u) buf[1] << 16 + | (Bit32u) buf[2] << 8 + | (Bit32u) buf[3] << 0; + + BX_DEBUG_ATA("sectors=%u\n", sectors); + if (block_len == 2048) + sectors <<= 2; /* # of sectors in 512-byte "soft" sector */ + if (sectors != read_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low)) + printf("%dMB medium detected\n", sectors>>(20-9)); + write_dword(ebda_seg,&EbdaData->ata.devices[device].sectors_low, sectors); return 0; } - Bit16u + Bit16u atapi_is_cdrom(device) Bit8u device; { @@ -3632,7 +3721,7 @@ static char eltorito[24]="EL TORITO SPEC // // Returns ah: emulated drive, al: error code // - Bit16u + Bit16u cdrom_boot() { Bit16u ebda_seg=read_word(0x0040,0x000E); @@ -3645,9 +3734,12 @@ cdrom_boot() for (device=0; device<BX_MAX_ATA_DEVICES;device++) { if (atapi_is_cdrom(device)) break; } - + // if not found if(device >= BX_MAX_ATA_DEVICES) return 2; + + if(error = atapi_is_ready(device) != 0) + BX_INFO("ata_is_ready returned %d\n",error); // Read the Boot Record Volume Descriptor memsetb(get_SS(),atacmd,0,12); @@ -3668,7 +3760,7 @@ cdrom_boot() } for(i=0;i<23;i++) if(buffer[7+i]!=read_byte(0xf000,&eltorito[i]))return 6; - + // ok, now we calculate the Boot catalog address lba=buffer[0x4A]*0x1000000+buffer[0x49]*0x10000+buffer[0x48]*0x100+buffer[0x47]; @@ -3683,7 +3775,7 @@ cdrom_boot() atacmd[5]=(lba & 0x000000ff); if((error = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, 2048L, ATA_DATA_IN, get_SS(), buffer)) != 0) return 7; - + // Validation entry if(buffer[0x00]!=0x01)return 8; // Header if(buffer[0x01]!=0x00)return 9; // Platform @@ -3702,10 +3794,10 @@ cdrom_boot() write_byte(ebda_seg,&EbdaData->cdemu.media,buffer[0x21]); if(buffer[0x21]==0){ - // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0. + // FIXME ElTorito Hardcoded. cdrom is hardcoded as device 0xE0. // Win2000 cd boot needs to know it booted from cd write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0xE0); - } + } else if(buffer[0x21]<4) write_byte(ebda_seg,&EbdaData->cdemu.emulated_drive,0x00); else @@ -3719,7 +3811,7 @@ cdrom_boot() write_word(ebda_seg,&EbdaData->cdemu.load_segment,boot_segment); write_word(ebda_seg,&EbdaData->cdemu.buffer_segment,0x0000); - + nbsectors=buffer[0x27]*0x100+buffer[0x26]; write_word(ebda_seg,&EbdaData->cdemu.sector_count,nbsectors); @@ -3743,7 +3835,6 @@ cdrom_boot() /* measure 1st 512 bytes */ tcpa_ipl((Bit32u)1L,(Bit32u)boot_segment,(Bit32u)0L,(Bit32u)512L); #endif - // Remember the media type switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) { @@ -3765,7 +3856,7 @@ cdrom_boot() case 0x04: // Harddrive write_word(ebda_seg,&EbdaData->cdemu.vdevice.spt,read_byte(boot_segment,446+6)&0x3f); write_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders, - (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1); + (read_byte(boot_segment,446+6)<<2) + read_byte(boot_segment,446+7) + 1); write_word(ebda_seg,&EbdaData->cdemu.vdevice.heads,read_byte(boot_segment,446+5) + 1); break; } @@ -3778,7 +3869,7 @@ cdrom_boot() write_byte(ebda_seg, &EbdaData->ata.hdcount, read_byte(ebda_seg, &EbdaData->ata.hdcount) + 1); } - + // everything is ok, so from now on, the emulation is active if(read_byte(ebda_seg,&EbdaData->cdemu.media)!=0) write_byte(ebda_seg,&EbdaData->cdemu.active,0x01); @@ -4124,9 +4215,10 @@ ASM_END regs.u.r8.al = inb_cmos(0x30); regs.u.r8.ah = inb_cmos(0x31); - // limit to 15M - if(regs.u.r16.ax > 0x3c00) - regs.u.r16.ax = 0x3c00; + // According to Ralf Brown's interrupt the limit should be 15M, + // but real machines mostly return max. 63M. + if(regs.u.r16.ax > 0xffc0) + regs.u.r16.ax = 0xffc0; CLEAR_CF(); #endif @@ -4344,13 +4436,35 @@ BX_DEBUG_INT15("case 2:\n"); case 3: // Set Resolution BX_DEBUG_INT15("case 3:\n"); - // BX: + // BH: // 0 = 25 dpi, 1 count per millimeter // 1 = 50 dpi, 2 counts per millimeter // 2 = 100 dpi, 4 counts per millimeter // 3 = 200 dpi, 8 counts per millimeter - CLEAR_CF(); - regs.u.r8.ah = 0; + comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets + if (regs.u.r8.bh < 4) { + ret = send_to_mouse_ctrl(0xE8); // set resolution command + if (ret == 0) { + ret = get_mouse_data(&mouse_data1); + if (mouse_data1 != 0xfa) + BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1); + ret = send_to_mouse_ctrl(regs.u.r8.bh); + ret = get_mouse_data(&mouse_data1); + if (mouse_data1 != 0xfa) + BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1); + CLEAR_CF(); + regs.u.r8.ah = 0; + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + } else { + // error + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + } + set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable break; case 4: // Get Device ID @@ -4472,7 +4586,30 @@ BX_DEBUG_INT15("case default:\n"); break; } } -#endif +#endif // BX_USE_PS2_MOUSE + + +void set_e820_range(ES, DI, start, end, type) + Bit16u ES; + Bit16u DI; + Bit32u start; + Bit32u end; + Bit16u type; +{ + write_word(ES, DI, start); + write_word(ES, DI+2, start >> 16); + write_word(ES, DI+4, 0x00); + write_word(ES, DI+6, 0x00); + + end -= start; + write_word(ES, DI+8, end); + write_word(ES, DI+10, end >> 16); + write_word(ES, DI+12, 0x0000); + write_word(ES, DI+14, 0x0000); + + write_word(ES, DI+16, type); + write_word(ES, DI+18, 0x0); +} void int15_function32(regs, ES, DS, FLAGS) @@ -4486,17 +4623,20 @@ BX_DEBUG_INT15("int15 AX=%04x\n",regs.u. switch (regs.u.r8.ah) { case 0x86: - // Wait for CX:DX microseconds. currently using the - // refresh request port 0x61 bit4, toggling every 15usec + // Wait for CX:DX microseconds. currently using the + // refresh request port 0x61 bit4, toggling every 15usec CX = regs.u.r16.cx; DX = regs.u.r16.dx; ASM_START + sti + ;; Get the count in eax - mov ax, .int15_function32.CX [bp] + mov bx, sp + mov ax, _int15_function32.CX [bx] shl eax, #16 - mov ax, .int15_function32.DX [bp] + mov ax, _int15_function32.DX [bx] ;; convert to numbers of 15usec ticks mov ebx, #15 @@ -4527,7 +4667,8 @@ ASM_END case 0xe8: switch(regs.u.r8.al) { - case 0x20: { +#ifdef HVMASSIST + case 0x20: { Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14; if (regs.u.r32.edx != 0x534D4150) /* SMAP */ @@ -4575,7 +4716,7 @@ ASM_END // Get the amount of extended memory (above 1M) regs.u.r8.cl = inb_cmos(0x30); regs.u.r8.ch = inb_cmos(0x31); - + // limit to 15M if (regs.u.r16.cx > (15*1024)) regs.u.r16.cx = 15*1024; @@ -4603,7 +4744,7 @@ ASM_END regs.u.r16.bx = regs.u.r16.dx; break; } - default: /* AH=0xE8?? but not implemented */ + default: /* AH=0xE8?? but not implemented */ goto int15_unimplemented; } break; @@ -4616,16 +4757,178 @@ ASM_END regs.u.r8.ah = UNSUPPORTED_FUNCTION; break; } +#else + case 0x20: // coded by osmaker aka K.J. + if(regs.u.r32.edx == 0x534D4150) + { + extended_memory_size = inb_cmos(0x35); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x34); + extended_memory_size *= 64; + // greater than EFF00000??? + if(extended_memory_size > 0x3bc000) { + extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000 + } + extended_memory_size *= 1024; + extended_memory_size += (16L * 1024 * 1024); + + if(extended_memory_size <= (16L * 1024 * 1024)) { + extended_memory_size = inb_cmos(0x31); + extended_memory_size <<= 8; + extended_memory_size |= inb_cmos(0x30); + extended_memory_size *= 1024; + extended_memory_size += (1L * 1024 * 1024); + } + + switch(regs.u.r16.bx) + { + case 0: + set_e820_range(ES, regs.u.r16.di, + 0x0000000L, 0x0009f000L, 1); + regs.u.r32.ebx = 1; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 1: + set_e820_range(ES, regs.u.r16.di, + 0x0009f000L, 0x000a0000L, 2); + regs.u.r32.ebx = 2; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 2: + set_e820_range(ES, regs.u.r16.di, + 0x000e8000L, 0x00100000L, 2); + regs.u.r32.ebx = 3; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 3: +#if BX_ROMBIOS32 + set_e820_range(ES, regs.u.r16.di, + 0x00100000L, + extended_memory_size - ACPI_DATA_SIZE, 1); + regs.u.r32.ebx = 4; +#else + set_e820_range(ES, regs.u.r16.di, + 0x00100000L, + extended_memory_size, 1); + regs.u.r32.ebx = 5; +#endif + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 4: + set_e820_range(ES, regs.u.r16.di, + extended_memory_size - ACPI_DATA_SIZE, + extended_memory_size, 3); // ACPI RAM + regs.u.r32.ebx = 5; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + break; + case 5: + /* 256KB BIOS area at the end of 4 GB */ + set_e820_range(ES, regs.u.r16.di, + 0xfffc0000L, 0x00000000L, 2); + regs.u.r32.ebx = 0; + regs.u.r32.eax = 0x534D4150; + regs.u.r32.ecx = 0x14; + CLEAR_CF(); + return; + default: /* AX=E820, DX=534D4150, BX unrecognized */ + goto int15_unimplemented; + break; + } + } else { + // if DX != 0x534D4150) + goto int15_unimplemented; + } + break; + + case 0x01: + // do we have any reason to fail here ? + CLEAR_CF(); + + // my real system sets ax and bx to 0 + // this is confirmed by Ralph Brown list + // but syslinux v1.48 is known to behave + // strangely if ax is set to 0 + // regs.u.r16.ax = 0; + // regs.u.r16.bx = 0; + + // Get the amount of extended memory (above 1M) + regs.u.r8.cl = inb_cmos(0x30); + regs.u.r8.ch = inb_cmos(0x31); + + // limit to 15M + if(regs.u.r16.cx > 0x3c00) + { + regs.u.r16.cx = 0x3c00; + } + + // Get the amount of extended memory above 16M in 64k blocs + regs.u.r8.dl = inb_cmos(0x34); + regs.u.r8.dh = inb_cmos(0x35); + + // Set configured memory equal to extended memory + regs.u.r16.ax = regs.u.r16.cx; + regs.u.r16.bx = regs.u.r16.dx; + break; + default: /* AH=0xE8?? but not implemented */ + goto int15_unimplemented; + } + break; + int15_unimplemented: + // fall into the default + default: + BX_INFO("*** int 15h function AX=%04x, BX=%04x not yet supported!\n", + (unsigned) regs.u.r16.ax, (unsigned) regs.u.r16.bx); + SET_CF(); + regs.u.r8.ah = UNSUPPORTED_FUNCTION; + break; + } +#endif /* HVMASSIST */ } void int16_function(DI, SI, BP, SP, BX, DX, CX, AX, FLAGS) Bit16u DI, SI, BP, SP, BX, DX, CX, AX, FLAGS; { - Bit8u scan_code, ascii_code, shift_flags, count; + Bit8u scan_code, ascii_code, shift_flags, led_flags, count; Bit16u kbd_code, max; BX_DEBUG_INT16("int16: AX=%04x BX=%04x CX=%04x DX=%04x \n", AX, BX, CX, DX); + + shift_flags = read_byte(0x0040, 0x17); + led_flags = read_byte(0x0040, 0x97); + if ((((shift_flags >> 4) & 0x07) ^ (led_flags & 0x07)) != 0) { +ASM_START + cli +ASM_END + outb(0x60, 0xed); + while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21); + if ((inb(0x60) == 0xfa)) { + led_flags &= 0xf8; + led_flags |= ((shift_flags >> 4) & 0x07); + outb(0x60, led_flags & 0x07); + while ((inb(0x64) & 0x01) == 0) outb(0x80, 0x21); + inb(0x60); + write_byte(0x0040, 0x97, led_flags); + } +ASM_START + sti +ASM_END + } switch (GET_AH()) { case 0x00: /* read keyboard input */ @@ -4664,7 +4967,7 @@ int16_function(DI, SI, BP, SP, BX, DX, C break; case 0x09: /* GET KEYBOARD FUNCTIONALITY */ - // bit Bochs Description + // bit Bochs Description // 7 0 reserved // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support) // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support) @@ -4694,7 +4997,7 @@ int16_function(DI, SI, BP, SP, BX, DX, C kbd_code |= (inb(0x60) << 8); } } while (--count>0); - } + } } BX=kbd_code; break; @@ -4721,7 +5024,8 @@ int16_function(DI, SI, BP, SP, BX, DX, C case 0x12: /* get extended keyboard status */ shift_flags = read_byte(0x0040, 0x17); SET_AL(shift_flags); - shift_flags = read_byte(0x0040, 0x18); + shift_flags = read_byte(0x0040, 0x18) & 0x73; + shift_flags |= read_byte(0x0040, 0x96) & 0x0c; SET_AH(shift_flags); BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX); break; @@ -4736,7 +5040,7 @@ int16_function(DI, SI, BP, SP, BX, DX, C case 0x6F: if (GET_AL() == 0x08) - SET_AH(0x02); // unsupported, aka normal keyboard + SET_AH(0x02); // unsupported, aka normal keyboard default: BX_INFO("KBD: unsupported int 16h function %02x\n", GET_AH()); @@ -4877,7 +5181,7 @@ int09_function(DI, SI, BP, SP, BX, DX, C Bit16u DI, SI, BP, SP, BX, DX, CX, AX; { Bit8u scancode, asciicode, shift_flags; - Bit8u mf2_flags, mf2_state, led_flags; + Bit8u mf2_flags, mf2_state; // // DS has been set to F000 before call @@ -4895,7 +5199,6 @@ int09_function(DI, SI, BP, SP, BX, DX, C shift_flags = read_byte(0x0040, 0x17); mf2_flags = read_byte(0x0040, 0x18); mf2_state = read_byte(0x0040, 0x96); - led_flags = read_byte(0x0040, 0x97); asciicode = 0; switch (scancode) { @@ -4904,8 +5207,6 @@ int09_function(DI, SI, BP, SP, BX, DX, C write_byte(0x0040, 0x17, shift_flags); mf2_flags |= 0x40; write_byte(0x0040, 0x18, mf2_flags); - led_flags ^= 0x04; - write_byte(0x0040, 0x97, led_flags); break; case 0xba: /* Caps Lock release */ mf2_flags &= ~0x40; @@ -4913,11 +5214,8 @@ int09_function(DI, SI, BP, SP, BX, DX, C break; case 0x2a: /* L Shift press */ - /*shift_flags &= ~0x40;*/ shift_flags |= 0x02; write_byte(0x0040, 0x17, shift_flags); - led_flags &= ~0x04; - write_byte(0x0040, 0x97, led_flags); break; case 0xaa: /* L Shift release */ shift_flags &= ~0x02; @@ -4925,11 +5223,8 @@ int09_function(DI, SI, BP, SP, BX, DX, C break; case 0x36: /* R Shift press */ - /*shift_flags &= ~0x40;*/ shift_flags |= 0x01; write_byte(0x0040, 0x17, shift_flags); - led_flags &= ~0x04; - write_byte(0x0040, 0x97, led_flags); break; case 0xb6: /* R Shift release */ shift_flags &= ~0x01; @@ -4937,71 +5232,75 @@ int09_function(DI, SI, BP, SP, BX, DX, C break; case 0x1d: /* Ctrl press */ - shift_flags |= 0x04; - write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags |= 0x04; - } else { - mf2_flags |= 0x01; + if ((mf2_state & 0x01) == 0) { + shift_flags |= 0x04; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x02) { + mf2_state |= 0x04; + write_byte(0x0040, 0x96, mf2_state); + } else { + mf2_flags |= 0x01; + write_byte(0x0040, 0x18, mf2_flags); } - write_byte(0x0040, 0x18, mf2_flags); + } break; case 0x9d: /* Ctrl release */ - shift_flags &= ~0x04; - write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags &= ~0x04; - } else { - mf2_flags &= ~0x01; + if ((mf2_state & 0x01) == 0) { + shift_flags &= ~0x04; + write_byte(0x0040, 0x17, shift_flags); + if (mf2_state & 0x02) { + mf2_state &= ~0x04; + write_byte(0x0040, 0x96, mf2_state); + } else { + mf2_flags &= ~0x01; + write_byte(0x0040, 0x18, mf2_flags); } - write_byte(0x0040, 0x18, mf2_flags); + } break; case 0x38: /* Alt press */ shift_flags |= 0x08; write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags |= 0x08; + if (mf2_state & 0x02) { + mf2_state |= 0x08; + write_byte(0x0040, 0x96, mf2_state); } else { mf2_flags |= 0x02; - } - write_byte(0x0040, 0x18, mf2_flags); + write_byte(0x0040, 0x18, mf2_flags); + } break; case 0xb8: /* Alt release */ shift_flags &= ~0x08; write_byte(0x0040, 0x17, shift_flags); - if (mf2_state & 0x01) { - mf2_flags &= ~0x08; + if (mf2_state & 0x02) { + mf2_state &= ~0x08; + write_byte(0x0040, 0x96, mf2_state); } else { mf2_flags &= ~0x02; - } - write_byte(0x0040, 0x18, mf2_flags); + write_byte(0x0040, 0x18, mf2_flags); + } break; case 0x45: /* Num Lock press */ - if ((mf2_state & 0x01) == 0) { + if ((mf2_state & 0x03) == 0) { mf2_flags |= 0x20; write_byte(0x0040, 0x18, mf2_flags); shift_flags ^= 0x20; - led_flags ^= 0x02; write_byte(0x0040, 0x17, shift_flags); - write_byte(0x0040, 0x97, led_flags); - } + } break; case 0xc5: /* Num Lock release */ - if ((mf2_state & 0x01) == 0) { + if ((mf2_state & 0x03) == 0) { mf2_flags &= ~0x20; write_byte(0x0040, 0x18, mf2_flags); - } + } break; case 0x46: /* Scroll Lock press */ mf2_flags |= 0x10; write_byte(0x0040, 0x18, mf2_flags); shift_flags ^= 0x10; - led_flags ^= 0x01; write_byte(0x0040, 0x17, shift_flags); - write_byte(0x0040, 0x97, led_flags); break; case 0xc6: /* Scroll Lock release */ @@ -5014,50 +5313,55 @@ int09_function(DI, SI, BP, SP, BX, DX, C machine_reset(); /* Fall through */ default: - if (scancode & 0x80) return; /* toss key releases ... */ + if (scancode & 0x80) { + break; /* toss key releases ... */ + } if (scancode > MAX_SCAN_CODE) { - BX_INFO("KBD: int09h_handler(): unknown scancode (%x) read!\n", scancode); + BX_INFO("KBD: int09h_handler(): unknown scancode read: 0x%02x!\n", scancode); return; - } + } if (shift_flags & 0x08) { /* ALT */ asciicode = scan_to_scanascii[scancode].alt; scancode = scan_to_scanascii[scancode].alt >> 8; - } - else if (shift_flags & 0x04) { /* CONTROL */ + } else if (shift_flags & 0x04) { /* CONTROL */ asciicode = scan_to_scanascii[scancode].control; scancode = scan_to_scanascii[scancode].control >> 8; - } - else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */ - /* check if lock state should be ignored + } else if (((mf2_state & 0x02) > 0) && ((scancode >= 0x47) && (scancode <= 0x53))) { + /* extended keys handling */ + asciicode = 0xe0; + scancode = scan_to_scanascii[scancode].normal >> 8; + } else if (shift_flags & 0x03) { /* LSHIFT + RSHIFT */ + /* check if lock state should be ignored * because a SHIFT key are pressed */ - + if (shift_flags & scan_to_scanascii[scancode].lock_flags) { asciicode = scan_to_scanascii[scancode].normal; scancode = scan_to_scanascii[scancode].normal >> 8; - } - else { + } else { asciicode = scan_to_scanascii[scancode].shift; scancode = scan_to_scanascii[scancode].shift >> 8; - } } - else { + } else { /* check if lock is on */ if (shift_flags & scan_to_scanascii[scancode].lock_flags) { asciicode = scan_to_scanascii[scancode].shift; scancode = scan_to_scanascii[scancode].shift >> 8; - } - else { + } else { asciicode = scan_to_scanascii[scancode].normal; scancode = scan_to_scanascii[scancode].normal >> 8; - } } + } if (scancode==0 && asciicode==0) { BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n"); - } + } enqueue_key(scancode, asciicode); break; - } - mf2_state &= ~0x01; + } + if ((scancode & 0x7f) != 0x1d) { + mf2_state &= ~0x01; + } + mf2_state &= ~0x02; + write_byte(0x0040, 0x96, mf2_state); } unsigned int @@ -5065,9 +5369,6 @@ enqueue_key(scan_code, ascii_code) Bit8u scan_code, ascii_code; { Bit16u buffer_start, buffer_end, buffer_head, buffer_tail, temp_tail; - - //BX_INFO("KBD: enqueue_key() called scan:%02x, ascii:%02x\n", - // scan_code, ascii_code); #if BX_CPU < 2 buffer_start = 0x001E; @@ -5118,9 +5419,8 @@ BX_DEBUG_INT74("int74: read byte %02x\n" mouse_flags_2 = read_byte(ebda_seg, 0x0027); if ( (mouse_flags_2 & 0x80) != 0x80 ) { - // BX_PANIC("int74_function:\n"); return; - } + } package_count = mouse_flags_2 & 0x07; index = mouse_flags_1 & 0x07; @@ -5148,10 +5448,10 @@ BX_DEBUG_INT74("int74_function: make_far #if BX_USE_ATADRV void -int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) - Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; { - Bit32u lba; + Bit32u lba_low, lba_high; Bit16u ebda_seg=read_word(0x0040,0x000E); Bit16u cylinder, head, sector; Bit16u segment, offset; @@ -5172,12 +5472,12 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, // Get the ata channel device=read_byte(ebda_seg,&EbdaData->ata.hdidmap[GET_ELDL()-0x80]); - // basic check : device has to be valid + // basic check : device has to be valid if (device >= BX_MAX_ATA_DEVICES) { BX_INFO("int13_harddisk: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL()); goto int13_fail; } - + switch (GET_AH()) { case 0x00: /* disk controller reset */ @@ -5195,7 +5495,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, break; case 0x02: // read disk sectors - case 0x03: // write disk sectors + case 0x03: // write disk sectors case 0x04: // verify disk sectors count = GET_AL(); @@ -5207,10 +5507,10 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, segment = ES; offset = BX; - if ( (count > 128) || (count == 0) ) { - BX_INFO("int13_harddisk: function %02x, count out of range!\n",GET_AH()); + if ((count > 128) || (count == 0) || (sector == 0)) { + BX_INFO("int13_harddisk: function %02x, parameter out of range!\n",GET_AH()); goto int13_fail; - } + } nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); @@ -5221,7 +5521,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX_INFO("int13_harddisk: function %02x, parameters out of range %04x/%04x/%04x!\n", GET_AH(), cylinder, head, sector); goto int13_fail; } - + // FIXME verify if ( GET_AH() == 0x04 ) goto int13_success; @@ -5230,14 +5530,15 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, // if needed, translate lchs to lba, and execute command if ( (nph != nlh) || (npspt != nlspt)) { - lba = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1; + lba_low = ((((Bit32u)cylinder * (Bit32u)nlh) + (Bit32u)head) * (Bit32u)nlspt) + (Bit32u)sector - 1; + lba_high = 0; sector = 0; // this forces the command to be lba } if ( GET_AH() == 0x02 ) - status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba, segment, offset); + status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset); else - status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba, segment, offset); + status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, cylinder, head, sector, lba_low, lba_high, segment, offset); // Set nb of sector transferred SET_AL(read_word(ebda_seg, &EbdaData->ata.trsfsectors)); @@ -5258,7 +5559,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, break; case 0x08: /* read disk drive parameters */ - + // Get logical geometry from table nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); @@ -5273,13 +5574,13 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, SET_DL(count); /* FIXME returns 0, 1, or n hard drives */ // FIXME should set ES & DI - + goto int13_success; break; case 0x10: /* check drive ready */ // should look at 40:8E also??? - + // Read the status from controller status = inb(read_word(ebda_seg, &EbdaData->ata.channels[device/2].iobase1) + ATA_CB_STAT); if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY ) { @@ -5293,15 +5594,15 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, case 0x15: /* read disk drive size */ - // Get physical geometry from table - npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders); - nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads); - npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt); + // Get logical geometry from table + nlc = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.cylinders); + nlh = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.heads); + nlspt = read_word(ebda_seg, &EbdaData->ata.devices[device].lchs.spt); // Compute sector count seen by int13 - lba = (Bit32u)(npc - 1) * (Bit32u)nph * (Bit32u)npspt; - CX = lba >> 16; - DX = lba & 0xffff; + lba_low = (Bit32u)(nlc - 1) * (Bit32u)nlh * (Bit32u)nlspt; + CX = lba_low >> 16; + DX = lba_low & 0xffff; SET_AH(3); // hard disk accessible goto int13_success_noah; @@ -5322,30 +5623,31 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, count=read_word(DS, SI+(Bit16u)&Int13Ext->count); segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment); offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset); - - // Can't use 64 bits lba - lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); - if (lba != 0L) { - BX_PANIC("int13_harddisk: function %02x. Can't use 64bits lba\n",GET_AH()); - goto int13_fail; - } - - // Get 32 bits lba and check - lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); - if (lba >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors) ) { + + // Get 32 msb lba and check + lba_high=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); + if (lba_high > read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) ) { BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH()); goto int13_fail; } + // Get 32 lsb lba and check + lba_low=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); + if (lba_high == read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high) + && lba_low >= read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low) ) { + BX_INFO("int13_harddisk: function %02x. LBA out of range\n",GET_AH()); + goto int13_fail; + } + // If verify or seek if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 )) goto int13_success; - + // Execute the command if ( GET_AH() == 0x42 ) - status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba, segment, offset); + status=ata_cmd_data_in(device, ATA_CMD_READ_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset); else - status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba, segment, offset); + status=ata_cmd_data_out(device, ATA_CMD_WRITE_SECTORS, count, 0, 0, 0, lba_low, lba_high, segment, offset); count=read_word(ebda_seg, &EbdaData->ata.trsfsectors); write_word(DS, SI+(Bit16u)&Int13Ext->count, count); @@ -5363,7 +5665,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, case 0x49: // IBM/MS extended media change goto int13_success; // Always success for HD break; - + case 0x46: // IBM/MS eject media SET_AH(0xb2); // Volume Not Removable goto int13_fail_noah; // Always fail for HD @@ -5373,7 +5675,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, size=read_word(DS,SI+(Bit16u)&Int13DPT->size); // Buffer is too small - if(size < 0x1a) + if(size < 0x1a) goto int13_fail; // EDD 1.x @@ -5383,17 +5685,26 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, npc = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.cylinders); nph = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.heads); npspt = read_word(ebda_seg, &EbdaData->ata.devices[device].pchs.spt); - lba = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors); + lba_low = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_low); + lba_high = read_dword(ebda_seg, &EbdaData->ata.devices[device].sectors_high); blksize = read_word(ebda_seg, &EbdaData->ata.devices[device].blksize); write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1a); - write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid - write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc); + if (lba_high || (lba_low/npspt)/nph > 0x3fff) + { + write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x00); // geometry is invalid + write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, 0x3fff); + } + else + { + write_word(DS, SI+(Bit16u)&Int13DPT->infos, 0x02); // geometry is valid + write_dword(DS, SI+(Bit16u)&Int13DPT->cylinders, (Bit32u)npc); + } write_dword(DS, SI+(Bit16u)&Int13DPT->heads, (Bit32u)nph); write_dword(DS, SI+(Bit16u)&Int13DPT->spt, (Bit32u)npspt); - write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba); // FIXME should be Bit64 - write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0L); - write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, lba_low); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, lba_high); + write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); } // EDD 2.x @@ -5403,8 +5714,8 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e); - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); // Fill in dpte channel = device / 2; @@ -5414,14 +5725,14 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, mode = read_byte(ebda_seg, &EbdaData->ata.devices[device].mode); translation = read_byte(ebda_seg, &EbdaData->ata.devices[device].translation); - options = (translation==ATA_TRANSLATION_NONE?0:1<<3); // chs translation + options = (translation==ATA_TRANSLATION_NONE?0:1)<<3; // chs translation options |= (1<<4); // lba translation - options |= (mode==ATA_MODE_PIO32?1:0<<7); - options |= (translation==ATA_TRANSLATION_LBA?1:0<<9); - options |= (translation==ATA_TRANSLATION_RECHS?3:0<<9); + options |= (mode==ATA_MODE_PIO32?1:0)<<7; + options |= (translation==ATA_TRANSLATION_LBA?1:0)<<9; + options |= (translation==ATA_TRANSLATION_RECHS?3:0)<<9; write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1); - write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2); + write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC); write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 ); write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb ); write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq ); @@ -5430,10 +5741,13 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, write_byte(ebda_seg, &EbdaData->ata.dpte.pio, 0 ); write_word(ebda_seg, &EbdaData->ata.dpte.options, options); write_word(ebda_seg, &EbdaData->ata.dpte.reserved, 0); - write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); - + if (size >=0x42) + write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); + else + write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x10); + checksum=0; - for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i); + for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i); checksum = ~checksum; write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum); } @@ -5459,7 +5773,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A'); write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0); } - else { + else { // FIXME PCI } write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A'); @@ -5472,7 +5786,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0); write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L); } - else { + else { // FIXME PCI } write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2); @@ -5508,7 +5822,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, case 0x0d: /* alternate disk reset */ case 0x11: /* recalibrate */ case 0x14: /* controller internal diagnostic */ - BX_INFO("int13h_harddisk function %02xh unimplemented, returns success\n", GET_AH()); + BX_INFO("int13_harddisk: function %02xh unimplemented, returns success\n", GET_AH()); goto int13_success; break; @@ -5517,7 +5831,7 @@ int13_harddisk(DS, ES, DI, SI, BP, ELDX, case 0x18: // set media type for format case 0x50: // IBM/MS send packet command default: - BX_INFO("int13_harddisk function %02xh unsupported, returns fail\n", GET_AH()); + BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", GET_AH()); goto int13_fail; break; } @@ -5553,8 +5867,7 @@ int13_cdrom(EHBX, DS, ES, DI, SI, BP, EL Bit16u count, segment, offset, i, size; BX_DEBUG_INT13_CD("int13_cdrom: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); - // BX_DEBUG_INT13_CD("int13_cdrom: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI); - + SET_DISK_RET_STATUS(0x00); /* basic check : device should be 0xE0+ */ @@ -5571,16 +5884,16 @@ int13_cdrom(EHBX, DS, ES, DI, SI, BP, EL BX_INFO("int13_cdrom: function %02x, unmapped device for ELDL=%02x\n", GET_AH(), GET_ELDL()); goto int13_fail; } - + switch (GET_AH()) { // all those functions return SUCCESS case 0x00: /* disk controller reset */ case 0x09: /* initialize drive parameters */ case 0x0c: /* seek to specified cylinder */ - case 0x0d: /* alternate disk reset */ - case 0x10: /* check drive ready */ - case 0x11: /* recalibrate */ + case 0x0d: /* alternate disk reset */ + case 0x10: /* check drive ready */ + case 0x11: /* recalibrate */ case 0x14: /* controller internal diagnostic */ case 0x16: /* detect disk change */ goto int13_success; @@ -5602,7 +5915,7 @@ int13_cdrom(EHBX, DS, ES, DI, SI, BP, EL /* set CF if error status read */ if (status) goto int13_fail_nostatus; else goto int13_success_noah; - break; + break; case 0x15: /* read disk drive size */ SET_AH(0x02); @@ -5619,11 +5932,11 @@ int13_cdrom(EHBX, DS, ES, DI, SI, BP, EL case 0x42: // IBM/MS extended read case 0x44: // IBM/MS verify sectors case 0x47: // IBM/MS extended seek - + count=read_word(DS, SI+(Bit16u)&Int13Ext->count); segment=read_word(DS, SI+(Bit16u)&Int13Ext->segment); offset=read_word(DS, SI+(Bit16u)&Int13Ext->offset); - + // Can't use 64 bits lba lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba2); if (lba != 0L) { @@ -5631,13 +5944,13 @@ int13_cdrom(EHBX, DS, ES, DI, SI, BP, EL goto int13_fail; } - // Get 32 bits lba + // Get 32 bits lba lba=read_dword(DS, SI+(Bit16u)&Int13Ext->lba1); // If verify or seek if (( GET_AH() == 0x44 ) || ( GET_AH() == 0x47 )) goto int13_success; - + memsetb(get_SS(),atacmd,0,12); atacmd[0]=0x28; // READ command atacmd[7]=(count & 0xff00) >> 8; // Sectors @@ -5646,7 +5959,7 @@ int13_cdrom(EHBX, DS, ES, DI, SI, BP, EL atacmd[3]=(lba & 0x00ff0000) >> 16; atacmd[4]=(lba & 0x0000ff00) >> 8; atacmd[5]=(lba & 0x000000ff); - status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset); + status = ata_cmd_packet(device, 12, get_SS(), atacmd, 0, count*2048L, ATA_DATA_IN, segment,offset); count = (Bit16u)(read_dword(ebda_seg, &EbdaData->ata.trsfbytes) >> 11); write_word(DS, SI+(Bit16u)&Int13Ext->count, count); @@ -5693,21 +6006,21 @@ int13_cdrom(EHBX, DS, ES, DI, SI, BP, EL case 0x46: // IBM/MS eject media locks = read_byte(ebda_seg, &EbdaData->ata.devices[device].lock); - + if (locks != 0) { SET_AH(0xb1); // media locked goto int13_fail_noah; } // FIXME should handle 0x31 no media in device // FIXME should handle 0xb5 valid request failed - + // Call removable media eject ASM_START push bp mov bp, sp mov ah, #0x52 - int 15 + int #0x15 mov _int13_cdrom.status + 2[bp], ah jnc int13_cdrom_rme_end mov _int13_cdrom.status, #1 @@ -5727,7 +6040,7 @@ int13_cdrom_rme_end: size = read_word(DS,SI+(Bit16u)&Int13Ext->size); // Buffer is too small - if(size < 0x1a) + if(size < 0x1a) goto int13_fail; // EDD 1.x @@ -5742,8 +6055,8 @@ int13_cdrom_rme_end: write_dword(DS, SI+(Bit16u)&Int13DPT->heads, 0xffffffff); write_dword(DS, SI+(Bit16u)&Int13DPT->spt, 0xffffffff); write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count1, 0xffffffff); // FIXME should be Bit64 - write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff); - write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); + write_dword(DS, SI+(Bit16u)&Int13DPT->sector_count2, 0xffffffff); + write_word(DS, SI+(Bit16u)&Int13DPT->blksize, blksize); } // EDD 2.x @@ -5753,8 +6066,8 @@ int13_cdrom_rme_end: write_word(DS, SI+(Bit16u)&Int13DPT->size, 0x1e); - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); - write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_segment, ebda_seg); + write_word(DS, SI+(Bit16u)&Int13DPT->dpte_offset, &EbdaData->ata.dpte); // Fill in dpte channel = device / 2; @@ -5770,7 +6083,7 @@ int13_cdrom_rme_end: options |= (mode==ATA_MODE_PIO32?1:0<<7); write_word(ebda_seg, &EbdaData->ata.dpte.iobase1, iobase1); - write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2); + write_word(ebda_seg, &EbdaData->ata.dpte.iobase2, iobase2 + ATA_CB_DC); write_byte(ebda_seg, &EbdaData->ata.dpte.prefix, (0xe | (device % 2))<<4 ); write_byte(ebda_seg, &EbdaData->ata.dpte.unused, 0xcb ); write_byte(ebda_seg, &EbdaData->ata.dpte.irq, irq ); @@ -5782,7 +6095,7 @@ int13_cdrom_rme_end: write_byte(ebda_seg, &EbdaData->ata.dpte.revision, 0x11); checksum=0; - for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, (&EbdaData->ata.dpte) + i); + for (i=0; i<15; i++) checksum+=read_byte(ebda_seg, ((Bit8u*)(&EbdaData->ata.dpte)) + i); checksum = ~checksum; write_byte(ebda_seg, &EbdaData->ata.dpte.checksum, checksum); } @@ -5808,7 +6121,7 @@ int13_cdrom_rme_end: write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[2], 'A'); write_byte(DS, SI+(Bit16u)&Int13DPT->host_bus[3], 0); } - else { + else { // FIXME PCI } write_byte(DS, SI+(Bit16u)&Int13DPT->iface_type[0], 'A'); @@ -5821,7 +6134,7 @@ int13_cdrom_rme_end: write_word(DS, SI+(Bit16u)&Int13DPT->iface_path[2], 0); write_dword(DS, SI+(Bit16u)&Int13DPT->iface_path[4], 0L); } - else { + else { // FIXME PCI } write_byte(DS, SI+(Bit16u)&Int13DPT->device_path[0], device%2); @@ -5843,7 +6156,7 @@ int13_cdrom_rme_end: SET_AH(06); goto int13_fail_nostatus; break; - + case 0x4e: // // IBM/MS set hardware configuration // DMA, prefetch, PIO maximum not supported switch (GET_AL()) { @@ -5905,7 +6218,7 @@ int13_eltorito(DS, ES, DI, SI, BP, SP, B BX_DEBUG_INT13_ET("int13_eltorito: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); // BX_DEBUG_INT13_ET("int13_eltorito: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), DS, ES, DI, SI); - + switch (GET_AH()) { // FIXME ElTorito Various. Should be implemented @@ -5980,11 +6293,10 @@ int13_cdemu(DS, ES, DI, SI, BP, SP, BX, Bit8u atacmd[12]; BX_DEBUG_INT13_ET("int13_cdemu: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); - //BX_DEBUG_INT13_ET("int13_cdemu: SS=%04x ES=%04x DI=%04x SI=%04x\n", get_SS(), ES, DI, SI); - + /* at this point, we are emulating a floppy/harddisk */ - - // Recompute the device number + + // Recompute the device number device = read_byte(ebda_seg,&EbdaData->cdemu.controller_index) * 2; device += read_byte(ebda_seg,&EbdaData->cdemu.device_spec); @@ -5997,7 +6309,6 @@ int13_cdemu(DS, ES, DI, SI, BP, SP, BX, goto int13_fail; } - switch (GET_AH()) { // all those functions return SUCCESS @@ -6006,7 +6317,7 @@ int13_cdemu(DS, ES, DI, SI, BP, SP, BX, case 0x0c: /* seek to specified cylinder */ case 0x0d: /* alternate disk reset */ // FIXME ElTorito Various. should really reset ? case 0x10: /* check drive ready */ // FIXME ElTorito Various. should check if ready ? - case 0x11: /* recalibrate */ + case 0x11: /* recalibrate */ case 0x14: /* controller internal diagnostic */ case 0x16: /* detect disk change */ goto int13_success; @@ -6031,9 +6342,9 @@ int13_cdemu(DS, ES, DI, SI, BP, SP, BX, case 0x02: // read disk sectors case 0x04: // verify disk sectors - vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); - vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders); - vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads); + vspt = read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); + vcylinders = read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders); + vheads = read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads); ilba = read_dword(ebda_seg,&EbdaData->cdemu.ilba); @@ -6062,17 +6373,17 @@ int13_cdemu(DS, ES, DI, SI, BP, SP, BX, // calculate the virtual lba inside the image vlba=((((Bit32u)cylinder*(Bit32u)vheads)+(Bit32u)head)*(Bit32u)vspt)+((Bit32u)(sector-1)); - + // In advance so we don't loose the count SET_AL(nbsectors); // start lba on cd - slba = (Bit32u)vlba/4; + slba = (Bit32u)vlba/4; before= (Bit16u)vlba%4; // end lba on cd elba = (Bit32u)(vlba+nbsectors-1)/4; - + memsetb(get_SS(),atacmd,0,12); atacmd[0]=0x28; // READ command atacmd[7]=((Bit16u)(elba-slba+1) & 0xff00) >> 8; // Sectors @@ -6092,10 +6403,10 @@ int13_cdemu(DS, ES, DI, SI, BP, SP, BX, break; case 0x08: /* read disk drive parameters */ - vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); - vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1; - vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1; - + vspt=read_word(ebda_seg,&EbdaData->cdemu.vdevice.spt); + vcylinders=read_word(ebda_seg,&EbdaData->cdemu.vdevice.cylinders) - 1; + vheads=read_word(ebda_seg,&EbdaData->cdemu.vdevice.heads) - 1; + SET_AL( 0x00 ); SET_BL( 0x00 ); SET_CH( vcylinders & 0xff ); @@ -6103,7 +6414,7 @@ int13_cdemu(DS, ES, DI, SI, BP, SP, BX, SET_DH( vheads ); SET_DL( 0x02 ); // FIXME ElTorito Various. should send the real count of drives 1 or 2 // FIXME ElTorito Harddisk. should send the HD count - + switch(read_byte(ebda_seg,&EbdaData->cdemu.media)) { case 0x01: SET_BL( 0x02 ); break; case 0x02: SET_BL( 0x04 ); break; @@ -6139,7 +6450,7 @@ ASM_END case 0x45: // IBM/MS lock/unlock drive case 0x46: // IBM/MS eject media case 0x47: // IBM/MS extended seek - case 0x48: // IBM/MS get drive parameters + case 0x48: // IBM/MS get drive parameters case 0x49: // IBM/MS extended media change case 0x4e: // ? - set hardware configuration case 0x50: // ? - send packet command @@ -6227,8 +6538,8 @@ ASM_END } void -int13_harddisk(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) - Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; +int13_harddisk(EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) + Bit16u EHAX, DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; { Bit8u drive, num_sectors, sector, head, status, mod; Bit8u drive_map; @@ -6334,7 +6645,7 @@ BX_DEBUG_INT13_HD("int13_f01\n"); } if ( (num_sectors > 128) || (num_sectors == 0) ) - BX_PANIC("int13_harddisk(): num_sectors out of range!\n"); + BX_PANIC("int13_harddisk: num_sectors out of range!\n"); if (head > 15) BX_PANIC("hard drive BIOS:(read/verify) head > 15\n"); @@ -6480,7 +6791,7 @@ BX_DEBUG_INT13_HD("int13_f03\n"); } if ( (num_sectors > 128) || (num_sectors == 0) ) - BX_PANIC("int13_harddisk(): num_sectors out of range!\n"); + BX_PANIC("int13_harddisk: num_sectors out of range!\n"); if (head > 15) BX_PANIC("hard drive BIOS:(read) head > 15\n"); @@ -6590,7 +6901,7 @@ BX_DEBUG_INT13_HD("int13_f05\n"); case 0x08: /* read disk drive parameters */ BX_DEBUG_INT13_HD("int13_f08\n"); - + drive = GET_ELDL (); get_hd_geometry(drive, &hd_cylinders, &hd_heads, &hd_sectors); @@ -6730,10 +7041,10 @@ ASM_END break; case 0x18: // set media type for format - case 0x41: // IBM/MS - case 0x42: // IBM/MS - case 0x43: // IBM/MS - case 0x44: // IBM/MS + case 0x41: // IBM/MS + case 0x42: // IBM/MS + case 0x43: // IBM/MS + case 0x44: // IBM/MS case 0x45: // IBM/MS lock/unlock drive case 0x46: // IBM/MS eject media case 0x47: // IBM/MS extended seek @@ -6778,7 +7089,7 @@ get_hd_geometry(drive, hd_cylinders, hd_ hd_type = inb_cmos(0x12) & 0x0f; if (hd_type != 0x0f) BX_INFO(panic_msg_reg12h,1); - hd_type = inb_cmos(0x1a); // HD0: extended type + hd_type = inb_cmos(0x1a); // HD1: extended type if (hd_type != 47) BX_INFO(panic_msg_reg19h,0,0x1a); iobase = 0x24; @@ -6797,10 +7108,71 @@ get_hd_geometry(drive, hd_cylinders, hd_ #endif //else BX_USE_ATADRV +#if BX_SUPPORT_FLOPPY ////////////////////// // FLOPPY functions // ////////////////////// + +void floppy_reset_controller() +{ + Bit8u val8; + + // Reset controller + val8 = inb(0x03f2); + outb(0x03f2, val8 & ~0x04); + outb(0x03f2, val8 | 0x04); + + // Wait for controller to come out of reset + do { + val8 = inb(0x3f4); + } while ( (val8 & 0xc0) != 0x80 ); +} + +void floppy_prepare_controller(drive) + Bit16u drive; +{ + Bit8u val8, dor, prev_reset; + + // set 40:3e bit 7 to 0 + val8 = read_byte(0x0040, 0x003e); + val8 &= 0x7f; + write_byte(0x0040, 0x003e, val8); + + // turn on motor of selected drive, DMA & int enabled, normal operation + prev_reset = inb(0x03f2) & 0x04; + if (drive) + dor = 0x20; + else + dor = 0x10; + dor |= 0x0c; + dor |= drive; + outb(0x03f2, dor); + + // reset the disk motor timeout value of INT 08 + write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); + + // wait for drive readiness + do { + val8 = inb(0x3f4); + } while ( (val8 & 0xc0) != 0x80 ); + + if (prev_reset == 0) { + // turn on interrupts +ASM_START + sti +ASM_END + // wait on 40:3e bit 7 to become 1 + do { + val8 = read_byte(0x0040, 0x003e); + } while ( (val8 & 0x80) == 0 ); + val8 &= 0x7f; +ASM_START + cli +ASM_END + write_byte(0x0040, 0x003e, val8); + } +} bx_bool floppy_media_known(drive) @@ -6908,7 +7280,7 @@ floppy_media_sense(drive) retval = 1; } // - // Extended floppy size uses special cmos setting + // Extended floppy size uses special cmos setting else if ( drive_type == 6 ) { // 160k 5.25" drive config_data = 0x00; // 0000 0000 @@ -6949,63 +7321,41 @@ floppy_drive_recal(drive) floppy_drive_recal(drive) Bit16u drive; { - Bit8u val8, dor; + Bit8u val8; Bit16u curr_cyl_offset; - // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("floppy recal:f07: ctrl not ready\n"); + floppy_prepare_controller(drive); // send Recalibrate command (2 bytes) to controller outb(0x03f5, 0x07); // 07: Recalibrate outb(0x03f5, drive); // 0=drive0, 1=drive1 - // turn on interrupts + // turn on interrupts ASM_START sti ASM_END // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); - } - - val8 = 0; // separate asm from while() loop - // turn off interrupts + do { + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0, and calibrated bit - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; if (drive) { val8 |= 0x02; // Drive 1 calibrated curr_cyl_offset = 0x0095; - } - else { + } else { val8 |= 0x01; // Drive 0 calibrated curr_cyl_offset = 0x0094; - } + } write_byte(0x0040, 0x003e, val8); write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0 @@ -7032,7 +7382,6 @@ floppy_drive_exists(drive) return(1); } -#if BX_SUPPORT_FLOPPY void int13_diskette_function(DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS) Bit16u DS, ES, DI, SI, BP, ELDX, BX, DX, CX, AX, IP, CS, FLAGS; @@ -7045,7 +7394,6 @@ int13_diskette_function(DS, ES, DI, SI, Bit16u es, last_addr; BX_DEBUG_INT13_FL("int13_diskette: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", AX, BX, CX, DX, ES); - // BX_DEBUG_INT13_FL("int13_diskette: SS=%04x DS=%04x ES=%04x DI=%04x SI=%04x\n",get_SS(), get_DS(), ES, DI, SI); ah = GET_AH(); @@ -7058,7 +7406,7 @@ BX_DEBUG_INT13_FL("floppy f00\n"); set_diskette_ret_status(1); SET_CF(); return; - } + } drive_type = inb_cmos(0x10); if (drive == 0) @@ -7070,7 +7418,7 @@ BX_DEBUG_INT13_FL("floppy f00\n"); set_diskette_ret_status(0x80); SET_CF(); return; - } + } SET_AH(0); set_diskette_ret_status(0); CLEAR_CF(); // successful @@ -7083,7 +7431,7 @@ BX_DEBUG_INT13_FL("floppy f00\n"); SET_AH(val8); if (val8) { SET_CF(); - } + } return; case 0x02: // Read Diskette Sectors @@ -7095,15 +7443,15 @@ BX_DEBUG_INT13_FL("floppy f00\n"); head = GET_DH(); drive = GET_ELDL(); - if ( (drive > 1) || (head > 1) || - (num_sectors == 0) || (num_sectors > 72) ) { -BX_INFO("floppy: drive>1 || head>1 ...\n"); + if ((drive > 1) || (head > 1) || (sector == 0) || + (num_sectors == 0) || (num_sectors > 72)) { + BX_INFO("int13_diskette: read/write/verify: parameter out of range\n"); SET_AH(1); set_diskette_ret_status(1); SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } // see if drive exists if (floppy_drive_exists(drive) == 0) { @@ -7112,7 +7460,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } // see if media in drive, and type is known if (floppy_media_known(drive) == 0) { @@ -7122,8 +7470,8 @@ BX_INFO("floppy: drive>1 || head>1 ...\n SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } } + } if (ah == 0x02) { // Read Diskette Sectors @@ -7142,7 +7490,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n if ( base_address < base_es ) { // in case of carry, adjust page by 1 page++; - } + } base_count = (num_sectors * 512) - 1; // check for 64K boundary overrun @@ -7153,7 +7501,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } BX_DEBUG_INT13_FL("masking DMA-1 c2\n"); outb(0x000a, 0x06); @@ -7186,28 +7534,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n //-------------------------------------- // set up floppy controller for transfer //-------------------------------------- - - // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("int13_diskette:f02: ctrl not ready\n"); + floppy_prepare_controller(drive); // send read-normal-data command (9 bytes) to controller outb(0x03f5, 0xe6); // e6: read normal data @@ -7220,27 +7547,35 @@ BX_INFO("floppy: drive>1 || head>1 ...\n outb(0x03f5, 0); // Gap length outb(0x03f5, 0xff); // Gap length - // turn on interrupts + // turn on interrupts ASM_START sti ASM_END // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); + do { + val8 = read_byte(0x0040, 0x0040); + if (val8 == 0) { + floppy_reset_controller(); + SET_AH(0x80); // drive not ready (timeout) + set_diskette_ret_status(0x80); + SET_AL(0); // no sectors read + SET_CF(); // error occurred + return; } - - val8 = 0; // separate asm from while() loop - // turn off interrupts + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); + write_byte(0x0040, 0x003e, val8); // check port 3f4 for accessibility to status bytes val8 = inb(0x3f4); @@ -7271,7 +7606,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } // ??? should track be new val from return_status[3] ? set_diskette_current_cyl(drive, track); @@ -7279,8 +7614,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n SET_AH(0x00); // success CLEAR_CF(); // success return; - } - else if (ah == 0x03) { + } else if (ah == 0x03) { // Write Diskette Sectors //----------------------------------- @@ -7297,7 +7631,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n if ( base_address < base_es ) { // in case of carry, adjust page by 1 page++; - } + } base_count = (num_sectors * 512) - 1; // check for 64K boundary overrun @@ -7308,7 +7642,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } BX_DEBUG_INT13_FL("masking DMA-1 c2\n"); outb(0x000a, 0x06); @@ -7334,30 +7668,9 @@ BX_INFO("floppy: drive>1 || head>1 ...\n //-------------------------------------- // set up floppy controller for transfer //-------------------------------------- - - // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("int13_diskette:f03: ctrl not ready\n"); - - // send read-normal-data command (9 bytes) to controller + floppy_prepare_controller(drive); + + // send write-normal-data command (9 bytes) to controller outb(0x03f5, 0xc5); // c5: write normal data outb(0x03f5, (head << 2) | drive); // HD DR1 DR2 outb(0x03f5, track); @@ -7368,27 +7681,35 @@ BX_INFO("floppy: drive>1 || head>1 ...\n outb(0x03f5, 0); // Gap length outb(0x03f5, 0xff); // Gap length - // turn on interrupts + // turn on interrupts ASM_START sti ASM_END // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); + do { + val8 = read_byte(0x0040, 0x0040); + if (val8 == 0) { + floppy_reset_controller(); + SET_AH(0x80); // drive not ready (timeout) + set_diskette_ret_status(0x80); + SET_AL(0); // no sectors written + SET_CF(); // error occurred + return; } - - val8 = 0; // separate asm from while() loop - // turn off interrupts + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); + write_byte(0x0040, 0x003e, val8); // check port 3f4 for accessibility to status bytes val8 = inb(0x3f4); @@ -7432,8 +7753,7 @@ BX_INFO("floppy: drive>1 || head>1 ...\n SET_AH(0x00); // success CLEAR_CF(); // success return; - } - else { // if (ah == 0x04) + } else { // if (ah == 0x04) // Verify Diskette Sectors // ??? should track be new val from return_status[3] ? @@ -7442,8 +7762,8 @@ BX_INFO("floppy: drive>1 || head>1 ...\n CLEAR_CF(); // success SET_AH(0x00); // success return; - } - + } + break; case 0x05: // format diskette track BX_DEBUG_INT13_FL("floppy f05\n"); @@ -7458,7 +7778,7 @@ BX_DEBUG_INT13_FL("floppy f05\n"); SET_AH(1); set_diskette_ret_status(1); SET_CF(); // error occurred - } + } // see if drive exists if (floppy_drive_exists(drive) == 0) { @@ -7466,7 +7786,7 @@ BX_DEBUG_INT13_FL("floppy f05\n"); set_diskette_ret_status(0x80); SET_CF(); // error occurred return; - } + } // see if media in drive, and type is known if (floppy_media_known(drive) == 0) { @@ -7476,8 +7796,8 @@ BX_DEBUG_INT13_FL("floppy f05\n"); SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } } + } // set up DMA controller for transfer page = (ES >> 12); // upper 4 bits @@ -7487,7 +7807,7 @@ BX_DEBUG_INT13_FL("floppy f05\n"); if ( base_address < base_es ) { // in case of carry, adjust page by 1 page++; - } + } base_count = (num_sectors * 4) - 1; // check for 64K boundary overrun @@ -7498,7 +7818,7 @@ BX_DEBUG_INT13_FL("floppy f05\n"); SET_AL(0); // no sectors read SET_CF(); // error occurred return; - } + } outb(0x000a, 0x06); outb(0x000c, 0x00); // clear flip-flop @@ -7515,27 +7835,9 @@ BX_DEBUG_INT13_FL("floppy f05\n"); outb(0x000a, 0x02); // set up floppy controller for transfer - val8 = read_byte(0x0000, 0x043e); - val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); - // turn on motor of selected drive, DMA & int enabled, normal operation - if (drive) - dor = 0x20; - else - dor = 0x10; - dor |= 0x0c; - dor |= drive; - outb(0x03f2, dor); - - // reset the disk motor timeout value of INT 08 - write_byte(0x40,0x40, BX_FLOPPY_ON_CNT); - - // check port 3f4 for drive readiness - val8 = inb(0x3f4); - if ( (val8 & 0xf0) != 0x80 ) - BX_PANIC("int13_diskette:f05: ctrl not ready\n"); - - // send read-normal-data command (6 bytes) to controller + floppy_prepare_controller(drive); + + // send format-track command (6 bytes) to controller outb(0x03f5, 0x4d); // 4d: format track outb(0x03f5, (head << 2) | drive); // HD DR1 DR2 outb(0x03f5, 2); // 512 byte sector size @@ -7546,20 +7848,29 @@ BX_DEBUG_INT13_FL("floppy f05\n"); ASM_START sti ASM_END + // wait on 40:3e bit 7 to become 1 - val8 = (read_byte(0x0000, 0x043e) & 0x80); - while ( val8 == 0 ) { - val8 = (read_byte(0x0000, 0x043e) & 0x80); + do { + val8 = read_byte(0x0040, 0x0040); + if (val8 == 0) { + floppy_reset_controller(); + SET_AH(0x80); // drive not ready (timeout) + set_diskette_ret_status(0x80); + SET_CF(); // error occurred + return; } - val8 = 0; // separate asm from while() loop - // turn off interrupts + val8 = (read_byte(0x0040, 0x003e) & 0x80); + } while ( val8 == 0 ); + + val8 = 0; // separate asm from while() loop + // turn off interrupts ASM_START cli ASM_END // set 40:3e bit 7 to 0 - val8 = read_byte(0x0000, 0x043e); + val8 = read_byte(0x0040, 0x003e); val8 &= 0x7f; - write_byte(0x0000, 0x043e, val8); + write_byte(0x0040, 0x003e, val8); // check port 3f4 for accessibility to status bytes val8 = inb(0x3f4); if ( (val8 & 0xc0) != 0xc0 ) @@ -7911,8 +8222,9 @@ Bit16u seq_nr; Bit16u bootseg; Bit16u bootip; Bit16u status; - - struct ipl_entry e; + Bit16u bootfirst; + + ipl_entry_t e; // if BX_ELTORITO_BOOT is not defined, old behavior // check bit 5 in CMOS reg 0x2d. load either 0x00 or 0x80 into DL @@ -7926,7 +8238,7 @@ Bit16u seq_nr; // CMOS reg 0x38 & 0xf0 : 3rd boot device // boot device codes: // 0x00 : not defined - // 0x01 : first floppy + // 0x01 : first floppy // 0x02 : first harddrive // 0x03 : first cdrom // 0x04 - 0x0f : PnP expansion ROMs (e.g. Etherboot) @@ -7938,16 +8250,25 @@ Bit16u seq_nr; bootdev |= ((inb_cmos(0x38) & 0xf0) << 4); bootdev >>= 4 * seq_nr; bootdev &= 0xf; - if (bootdev == 0) BX_PANIC("No bootable device.\n"); - + + /* Read user selected device */ + bootfirst = read_word(ebda_seg, IPL_BOOTFIRST_OFFSET); + if (bootfirst != 0xFFFF) { + bootdev = bootfirst; + /* User selected device not set */ + write_word(ebda_seg, IPL_BOOTFIRST_OFFSET, 0xFFFF); + /* Reset boot sequence */ + write_word(ebda_seg, IPL_SEQUENCE_OFFSET, 0xFFFF); + } else if (bootdev == 0) BX_PANIC("No bootable device.\n"); + /* Translate from CMOS runes to an IPL table offset by subtracting 1 */ bootdev -= 1; -#else +#else if (seq_nr ==2) BX_PANIC("No more boot devices."); - if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1)) + if (!!(inb_cmos(0x2d) & 0x20) ^ (seq_nr == 1)) /* Boot from floppy if the bit is set or it's the second boot */ bootdev = 0x00; - else + else bootdev = 0x01; #endif @@ -7959,13 +8280,13 @@ Bit16u seq_nr; /* Do the loading, and set up vector as a far pointer to the boot * address, and bootdrv as the boot drive */ - print_boot_device(e.type); + print_boot_device(&e); switch(e.type) { - case 0x01: /* FDD */ - case 0x02: /* HDD */ - - bootdrv = (e.type == 0x02) ? 0x80 : 0x00; + case IPL_TYPE_FLOPPY: /* FDD */ + case IPL_TYPE_HARDDISK: /* HDD */ + + bootdrv = (e.type == IPL_TYPE_HARDDISK) ? 0x80 : 0x00; bootseg = 0x07c0; status = 0; @@ -7980,7 +8301,7 @@ ASM_START mov dl, _int18_function.bootdrv + 2[bp] mov ax, _int18_function.bootseg + 2[bp] mov es, ax ;; segment - mov bx, #0x0000 ;; offset + xor bx, bx ;; offset mov ah, #0x02 ;; function 2, read diskette sector mov al, #0x01 ;; read 1 sector mov ch, #0x00 ;; track 0 @@ -7998,7 +8319,7 @@ int19_load_done: pop ax pop bp ASM_END - + if (status != 0) { print_boot_failure(e.type, 1); return; @@ -8006,7 +8327,7 @@ ASM_END /* Always check the signature on a HDD boot sector; on FDD, only do * the check if the CMOS doesn't tell us to skip it */ - if (e.type != 0x00 || !((inb_cmos(0x38) & 0x01))) { + if ((e.type != IPL_TYPE_FLOPPY) || !((inb_cmos(0x38) & 0x01))) { if (read_word(bootseg,0x1fe) != 0xaa55) { print_boot_failure(e.type, 0); return; @@ -8024,7 +8345,7 @@ ASM_END break; #if BX_ELTORITO_BOOT - case 0x03: /* CD-ROM */ + case IPL_TYPE_CDROM: /* CD-ROM */ status = cdrom_boot(); // If failure @@ -8043,7 +8364,7 @@ ASM_END break; #endif - case 0x80: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */ + case IPL_TYPE_BEV: /* Expansion ROM with a Bootstrap Entry Vector (a far pointer) */ bootseg = e.vector >> 16; bootip = e.vector & 0xffff; break; @@ -8051,16 +8372,20 @@ ASM_END default: return; } - + /* Debugging info */ + BX_INFO("Booting from %x:%x\n", bootseg, bootip); + /* Jump to the boot vector */ ASM_START mov bp, sp +// push cs +// push #int18_handler ;; Build an iret stack frame that will take us to the boot vector. ;; iret pops ip, then cs, then flags, so push them in the opposite order. pushf - mov ax, _int18_function.bootseg + 0[bp] + mov ax, _int18_function.bootseg + 0[bp] push ax - mov ax, _int18_function.bootip + 0[bp] + mov ax, _int18_function.bootip + 0[bp] push ax ;; Set the magic number in ax and the boot drive in dl. mov ax, #0xaa55 @@ -8263,7 +8588,11 @@ int1a_function(regs, ds, iret_addr) } else if (regs.u.r8.bl == 0x83) { BX_INFO("bad PCI vendor ID %04x\n", regs.u.r16.dx); } else if (regs.u.r8.bl == 0x86) { - BX_INFO("PCI device %04x:%04x not found\n", regs.u.r16.dx, regs.u.r16.cx); + if (regs.u.r8.al == 0x02) { + BX_INFO("PCI device %04x:%04x not found at index %d\n", regs.u.r16.dx, regs.u.r16.cx, regs.u.r16.si); + } else { + BX_INFO("no PCI device with class code 0x%02x%04x found at index %d\n", regs.u.r8.cl, regs.u.r16.dx, regs.u.r16.si); + } } regs.u.r8.ah = regs.u.r8.bl; SetCF(iret_addr.flags); @@ -8309,11 +8638,11 @@ ASM_END // Done waiting. Bit16u segment, offset; - offset = read_word( 0x40, 0x98 ); - segment = read_word( 0x40, 0x9A ); + segment = read_word( 0x40, 0x98 ); + offset = read_word( 0x40, 0x9A ); write_byte( 0x40, 0xA0, 0 ); // Turn of status byte. outb_cmos( 0xB, registerB & 0x37 ); // Clear the Periodic Interrupt. - write_byte( segment, offset, 0x80 ); // Write to specified flag byte. + write_byte(segment, offset, read_byte(segment, offset) | 0x80 ); // Write to specified flag byte. } else { // Continue waiting. time -= 0x3D1; @@ -8521,13 +8850,18 @@ int13_notcdrom: #endif int13_disk: + ;; int13_harddisk modifies high word of EAX + shr eax, #16 + push ax call _int13_harddisk + pop ax + shl eax, #16 int13_out: pop ds pop es popa - iret + iret ;---------- ;- INT18h - @@ -8540,18 +8874,19 @@ int18_handler: ;; Boot Failure recovery: xor ax, ax mov ss, ax - ;; Get the boot sequence number out of the IPL memory ;; The first time we do this it will have been set to -1 so ;; we will start from device 0. - mov bx, #IPL_SEG + mov ds, ax + mov bx, word ptr [0x40E] ;; EBDA segment mov ds, bx ;; Set segment mov bx, IPL_SEQUENCE_OFFSET ;; BX is now the sequence number inc bx ;; ++ mov IPL_SEQUENCE_OFFSET, bx ;; Write it back - mov ds, ax ;; and reset the segment to zero. + mov ds, ax ;; and reset the segment to zero. ;; Call the C code for the next boot device push bx + call _int18_function ;; Boot failed: invoke the boot recovery function... @@ -8561,6 +8896,7 @@ int18_handler: ;; Boot Failure recovery: ;- INT19h - ;---------- int19_relocated: ;; Boot function, relocated + ;; ;; *** Warning: INT 19h resets the whole machine *** ;; @@ -8572,10 +8908,12 @@ int19_relocated: ;; Boot function, reloc ;; boot sequence will start, which is more or less the required behaviour. ;; ;; Reset SP and SS + mov ax, #0xfffe mov sp, ax xor ax, ax mov ss, ax + call _machine_reset ;---------- @@ -8589,7 +8927,7 @@ int1c_handler: ;; User Timer Tick ;- POST: Floppy Drive - ;---------------------- floppy_drive_post: - mov ax, #0x0000 + xor ax, ax mov ds, ax mov al, #0x00 @@ -8671,7 +9009,7 @@ hard_drive_post: mov dx, #0x03f6 out dx, al - mov ax, #0x0000 + xor ax, ax mov ds, ax mov 0x0474, al /* hard disk status of last operation */ mov 0x0477, al /* hard disk port offset (XT only ???) */ @@ -8686,8 +9024,8 @@ hard_drive_post: SET_INT_VECTOR(0x76, #0xF000, #int76_handler) ;; INT 41h: hard disk 0 configuration pointer ;; INT 46h: hard disk 1 configuration pointer - SET_INT_VECTOR(0x41, #EBDA_SEG, #0x003D) - SET_INT_VECTOR(0x46, #EBDA_SEG, #0x004D) + SET_INT_VECTOR(0x41, word ptr [0x40E], #0x003D) /* EBDA:003D */ + SET_INT_VECTOR(0x46, word ptr [0x40E], #0x004D) /* EBDA:004D */ ;; move disk geometry data from CMOS to EBDA disk parameter table(s) mov al, #0x12 @@ -8716,7 +9054,9 @@ post_d0_type47: ;; 22 landing zone high D ;; 23 sectors/track E - mov ax, #EBDA_SEG + xor ax, ax + mov ds, ax + mov ax, word ptr [0x40E] ;; EBDA segment mov ds, ax ;;; Filling EBDA table for hard disk 0. @@ -8862,7 +9202,9 @@ post_d1_type47: ;; 0x2b landing zone high D ;; 0x2c sectors/track E ;;; Fill EBDA table for hard disk 1. - mov ax, #EBDA_SEG + xor ax, ax + mov ds, ax + mov ax, word ptr [0x40E] ;; EBDA segment mov ds, ax mov al, #0x28 out #0x70, al @@ -8993,13 +9335,42 @@ ebda_post: ;-------------------- ; relocated here because the primary POST area isnt big enough. eoi_jmp_post: - call eoi_both_pics - + mov al, #0x20 + out #0xA0, al ;; slave PIC EOI + mov al, #0x20 + out #0x20, al ;; master PIC EOI + +jmp_post_0x467: xor ax, ax mov ds, ax jmp far ptr [0x467] +iret_post_0x467: + xor ax, ax + mov ds, ax + + mov sp, [0x467] + mov ss, [0x469] + iret + +retf_post_0x467: + xor ax, ax + mov ds, ax + + mov sp, [0x467] + mov ss, [0x469] + retf + +s3_post: +#if BX_ROMBIOS32 + call rombios32_init +#endif + call _s3_resume + mov bl, #0x00 + and ax, ax + jz normal_post + call _s3_resume_panic ;-------------------- eoi_both_pics: @@ -9152,16 +9523,22 @@ bios32_structure: .align 16 bios32_entry_point: - pushf - cmp eax, #0x49435024 + pushfd + cmp eax, #0x49435024 ;; "$PCI" jne unknown_service mov eax, #0x80000000 mov dx, #0x0cf8 out dx, eax mov dx, #0x0cfc in eax, dx - cmp eax, #0x12378086 +#ifdef PCI_FIXED_HOST_BRIDGE + cmp eax, #PCI_FIXED_HOST_BRIDGE jne unknown_service +#else + ;; say ok if a device is present + cmp eax, #0xffffffff + je unknown_service +#endif mov ebx, #0x000f0000 mov ecx, #0 mov edx, #pcibios_protected @@ -9170,12 +9547,15 @@ unknown_service: unknown_service: mov al, #0x80 bios32_end: - popf +#ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu +#endif + popfd retf .align 16 pcibios_protected: - pushf + pushfd cli push esi push edi @@ -9183,15 +9563,15 @@ pcibios_protected: jne pci_pro_f02 mov bx, #0x0210 mov cx, #0 - mov edx, #0x20494350 + mov edx, #0x20494350 ;; "PCI " mov al, #0x01 jmp pci_pro_ok pci_pro_f02: ;; find pci device cmp al, #0x02 - jne pci_pro_f08 + jne pci_pro_f03 shl ecx, #16 mov cx, dx - mov bx, #0x0000 + xor bx, bx mov di, #0x00 pci_pro_devloop: call pci_pro_select_reg @@ -9206,6 +9586,27 @@ pci_pro_nextdev: inc bx cmp bx, #0x0100 jne pci_pro_devloop + mov ah, #0x86 + jmp pci_pro_fail +pci_pro_f03: ;; find class code + cmp al, #0x03 + jne pci_pro_f08 + xor bx, bx + mov di, #0x08 +pci_pro_devloop2: + call pci_pro_select_reg + mov dx, #0x0cfc + in eax, dx + shr eax, #8 + cmp eax, ecx + jne pci_pro_nextdev2 + cmp si, #0 + je pci_pro_ok + dec si +pci_pro_nextdev2: + inc bx + cmp bx, #0x0100 + jne pci_pro_devloop2 mov ah, #0x86 jmp pci_pro_fail pci_pro_f08: ;; read configuration byte @@ -9281,16 +9682,20 @@ pci_pro_fail: pci_pro_fail: pop edi pop esi - sti - popf +#ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu +#endif + popfd stc retf pci_pro_ok: xor ah, ah pop edi pop esi - sti - popf +#ifdef BX_QEMU + and dword ptr[esp+8],0xfffffffc ;; reset CS.RPL for kqemu +#endif + popfd clc retf @@ -9317,8 +9722,14 @@ pcibios_real: out dx, eax mov dx, #0x0cfc in eax, dx - cmp eax, #0x12378086 +#ifdef PCI_FIXED_HOST_BRIDGE + cmp eax, #PCI_FIXED_HOST_BRIDGE je pci_present +#else + ;; say ok if a device is present + cmp eax, #0xffffffff + jne pci_present +#endif pop dx pop eax mov ah, #0xff @@ -9332,7 +9743,7 @@ pci_present: mov ax, #0x0001 mov bx, #0x0210 mov cx, #0 - mov edx, #0x20494350 + mov edx, #0x20494350 ;; "PCI " mov edi, #0xf0000 mov di, #pcibios_protected clc @@ -9341,10 +9752,10 @@ pci_real_f02: ;; find pci device push esi push edi cmp al, #0x02 - jne pci_real_f08 + jne pci_real_f03 shl ecx, #16 mov cx, dx - mov bx, #0x0000 + xor bx, bx mov di, #0x00 pci_real_devloop: call pci_real_select_reg @@ -9361,7 +9772,30 @@ pci_real_nextdev: jne pci_real_devloop mov dx, cx shr ecx, #16 - mov ah, #0x86 + mov ax, #0x8602 + jmp pci_real_fail +pci_real_f03: ;; find class code + cmp al, #0x03 + jne pci_real_f08 + xor bx, bx + mov di, #0x08 +pci_real_devloop2: + call pci_real_select_reg + mov dx, #0x0cfc + in eax, dx + shr eax, #8 + cmp eax, ecx + jne pci_real_nextdev2 + cmp si, #0 + je pci_real_ok + dec si +pci_real_nextdev2: + inc bx + cmp bx, #0x0100 + jne pci_real_devloop2 + mov dx, cx + shr ecx, #16 + mov ax, #0x8603 jmp pci_real_fail pci_real_f08: ;; read configuration byte cmp al, #0x08 @@ -9423,7 +9857,7 @@ pci_real_f0c: ;; write configuration wor jmp pci_real_ok pci_real_f0d: ;; write configuration dword cmp al, #0x0d - jne pci_real_unknown + jne pci_real_f0e call pci_real_select_reg push dx mov dx, #0x0cfc @@ -9431,6 +9865,46 @@ pci_real_f0d: ;; write configuration dwo out dx, eax pop dx jmp pci_real_ok +pci_real_f0e: ;; get irq routing options + cmp al, #0x0e + jne pci_real_unknown + SEG ES + cmp word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start + jb pci_real_too_small + SEG ES + mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start + pushf + push ds + push es + push cx + push si + push di + cld + mov si, #pci_routing_table_structure_start + push cs + pop ds + SEG ES + mov cx, [di+2] + SEG ES + mov es, [di+4] + mov di, cx + mov cx, #pci_routing_table_structure_end - pci_routing_table_structure_start + rep + movsb + pop di + pop si + pop cx + pop es + pop ds + popf + mov bx, #(1 << 9) | (1 << 11) ;; irq 9 and 11 are used + jmp pci_real_ok +pci_real_too_small: + SEG ES + mov word ptr [di], #pci_routing_table_structure_end - pci_routing_table_structure_start + mov ah, #0x89 + jmp pci_real_fail + pci_real_unknown: mov ah, #0x81 pci_real_fail: @@ -9457,7 +9931,7 @@ pci_real_select_reg: out dx, eax pop dx ret - + .align 16 pci_routing_table_structure: db 0x24, 0x50, 0x49, 0x52 ;; "$PIR" signature @@ -9465,21 +9939,22 @@ pci_routing_table_structure: dw 32 + (6 * 16) ;; table size db 0 ;; PCI interrupt router bus db 0x08 ;; PCI interrupt router DevFunc - dw 0x0000 ;; PCI exclusive IRQs + dw 0x0000 ;; PCI exclusive IRQs dw 0x8086 ;; compatible PCI interrupt router vendor ID - dw 0x7000 ;; compatible PCI interrupt router device ID + dw 0x122e ;; compatible PCI interrupt router device ID dw 0,0 ;; Miniport data db 0,0,0,0,0,0,0,0,0,0,0 ;; reserved - db 0x07 ;; checksum + db 0x37 ;; checksum +pci_routing_table_structure_start: ;; first slot entry PCI-to-ISA (embedded) db 0 ;; pci bus number db 0x08 ;; pci device number (bit 7-3) db 0x61 ;; link value INTA#: pointer into PCI2ISA config space - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x62 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x63 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x60 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 0 ;; physical slot (0 = embedded) @@ -9488,11 +9963,11 @@ pci_routing_table_structure: db 0 ;; pci bus number db 0x10 ;; pci device number (bit 7-3) db 0x62 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x63 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x60 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x61 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 1 ;; physical slot (0 = embedded) @@ -9501,11 +9976,11 @@ pci_routing_table_structure: db 0 ;; pci bus number db 0x18 ;; pci device number (bit 7-3) db 0x63 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x60 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x61 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x62 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 2 ;; physical slot (0 = embedded) @@ -9514,11 +9989,11 @@ pci_routing_table_structure: db 0 ;; pci bus number db 0x20 ;; pci device number (bit 7-3) db 0x60 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x61 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x62 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x63 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 3 ;; physical slot (0 = embedded) @@ -9527,11 +10002,11 @@ pci_routing_table_structure: db 0 ;; pci bus number db 0x28 ;; pci device number (bit 7-3) db 0x61 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x62 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x63 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x60 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 4 ;; physical slot (0 = embedded) @@ -9540,16 +10015,351 @@ pci_routing_table_structure: db 0 ;; pci bus number db 0x30 ;; pci device number (bit 7-3) db 0x62 ;; link value INTA# - dw 0x0c20 ;; IRQ bitmap INTA# + dw 0x0c20 ;; IRQ bitmap INTA# db 0x63 ;; link value INTB# - dw 0x0c20 ;; IRQ bitmap INTB# + dw 0x0c20 ;; IRQ bitmap INTB# db 0x60 ;; link value INTC# - dw 0x0c20 ;; IRQ bitmap INTC# + dw 0x0c20 ;; IRQ bitmap INTC# db 0x61 ;; link value INTD# dw 0x0c20 ;; IRQ bitmap INTD# db 5 ;; physical slot (0 = embedded) db 0 ;; reserved +pci_routing_table_structure_end: + +#if !BX_ROMBIOS32 +pci_irq_list: + db 11, 10, 9, 5; + +pcibios_init_sel_reg: + push eax + mov eax, #0x800000 + mov ax, bx + shl eax, #8 + and dl, #0xfc + or al, dl + mov dx, #0x0cf8 + out dx, eax + pop eax + ret + +pcibios_init_iomem_bases: + push bp + mov bp, sp + mov eax, #0xe0000000 ;; base for memory init + push eax + mov ax, #0xc000 ;; base for i/o init + push ax + mov ax, #0x0010 ;; start at base address #0 + push ax + mov bx, #0x0008 +pci_init_io_loop1: + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in ax, dx + cmp ax, #0xffff + jz next_pci_dev + mov dl, #0x04 ;; disable i/o and memory space access + call pcibios_init_sel_reg + mov dx, #0x0cfc + in al, dx + and al, #0xfc + out dx, al +pci_init_io_loop2: + mov dl, [bp-8] + call pcibios_init_sel_reg + mov dx, #0x0cfc + in eax, dx + test al, #0x01 + jnz init_io_base + mov ecx, eax + mov eax, #0xffffffff + out dx, eax + in eax, dx + cmp eax, ecx + je next_pci_base + xor eax, #0xffffffff + mov ecx, eax + mov eax, [bp-4] + out dx, eax + add eax, ecx ;; calculate next free mem base + add eax, #0x01000000 + and eax, #0xff000000 + mov [bp-4], eax + jmp next_pci_base +init_io_base: + mov cx, ax + mov ax, #0xffff + out dx, ax + in ax, dx + cmp ax, cx + je next_pci_base + xor ax, #0xfffe + mov cx, ax + mov ax, [bp-6] + out dx, ax + add ax, cx ;; calculate next free i/o base + add ax, #0x0100 + and ax, #0xff00 + mov [bp-6], ax +next_pci_base: + mov al, [bp-8] + add al, #0x04 + cmp al, #0x28 + je enable_iomem_space + mov byte ptr[bp-8], al + jmp pci_init_io_loop2 +enable_iomem_space: + mov dl, #0x04 ;; enable i/o and memory space access if available + call pcibios_init_sel_reg + mov dx, #0x0cfc + in al, dx + or al, #0x07 + out dx, al +next_pci_dev: + mov byte ptr[bp-8], #0x10 + inc bx + cmp bx, #0x0100 + jne pci_init_io_loop1 + mov sp, bp + pop bp + ret + +pcibios_init_set_elcr: + push ax + push cx + mov dx, #0x04d0 + test al, #0x08 + jz is_master_pic + inc dx + and al, #0x07 +is_master_pic: + mov cl, al + mov bl, #0x01 + shl bl, cl + in al, dx + or al, bl + out dx, al + pop cx + pop ax + ret + +pcibios_init_irqs: + push ds + push bp + mov ax, #0xf000 + mov ds, ax + mov dx, #0x04d0 ;; reset ELCR1 + ELCR2 + mov al, #0x00 + out dx, al + inc dx + out dx, al + mov si, #pci_routing_table_structure + mov bh, [si+8] + mov bl, [si+9] + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in eax, dx + cmp eax, [si+12] ;; check irq router + jne pci_init_end + mov dl, [si+34] + call pcibios_init_sel_reg + push bx ;; save irq router bus + devfunc + mov dx, #0x0cfc + mov ax, #0x8080 + out dx, ax ;; reset PIRQ route control + add dx, #2 + out dx, ax + mov ax, [si+6] + sub ax, #0x20 + shr ax, #4 + mov cx, ax + add si, #0x20 ;; set pointer to 1st entry + mov bp, sp + mov ax, #pci_irq_list + push ax + xor ax, ax + push ax +pci_init_irq_loop1: + mov bh, [si] + mov bl, [si+1] +pci_init_irq_loop2: + mov dl, #0x00 + call pcibios_init_sel_reg + mov dx, #0x0cfc + in ax, dx + cmp ax, #0xffff + jnz pci_test_int_pin + test bl, #0x07 + jz next_pir_entry + jmp next_pci_func +pci_test_int_pin: + mov dl, #0x3c + call pcibios_init_sel_reg + mov dx, #0x0cfd + in al, dx + and al, #0x07 + jz next_pci_func + dec al ;; determine pirq reg + mov dl, #0x03 + mul al, dl + add al, #0x02 + xor ah, ah + mov bx, ax + mov al, [si+bx] + mov dl, al + mov bx, [bp] + call pcibios_init_sel_reg + mov dx, #0x0cfc + and al, #0x03 + add dl, al + in al, dx + cmp al, #0x80 + jb pirq_found + mov bx, [bp-2] ;; pci irq list pointer + mov al, [bx] + out dx, al + inc bx + mov [bp-2], bx + call pcibios_init_set_elcr +pirq_found: + mov bh, [si] + mov bl, [si+1] + add bl, [bp-3] ;; pci function number + mov dl, #0x3c + call pcibios_init_sel_reg + mov dx, #0x0cfc + out dx, al +next_pci_func: + inc byte ptr[bp-3] + inc bl + test bl, #0x07 + jnz pci_init_irq_loop2 +next_pir_entry: + add si, #0x10 + mov byte ptr[bp-3], #0x00 + loop pci_init_irq_loop1 + mov sp, bp + pop bx +pci_init_end: + pop bp + pop ds + ret +#endif // !BX_ROMBIOS32 #endif // BX_PCIBIOS + +#if BX_ROMBIOS32 +rombios32_init: + ;; save a20 and enable it + in al, 0x92 + push ax + or al, #0x02 + out 0x92, al + + ;; save SS:SP to the BDA + xor ax, ax + mov ds, ax + mov 0x0469, ss + mov 0x0467, sp + + SEG CS + lidt [pmode_IDT_info] + SEG CS + lgdt [rombios32_gdt_48] + ;; set PE bit in CR0 + mov eax, cr0 + or al, #0x01 + mov cr0, eax + ;; start protected mode code: ljmpl 0x10:rombios32_init1 + db 0x66, 0xea + dw rombios32_05 + dw 0x000f ;; high 16 bit address + dw 0x0010 + +use32 386 +rombios32_05: + ;; init data segments + mov eax, #0x18 + mov ds, ax + mov es, ax + mov ss, ax + xor eax, eax + mov fs, ax + mov gs, ax + cld + + ;; init the stack pointer to point below EBDA + mov ax, [0x040e] + shl eax, #4 + mov esp, #-0x10 + add esp, eax + + ;; pass pointer to s3_resume_flag and s3_resume_vector to rombios32 + push #0x04b0 + push #0x04b2 + + ;; call rombios32 code + mov eax, #0x000e0000 + call eax + + ;; return to 16 bit protected mode first + db 0xea + dd rombios32_10 + dw 0x20 + +use16 386 +rombios32_10: + ;; restore data segment limits to 0xffff + mov ax, #0x28 + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + ;; reset PE bit in CR0 + mov eax, cr0 + and al, #0xFE + mov cr0, eax + + ;; far jump to flush CPU queue after transition to real mode + JMP_AP(0xf000, rombios32_real_mode) + +rombios32_real_mode: + ;; restore IDT to normal real-mode defaults + SEG CS + lidt [rmode_IDT_info] + + xor ax, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ;; restore SS:SP from the BDA + mov ss, 0x0469 + xor esp, esp + mov sp, 0x0467 + ;; restore a20 + pop ax + out 0x92, al + ret + +rombios32_gdt_48: + dw 0x30 + dw rombios32_gdt + dw 0x000f + +rombios32_gdt: + dw 0, 0, 0, 0 + dw 0, 0, 0, 0 + dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x10) + dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x18) + dw 0xffff, 0, 0x9b0f, 0x0000 ; 16 bit code segment base=0xf0000 limit=0xffff + dw 0xffff, 0, 0x9300, 0x0000 ; 16 bit data segment base=0x0 limit=0xffff +#endif // BX_ROMBIOS32 + ; parallel port detection: base address in DX, index in BX, timeout in CL detect_parport: @@ -9621,13 +10431,12 @@ checksum_loop: ret -;; We need a copy of this string, but we are not actually a PnP BIOS, +;; We need a copy of this string, but we are not actually a PnP BIOS, ;; so make sure it is *not* aligned, so OSes will not see it if they scan. .align 16 db 0 pnp_string: .ascii "$PnP" - rom_scan: ;; Scan for existence of valid expansion ROMS. @@ -9645,8 +10454,9 @@ rom_scan: #if BX_TCGBIOS call _tcpa_start_option_rom_scan /* specs: 3.2.3.3 + 10.4.3 */ #endif - mov cx, #0xc000 + rom_scan_loop: + push ax ;; Save AX mov ds, cx mov ax, #0x0004 ;; start with increment of 4 (512-byte) blocks = 2k cmp [0], #0xAA55 ;; look for signature @@ -9663,6 +10473,8 @@ rom_scan_loop: add al, #0x04 block_count_rounded: + xor bx, bx ;; Restore DS back to 0000: + mov ds, bx #if BX_TCGBIOS push ax push ds @@ -9673,7 +10485,7 @@ block_count_rounded: push ecx ;; segment where option rom is located at call _tcpa_option_rom /* specs: 3.2.3.3 */ add sp, #4 ;; pop segment - pop ecx ;; original ecx + pop ecx ;; original ecx pop ds pop ax #endif @@ -9697,11 +10509,11 @@ fetch_bdf: xor ax, ax mov al, [bx] - ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS. + ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS. ;; That should stop it grabbing INT 19h; we will use its BEV instead. mov bx, #0xf000 mov es, bx - lea di, pnp_string + lea di, pnp_string xor bx, bx ;; Restore DS back to 0000: mov ds, bx @@ -9714,8 +10526,8 @@ fetch_bdf: add sp, #2 ;; Pop offset value pop cx ;; Pop seg value (restore CX) - ;; Look at the ROM's PnP Expansion header. Properly, we're supposed - ;; to init all the ROMs and then go back and build an IPL table of + ;; Look at the ROM's PnP Expansion header. Properly, we're supposed + ;; to init all the ROMs and then go back and build an IPL table of ;; all the bootable devices, but we can get away with one pass. mov ds, cx ;; ROM base mov bx, 0x001a ;; 0x1A is the offset into ROM header that contains... @@ -9723,22 +10535,54 @@ fetch_bdf: cmp ax, #0x5024 ;; we look for signature "$PnP" jne no_bev mov ax, 2[bx] - cmp ax, #0x506e + cmp ax, #0x506e jne no_bev + + mov ax, 0x16[bx] ;; 0x16 is the offset of Boot Connection Vector + cmp ax, #0x0000 + je no_bcv + + ;; Option ROM has BCV. Run it now. + push cx ;; Push seg + push ax ;; Push offset + + ;; Point ES:DI at "$PnP", which tells the ROM that we are a PnP BIOS. + mov bx, #0xf000 + mov es, bx + lea di, pnp_string + /* jump to BCV function entry pointer */ + mov bp, sp ;; Call ROM BCV routine using seg:off on stack + db 0xff ;; call_far ss:[bp+0] + db 0x5e + db 0 + cli ;; In case expansion ROM BIOS turns IF on + add sp, #2 ;; Pop offset value + pop cx ;; Pop seg value (restore CX) + jmp no_bev + +no_bcv: mov ax, 0x1a[bx] ;; 0x1A is also the offset into the expansion header of... cmp ax, #0x0000 ;; the Bootstrap Entry Vector, or zero if there is none. je no_bev - ;; Found a device that thinks it can boot the system. Record its BEV. - mov bx, #IPL_SEG ;; Go to the segment where the IPL table lives + ;; Found a device that thinks it can boot the system. Record its BEV and product name string. + mov di, 0x10[bx] ;; Pointer to the product name string or zero if none + xor bx, bx mov ds, bx + mov bx, word ptr [0x40E] ;; EBDA segment + mov ds, bx ;; Go to the segment where the IPL table lives mov bx, IPL_COUNT_OFFSET ;; Read the number of entries so far cmp bx, #IPL_TABLE_ENTRIES je no_bev ;; Get out if the table is full shl bx, #0x4 ;; Turn count into offset (entries are 16 bytes) - mov 0[bx], #0x80 ;; This entry is a BEV device - mov 6[bx], cx ;; Build a far pointer from the segment... - mov 4[bx], ax ;; and the offset + mov IPL_TABLE_OFFSET+0[bx], #IPL_TYPE_BEV ;; This entry is a BEV device + mov IPL_TABLE_OFFSET+6[bx], cx ;; Build a far pointer from the segment... + mov IPL_TABLE_OFFSET+4[bx], ax ;; and the offset + cmp di, #0x0000 + je no_prod_str + mov 0xA[bx], cx ;; Build a far pointer from the segment... + mov 8[bx], di ;; and the offset +no_prod_str: shr bx, #0x4 ;; Turn the offset back into a count inc bx ;; We have one more entry now mov IPL_COUNT_OFFSET, bx ;; Remember that. @@ -9750,7 +10594,8 @@ rom_scan_increment: shl ax, #5 ;; convert 512-bytes blocks to 16-byte increments ;; because the segment selector is shifted left 4 bits. add cx, ax - cmp cx, #0xe000 + pop ax ;; Restore AX + cmp cx, ax jbe rom_scan_loop xor ax, ax ;; Restore DS back to 0000: @@ -9815,234 +10660,7 @@ tcpa_post_part2: #endif -;; for 'C' strings and other data, insert them here with -;; a the following hack: -;; DATA_SEG_DEFS_HERE - - -;-------- -;- POST - -;-------- -.org 0xe05b ; POST Entry Point -post: - - xor ax, ax - - ;; first reset the DMA controllers - out 0x0d,al - out 0xda,al - - ;; then initialize the DMA controllers - mov al, #0xC0 - out 0xD6, al ; cascade mode of channel 4 enabled - mov al, #0x00 - out 0xD4, al ; unmask channel 4 - - ;; Examine CMOS shutdown status. - mov AL, #0x0f - out 0x70, AL - in AL, 0x71 - - ;; backup status - mov bl, al - - ;; Reset CMOS shutdown status. - mov AL, #0x0f - out 0x70, AL ; select CMOS register Fh - mov AL, #0x00 - out 0x71, AL ; set shutdown action to normal - - ;; Examine CMOS shutdown status. - mov al, bl - mov dx, #EBDA_SEG - mov ds, dx - mov [EBDA_CMOS_SHUTDOWN_STATUS_OFFSET], AL - - cli - mov ax, #0xfffe - mov sp, ax - mov ax, #0x0000 - mov ds, ax - mov ss, ax - - ;; zero out BIOS data area (40:00..40:ff) - mov es, ax - mov cx, #0x0080 ;; 128 words - mov di, #0x0400 - cld - rep - stosw - - call _log_bios_start - - ;; set all interrupts to default handler - mov bx, #0x0000 ;; offset index - mov cx, #0x0100 ;; counter (256 interrupts) - mov ax, #dummy_iret_handler - mov dx, #0xF000 - -post_default_ints: - mov [bx], ax - inc bx - inc bx - mov [bx], dx - inc bx - inc bx - loop post_default_ints - - ;; set vector 0x79 to zero - ;; this is used by 'gardian angel' protection system - SET_INT_VECTOR(0x79, #0, #0) - - ;; base memory in K 40:13 (word) - mov ax, #BASE_MEM_IN_K - mov 0x0413, ax - - - ;; Manufacturing Test 40:12 - ;; zerod out above - - ;; Warm Boot Flag 0040:0072 - ;; value of 1234h = skip memory checks - ;; zerod out above - - - ;; Printer Services vector - SET_INT_VECTOR(0x17, #0xF000, #int17_handler) - - ;; Bootstrap failure vector - SET_INT_VECTOR(0x18, #0xF000, #int18_handler) - - ;; Bootstrap Loader vector - SET_INT_VECTOR(0x19, #0xF000, #int19_handler) - - ;; User Timer Tick vector - SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler) - - ;; Memory Size Check vector - SET_INT_VECTOR(0x12, #0xF000, #int12_handler) - - ;; Equipment Configuration Check vector - SET_INT_VECTOR(0x11, #0xF000, #int11_handler) - - ;; System Services - SET_INT_VECTOR(0x15, #0xF000, #int15_handler) - - ;; EBDA setup - call ebda_post - - ;; PIT setup - SET_INT_VECTOR(0x08, #0xF000, #int08_handler) - ;; int 1C already points at dummy_iret_handler (above) - mov al, #0x34 ; timer0: binary count, 16bit count, mode 2 - out 0x43, al -#ifdef HVMASSIST - mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support) - out 0x40, al ; lsb - mov al, #0xe9 - out 0x40, al ; msb -#else - mov al, #0x00 ; maximum count of 0000H = 18.2Hz - out 0x40, al - out 0x40, al -#endif - - ;; Keyboard - SET_INT_VECTOR(0x09, #0xF000, #int09_handler) - SET_INT_VECTOR(0x16, #0xF000, #int16_handler) - - xor ax, ax - mov ds, ax - mov 0x0417, al /* keyboard shift flags, set 1 */ - mov 0x0418, al /* keyboard shift flags, set 2 */ - mov 0x0419, al /* keyboard alt-numpad work area */ - mov 0x0471, al /* keyboard ctrl-break flag */ - mov 0x0497, al /* keyboard status flags 4 */ - mov al, #0x10 - mov 0x0496, al /* keyboard status flags 3 */ - - - /* keyboard head of buffer pointer */ - mov bx, #0x001E - mov 0x041A, bx - - /* keyboard end of buffer pointer */ - mov 0x041C, bx - - /* keyboard pointer to start of buffer */ - mov bx, #0x001E - mov 0x0480, bx - - /* keyboard pointer to end of buffer */ - mov bx, #0x003E - mov 0x0482, bx - - /* init the keyboard */ - call _keyboard_init - - ;; mov CMOS Equipment Byte to BDA Equipment Word - mov ax, 0x0410 - mov al, #0x14 - out 0x70, al - in al, 0x71 - mov 0x0410, ax - -#if BX_TCGBIOS - call tcpa_post_part1 -#endif - - ;; Parallel setup - SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler) - xor ax, ax - mov ds, ax - xor bx, bx - mov cl, #0x14 ; timeout value - mov dx, #0x378 ; Parallel I/O address, port 1 - call detect_parport - mov dx, #0x278 ; Parallel I/O address, port 2 - call detect_parport - shl bx, #0x0e - mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports - and ax, #0x3fff - or ax, bx ; set number of parallel ports - mov 0x410, ax - - ;; Serial setup - SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler) - SET_INT_VECTOR(0x14, #0xF000, #int14_handler) - xor bx, bx - mov cl, #0x0a ; timeout value - mov dx, #0x03f8 ; Serial I/O address, port 1 - call detect_serial - mov dx, #0x02f8 ; Serial I/O address, port 2 - call detect_serial - mov dx, #0x03e8 ; Serial I/O address, port 3 - call detect_serial - mov dx, #0x02e8 ; Serial I/O address, port 4 - call detect_serial - shl bx, #0x09 - mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports - and ax, #0xf1ff - or ax, bx ; set number of serial port - mov 0x410, ax - - ;; CMOS RTC - SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler) - SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler) - SET_INT_VECTOR(0x70, #0xF000, #int70_handler) - ;; BIOS DATA AREA 0x4CE ??? - call timer_tick_post - - ;; PS/2 mouse setup - SET_INT_VECTOR(0x74, #0xF000, #int74_handler) - - ;; IRQ13 (FPU exception) setup - SET_INT_VECTOR(0x75, #0xF000, #int75_handler) - - ;; Video setup - SET_INT_VECTOR(0x10, #0xF000, #int10_handler) - - ;; PIC +post_init_pic: mov al, #0x11 ; send initialisation commands out 0x20, al out 0xa0, al @@ -10065,6 +10683,329 @@ post_default_ints: mov al, #0x9f #endif out 0xa1, AL ;slave pic: unmask IRQ 12, 13, 14 + ret + +;; the following area can be used to write dynamically generated tables + .align 16 +bios_table_area_start: + dd 0xaafb4442 + dd bios_table_area_end - bios_table_area_start - 8; + +;-------- +;- POST - +;-------- +.org 0xe05b ; POST Entry Point +post: + + xor ax, ax + + ;; first reset the DMA controllers + out 0x0d,al + out 0xda,al + + ;; then initialize the DMA controllers + mov al, #0xC0 + out 0xD6, al ; cascade mode of channel 4 enabled + mov al, #0x00 + out 0xD4, al ; unmask channel 4 + + ;; Examine CMOS shutdown status. + mov AL, #0x0f + out 0x70, AL + in AL, 0x71 + + ;; backup status + mov bl, al + + ;; Reset CMOS shutdown status. + mov AL, #0x0f + out 0x70, AL ; select CMOS register Fh + mov AL, #0x00 + out 0x71, AL ; set shutdown action to normal + + ;; Examine CMOS shutdown status. + mov al, bl + + ;; 0x00, 0x09, 0x0D+ = normal startup + cmp AL, #0x00 + jz normal_post + cmp AL, #0x0d + jae normal_post + cmp AL, #0x09 + je normal_post + + ;; 0x05 = eoi + jmp via [0x40:0x67] jump + cmp al, #0x05 + je eoi_jmp_post + + ;; 0x0A = jmp via [0x40:0x67] jump + cmp al, #0x0a + je jmp_post_0x467 + + ;; 0x0B = iret via [0x40:0x67] + cmp al, #0x0b + je iret_post_0x467 + + ;; 0x0C = retf via [0x40:0x67] + cmp al, #0x0c + je retf_post_0x467 + + ;; Examine CMOS shutdown status. + ;; 0x01,0x02,0x03,0x04,0x06,0x07,0x08 = Unimplemented shutdown status. + push bx + call _shutdown_status_panic + +#if 0 + HALT(__LINE__) + ; + ;#if 0 + ; 0xb0, 0x20, /* mov al, #0x20 */ + ; 0xe6, 0x20, /* out 0x20, al ;send EOI to PIC */ + ;#endif + ; + pop es + pop ds + popa + iret +#endif + +normal_post: + ; case 0: normal startup + + cli + mov ax, #0xfffe + mov sp, ax + xor ax, ax + mov ds, ax + mov ss, ax + + ;; Save shutdown status + mov 0x04b0, bl + + cmp bl, #0xfe + jz s3_post + + ;; zero out BIOS data area (40:00..40:ff) + mov es, ax + mov cx, #0x0080 ;; 128 words + mov di, #0x0400 + cld + rep + stosw + + call _log_bios_start + + ;; set all interrupts to default handler + xor bx, bx ;; offset index + mov cx, #0x0100 ;; counter (256 interrupts) + mov ax, #dummy_iret_handler + mov dx, #0xF000 + +post_default_ints: + mov [bx], ax + add bx, #2 + mov [bx], dx + add bx, #2 + loop post_default_ints + + ;; set vector 0x79 to zero + ;; this is used by 'gardian angel' protection system + SET_INT_VECTOR(0x79, #0, #0) + + ;; base memory in K 40:13 (word) + mov ax, #BASE_MEM_IN_K + mov 0x0413, ax + + + ;; Manufacturing Test 40:12 + ;; zerod out above + + ;; Warm Boot Flag 0040:0072 + ;; value of 1234h = skip memory checks + ;; zerod out above + + + ;; Printer Services vector + SET_INT_VECTOR(0x17, #0xF000, #int17_handler) + + ;; Bootstrap failure vector + SET_INT_VECTOR(0x18, #0xF000, #int18_handler) + + ;; Bootstrap Loader vector + SET_INT_VECTOR(0x19, #0xF000, #int19_handler) + + ;; User Timer Tick vector + SET_INT_VECTOR(0x1c, #0xF000, #int1c_handler) + + ;; Memory Size Check vector + SET_INT_VECTOR(0x12, #0xF000, #int12_handler) + + ;; Equipment Configuration Check vector + SET_INT_VECTOR(0x11, #0xF000, #int11_handler) + + ;; System Services + SET_INT_VECTOR(0x15, #0xF000, #int15_handler) + + ;; EBDA setup + call ebda_post + + ;; PIT setup + SET_INT_VECTOR(0x08, #0xF000, #int08_handler) + ;; int 1C already points at dummy_iret_handler (above) + mov al, #0x34 ; timer0: binary count, 16bit count, mode 2 + out 0x43, al +#ifdef HVMASSIST + mov al, #0x0b ; #0xe90b = 20 Hz (temporary, until we fix xen/vmx support) + out 0x40, al ; lsb + mov al, #0xe9 + out 0x40, al ; msb +#else + mov al, #0x00 ; maximum count of 0000H = 18.2Hz + out 0x40, al + out 0x40, al +#endif + + ;; Keyboard + SET_INT_VECTOR(0x09, #0xF000, #int09_handler) + SET_INT_VECTOR(0x16, #0xF000, #int16_handler) + + xor ax, ax + mov ds, ax + mov 0x0417, al /* keyboard shift flags, set 1 */ + mov 0x0418, al /* keyboard shift flags, set 2 */ + mov 0x0419, al /* keyboard alt-numpad work area */ + mov 0x0471, al /* keyboard ctrl-break flag */ + mov 0x0497, al /* keyboard status flags 4 */ + mov al, #0x10 + mov 0x0496, al /* keyboard status flags 3 */ + + + /* keyboard head of buffer pointer */ + mov bx, #0x001E + mov 0x041A, bx + + /* keyboard end of buffer pointer */ + mov 0x041C, bx + + /* keyboard pointer to start of buffer */ + mov bx, #0x001E + mov 0x0480, bx + + /* keyboard pointer to end of buffer */ + mov bx, #0x003E + mov 0x0482, bx + + /* init the keyboard */ + call _keyboard_init + + ;; mov CMOS Equipment Byte to BDA Equipment Word + mov ax, 0x0410 + mov al, #0x14 + out 0x70, al + in al, 0x71 + mov 0x0410, ax + +#if BX_TCGBIOS + call tcpa_post_part1 +#endif + + ;; Parallel setup + SET_INT_VECTOR(0x0F, #0xF000, #dummy_iret_handler) + xor ax, ax + mov ds, ax + xor bx, bx + mov cl, #0x14 ; timeout value + mov dx, #0x378 ; Parallel I/O address, port 1 + call detect_parport + mov dx, #0x278 ; Parallel I/O address, port 2 + call detect_parport + shl bx, #0x0e + mov ax, 0x410 ; Equipment word bits 14..15 determing # parallel ports + and ax, #0x3fff + or ax, bx ; set number of parallel ports + mov 0x410, ax + + ;; Serial setup + SET_INT_VECTOR(0x0C, #0xF000, #dummy_iret_handler) + SET_INT_VECTOR(0x14, #0xF000, #int14_handler) + xor bx, bx + mov cl, #0x0a ; timeout value + mov dx, #0x03f8 ; Serial I/O address, port 1 + call detect_serial + mov dx, #0x02f8 ; Serial I/O address, port 2 + call detect_serial + mov dx, #0x03e8 ; Serial I/O address, port 3 + call detect_serial + mov dx, #0x02e8 ; Serial I/O address, port 4 + call detect_serial + shl bx, #0x09 + mov ax, 0x410 ; Equipment word bits 9..11 determing # serial ports + and ax, #0xf1ff + or ax, bx ; set number of serial port + mov 0x410, ax + + ;; CMOS RTC + SET_INT_VECTOR(0x1A, #0xF000, #int1a_handler) + SET_INT_VECTOR(0x4A, #0xF000, #dummy_iret_handler) + SET_INT_VECTOR(0x70, #0xF000, #int70_handler) + ;; BIOS DATA AREA 0x4CE ??? + call timer_tick_post + + ;; PS/2 mouse setup + SET_INT_VECTOR(0x74, #0xF000, #int74_handler) + + ;; IRQ13 (FPU exception) setup + SET_INT_VECTOR(0x75, #0xF000, #int75_handler) + + ;; Video setup + SET_INT_VECTOR(0x10, #0xF000, #int10_handler) + + ;; PIC + call post_init_pic + + mov cx, #0xc000 ;; init vga bios + mov ax, #0xc780 + call rom_scan + + call _print_bios_banner + +#if BX_ROMBIOS32 + call rombios32_init +#else +#if BX_PCIBIOS + call pcibios_init_iomem_bases + call pcibios_init_irqs +#endif //BX_PCIBIOS +#endif + + ;; + ;; Floppy setup + ;; + call floppy_drive_post + + ;; + ;; Hard Drive setup + ;; + call hard_drive_post + +#if BX_USE_ATADRV + + ;; + ;; ATA/ATAPI driver setup + ;; + call _ata_init + call _ata_detect + ;; + +#endif // BX_USE_ATADRV + +#if BX_ELTORITO_BOOT + ;; + ;; eltorito floppy/harddisk emulation from cd + ;; + call _cdemu_init + ;; +#endif // BX_ELTORITO_BOOT #ifdef HVMASSIST call _enable_rom_write_access @@ -10076,52 +11017,19 @@ post_default_ints: call _init_boot_vectors + mov cx, #0xc800 ;; init option roms + mov ax, #0xe000 call rom_scan - call _print_bios_banner - - ;; - ;; Floppy setup - ;; - call floppy_drive_post - -#if BX_USE_ATADRV - - ;; - ;; Hard Drive setup - ;; - call hard_drive_post - - ;; - ;; ATA/ATAPI driver setup - ;; - call _ata_init - call _ata_detect - ;; -#else // BX_USE_ATADRV - - ;; - ;; Hard Drive setup - ;; - call hard_drive_post - -#endif // BX_USE_ATADRV - #if BX_ELTORITO_BOOT - ;; - ;; eltorito floppy/harddisk emulation from cd - ;; - call _cdemu_init - ;; + call _interactive_bootkey #endif // BX_ELTORITO_BOOT - - call _s3_resume - call _interactive_bootkey #if BX_TCGBIOS call tcpa_post_part2 #endif + sti ;; enable interrupts ;; Start the boot sequence. See the comments in int19_relocated ;; for why we use INT 18h instead of INT 19h here. int #0x18 @@ -10134,7 +11042,7 @@ nmi: iret int75_handler: - out 0xf0, al // clear irq13 + out 0xf0, al // clear irq13 call eoi_both_pics // clear interrupt int 2 // legacy nmi call iret @@ -10233,7 +11141,7 @@ int14_handler: int14_handler: push ds pusha - mov ax, #0x0000 + xor ax, ax mov ds, ax call _int14_function popa @@ -10338,26 +11246,7 @@ int09_handler: jz int09_finish in al, #0x60 ;;read key from keyboard controller - //test al, #0x80 ;;look for key release - //jnz int09_process_key ;; dont pass releases to intercept? - - ;; check for extended key - cmp al, #0xe0 - jne int09_call_int15_4f - - push ds - xor ax, ax - mov ds, ax - mov al, BYTE [0x496] ;; mf2_state |= 0x01 - or al, #0x01 - mov BYTE [0x496], al - pop ds - - in al, #0x60 ;;read another key from keyboard controller - sti - -int09_call_int15_4f: push ds pusha #ifdef BX_CALL_INT15_4F @@ -10367,8 +11256,27 @@ int09_call_int15_4f: jnc int09_done #endif - -//int09_process_key: + ;; check for extended key + cmp al, #0xe0 + jne int09_check_pause + xor ax, ax + mov ds, ax + mov al, BYTE [0x496] ;; mf2_state |= 0x02 + or al, #0x02 + mov BYTE [0x496], al + jmp int09_done + +int09_check_pause: ;; check for pause key + cmp al, #0xe1 + jne int09_process_key + xor ax, ax + mov ds, ax + mov al, BYTE [0x496] ;; mf2_state |= 0x01 + or al, #0x01 + mov BYTE [0x496], al + jmp int09_done + +int09_process_key: mov bx, #0xf000 mov ds, bx call _int09_function @@ -10384,8 +11292,6 @@ int09_finish: out #0x64, al pop ax iret - - ;---------------------------------------- @@ -10426,7 +11332,7 @@ int0e_loop2: je int0e_loop2 int0e_normal: push ds - mov ax, #0x0000 ;; segment 0000 + xor ax, ax ;; segment 0000 mov ds, ax call eoi_master_pic mov al, 0x043e @@ -10463,7 +11369,7 @@ int17_handler: int17_handler: push ds pusha - mov ax, #0x0000 + xor ax, ax mov ds, ax call _int17_function popa @@ -10653,11 +11559,11 @@ int1a_callfunction: ;; int70_handler: push ds - pusha + pushad xor ax, ax mov ds, ax call _int70_function - popa + popad pop ds iret @@ -10715,7 +11621,7 @@ int08_store_ticks: .org 0xff00 -.ascii "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team." +.ascii BIOS_COPYRIGHT_STRING ;------------------------------------------------ ;- IRET Instruction for Dummy Interrupt Handler - @@ -10737,7 +11643,7 @@ dummy_iret_handler: #ifdef HVMTEST jmp 0xd000:0x0003; #else - jmp 0xf000:post + jmp 0xf000:post #endif .org 0xfff5 ; ASCII Date ROM was built - 8 characters in MM/DD/YY @@ -10750,10 +11656,10 @@ db 0x00 ; filler .org 0xfa6e ;; Character Font for 320x200 & 640x200 Graphics (lower 128 characters) ASM_END /* - * This font comes from the fntcol16.zip package (c) by Joseph Gil + * This font comes from the fntcol16.zip package (c) by Joseph Gil * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip * This font is public domain - */ + */ static Bit8u vgafont8[128*8]= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -10929,328 +11835,10 @@ db 0,0,0,0,0,0,0 ; 31 bytes db 0,0,0,0,0,0,0 ; 31 bytes ASM_END -#else // !HVMASSIST - +#endif // HVMASSIST ASM_START -.org 0xcc00 +.org 0xcff0 +bios_table_area_end: // bcc-generated data will be placed here - -// For documentation of this config structure, look on developer.intel.com and -// search for multiprocessor specification. Note that when you change anything -// you must update the checksum (a pain!). It would be better to construct this -// with C structures, or at least fill in the checksum automatically. -// -// Maybe this structs could be moved elsewhere than d000 - -#if (BX_SMP_PROCESSORS==1) - // no structure necessary. -#elif (BX_SMP_PROCESSORS==2) -// define the Intel MP Configuration Structure for 2 processors at -// APIC ID 0,1. I/O APIC at ID=2. -.align 16 -mp_config_table: - db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature - dw (mp_config_end-mp_config_table) ;; table length - db 4 ;; spec rev - db 0x65 ;; checksum - .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" - db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " - db 0x20, 0x20, 0x20, 0x20 - db 0x20, 0x20, 0x20, 0x20 - dw 0,0 ;; oem table ptr - dw 0 ;; oem table size - dw 20 ;; entry count - dw 0x0000, 0xfee0 ;; memory mapped address of local APIC - dw 0 ;; extended table length - db 0 ;; extended table checksum - db 0 ;; reserved -mp_config_proc0: - db 0 ;; entry type=processor - db 0 ;; local APIC id - db 0x11 ;; local APIC version number - db 3 ;; cpu flags: enabled, bootstrap processor - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc1: - db 0 ;; entry type=processor - db 1 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_isa_bus: - db 1 ;; entry type=bus - db 0 ;; bus ID - db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " -mp_config_ioapic: - db 2 ;; entry type=I/O APIC - db 2 ;; apic id=2. linux will set. - db 0x11 ;; I/O APIC version number - db 1 ;; flags=1=enabled - dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC -mp_config_irqs: - db 3 ;; entry type=I/O interrupt - db 0 ;; interrupt type=vectored interrupt - db 0,0 ;; flags po=0, el=0 (linux uses as default) - db 0 ;; source bus ID is ISA - db 0 ;; source bus IRQ - db 2 ;; destination I/O APIC ID - db 0 ;; destination I/O APIC interrrupt in - ;; repeat pattern for interrupts 0-15 - db 3,0,0,0,0,1,2,1 - db 3,0,0,0,0,2,2,2 - db 3,0,0,0,0,3,2,3 - db 3,0,0,0,0,4,2,4 - db 3,0,0,0,0,5,2,5 - db 3,0,0,0,0,6,2,6 - db 3,0,0,0,0,7,2,7 - db 3,0,0,0,0,8,2,8 - db 3,0,0,0,0,9,2,9 - db 3,0,0,0,0,10,2,10 - db 3,0,0,0,0,11,2,11 - db 3,0,0,0,0,12,2,12 - db 3,0,0,0,0,13,2,13 - db 3,0,0,0,0,14,2,14 - db 3,0,0,0,0,15,2,15 -#elif (BX_SMP_PROCESSORS==4) -// define the Intel MP Configuration Structure for 4 processors at -// APIC ID 0,1,2,3. I/O APIC at ID=4. -.align 16 -mp_config_table: - db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature - dw (mp_config_end-mp_config_table) ;; table length - db 4 ;; spec rev - db 0xdd ;; checksum - .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" - db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " - db 0x20, 0x20, 0x20, 0x20 - db 0x20, 0x20, 0x20, 0x20 - dw 0,0 ;; oem table ptr - dw 0 ;; oem table size - dw 22 ;; entry count - dw 0x0000, 0xfee0 ;; memory mapped address of local APIC - dw 0 ;; extended table length - db 0 ;; extended table checksum - db 0 ;; reserved -mp_config_proc0: - db 0 ;; entry type=processor - db 0 ;; local APIC id - db 0x11 ;; local APIC version number - db 3 ;; cpu flags: enabled, bootstrap processor - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc1: - db 0 ;; entry type=processor - db 1 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc2: - db 0 ;; entry type=processor - db 2 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc3: - db 0 ;; entry type=processor - db 3 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_isa_bus: - db 1 ;; entry type=bus - db 0 ;; bus ID - db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " -mp_config_ioapic: - db 2 ;; entry type=I/O APIC - db 4 ;; apic id=4. linux will set. - db 0x11 ;; I/O APIC version number - db 1 ;; flags=1=enabled - dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC -mp_config_irqs: - db 3 ;; entry type=I/O interrupt - db 0 ;; interrupt type=vectored interrupt - db 0,0 ;; flags po=0, el=0 (linux uses as default) - db 0 ;; source bus ID is ISA - db 0 ;; source bus IRQ - db 4 ;; destination I/O APIC ID - db 0 ;; destination I/O APIC interrrupt in - ;; repeat pattern for interrupts 0-15 - db 3,0,0,0,0,1,4,1 - db 3,0,0,0,0,2,4,2 - db 3,0,0,0,0,3,4,3 - db 3,0,0,0,0,4,4,4 - db 3,0,0,0,0,5,4,5 - db 3,0,0,0,0,6,4,6 - db 3,0,0,0,0,7,4,7 - db 3,0,0,0,0,8,4,8 - db 3,0,0,0,0,9,4,9 - db 3,0,0,0,0,10,4,10 - db 3,0,0,0,0,11,4,11 - db 3,0,0,0,0,12,4,12 - db 3,0,0,0,0,13,4,13 - db 3,0,0,0,0,14,4,14 - db 3,0,0,0,0,15,4,15 -#elif (BX_SMP_PROCESSORS==8) -// define the Intel MP Configuration Structure for 8 processors at -// APIC ID 0,1,2,3,4,5,6,7. I/O APIC at ID=8. -.align 16 -mp_config_table: - db 0x50, 0x43, 0x4d, 0x50 ;; "PCMP" signature - dw (mp_config_end-mp_config_table) ;; table length - db 4 ;; spec rev - db 0xc3 ;; checksum - .ascii "BOCHSCPU" ;; OEM id = "BOCHSCPU" - db 0x30, 0x2e, 0x31, 0x20 ;; vendor id = "0.1 " - db 0x20, 0x20, 0x20, 0x20 - db 0x20, 0x20, 0x20, 0x20 - dw 0,0 ;; oem table ptr - dw 0 ;; oem table size - dw 26 ;; entry count - dw 0x0000, 0xfee0 ;; memory mapped address of local APIC - dw 0 ;; extended table length - db 0 ;; extended table checksum - db 0 ;; reserved -mp_config_proc0: - db 0 ;; entry type=processor - db 0 ;; local APIC id - db 0x11 ;; local APIC version number - db 3 ;; cpu flags: enabled, bootstrap processor - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc1: - db 0 ;; entry type=processor - db 1 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc2: - db 0 ;; entry type=processor - db 2 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc3: - db 0 ;; entry type=processor - db 3 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc4: - db 0 ;; entry type=processor - db 4 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc5: - db 0 ;; entry type=processor - db 5 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc6: - db 0 ;; entry type=processor - db 6 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_proc7: - db 0 ;; entry type=processor - db 7 ;; local APIC id - db 0x11 ;; local APIC version number - db 1 ;; cpu flags: enabled - db 0,6,0,0 ;; cpu signature - dw 0x201,0 ;; feature flags - dw 0,0 ;; reserved - dw 0,0 ;; reserved -mp_config_isa_bus: - db 1 ;; entry type=bus - db 0 ;; bus ID - db 0x49, 0x53, 0x41, 0x20, 0x20, 0x20 ;; bus type="ISA " -mp_config_ioapic: - db 2 ;; entry type=I/O APIC - db 8 ;; apic id=8 - db 0x11 ;; I/O APIC version number - db 1 ;; flags=1=enabled - dw 0x0000, 0xfec0 ;; memory mapped address of I/O APIC -mp_config_irqs: - db 3 ;; entry type=I/O interrupt - db 0 ;; interrupt type=vectored interrupt - db 0,0 ;; flags po=0, el=0 (linux uses as default) - db 0 ;; source bus ID is ISA - db 0 ;; source bus IRQ - db 8 ;; destination I/O APIC ID - db 0 ;; destination I/O APIC interrrupt in - ;; repeat pattern for interrupts 0-15 - db 3,0,0,0,0,1,8,1 - db 3,0,0,0,0,2,8,2 - db 3,0,0,0,0,3,8,3 - db 3,0,0,0,0,4,8,4 - db 3,0,0,0,0,5,8,5 - db 3,0,0,0,0,6,8,6 - db 3,0,0,0,0,7,8,7 - db 3,0,0,0,0,8,8,8 - db 3,0,0,0,0,9,8,9 - db 3,0,0,0,0,10,8,10 - db 3,0,0,0,0,11,8,11 - db 3,0,0,0,0,12,8,12 - db 3,0,0,0,0,13,8,13 - db 3,0,0,0,0,14,8,14 - db 3,0,0,0,0,15,8,15 -#else -# error Sorry, rombios only has configurations for 1, 2, 4 or 8 processors. -#endif // if (BX_SMP_PROCESSORS==...) - -mp_config_end: // this label used to find length of mp structure - db 0 - -#if (BX_SMP_PROCESSORS>1) -.align 16 -mp_floating_pointer_structure: -db 0x5f, 0x4d, 0x50, 0x5f ; "_MP_" signature -dw mp_config_table, 0xf ;; pointer to MP configuration table -db 1 ;; length of this struct in 16-bit byte chunks -db 4 ;; MP spec revision -db 0xc1 ;; checksum -db 0 ;; MP feature byte 1. value 0 means look at the config table -db 0,0,0,0 ;; MP feature bytes 2-5. -#endif - ASM_END -#endif // HVMASSIST diff -r 9837303a4708 -r 07f26e047fbf tools/firmware/rombios/rombios.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/firmware/rombios/rombios.h Wed Dec 24 12:52:34 2008 +0900 @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: rombios.h,v 1.8 2008/12/04 18:48:33 sshwarts Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2006 Volker Ruppert +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +/* define it to include QEMU specific code */ +//#define BX_QEMU +#define LEGACY + +#ifndef LEGACY +# define BX_ROMBIOS32 1 +#else +# define BX_ROMBIOS32 0 +#endif +#define DEBUG_ROMBIOS 1 + +#define PANIC_PORT 0x400 +#define PANIC_PORT2 0x401 +#define INFO_PORT 0x402 +#define DEBUG_PORT 0x403 + +#define BIOS_PRINTF_HALT 1 +#define BIOS_PRINTF_SCREEN 2 +#define BIOS_PRINTF_INFO 4 +#define BIOS_PRINTF_DEBUG 8 +#define BIOS_PRINTF_ALL (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO) +#define BIOS_PRINTF_DEBHALT (BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO | BIOS_PRINTF_HALT) + +#define printf(format, p...) bios_printf(BIOS_PRINTF_SCREEN, format, ##p) + +// Defines the output macros. +// BX_DEBUG goes to INFO port until we can easily choose debug info on a +// per-device basis. Debug info are sent only in debug mode +#if DEBUG_ROMBIOS +# define BX_DEBUG(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) +#else +# define BX_DEBUG(format, p...) +#endif +#define BX_INFO(format, p...) bios_printf(BIOS_PRINTF_INFO, format, ##p) +#define BX_PANIC(format, p...) bios_printf(BIOS_PRINTF_DEBHALT, format, ##p) + +#define ACPI_DATA_SIZE 0x00010000L +#define PM_IO_BASE 0xb000 +#define SMB_IO_BASE 0xb100 + + // Define the application NAME +#if define HVMASSIST +# define BX_APPNAME "HVMAssist" +#elif defined(BX_QEMU) +# define BX_APPNAME "QEMU" +#elif defined(PLEX86) +# define BX_APPNAME "Plex86" +#else +# define BX_APPNAME "Bochs" +#endif diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_dom_core.c --- a/tools/libxc/xc_dom_core.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_dom_core.c Wed Dec 24 12:52:34 2008 +0900 @@ -244,6 +244,7 @@ int xc_dom_do_gunzip(void *src, size_t s return -1; } rc = inflate(&zStream, Z_FINISH); + inflateEnd(&zStream); if ( rc != Z_STREAM_END ) { xc_dom_panic(XC_INTERNAL_ERROR, diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_dom_x86.c --- a/tools/libxc/xc_dom_x86.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_dom_x86.c Wed Dec 24 12:52:34 2008 +0900 @@ -418,7 +418,8 @@ static int start_info_x86_32(struct xc_d xc_dom_printf("%s: called\n", __FUNCTION__); memset(start_info, 0, sizeof(*start_info)); - snprintf(start_info->magic, sizeof(start_info->magic), dom->guest_type); + strncpy(start_info->magic, dom->guest_type, sizeof(start_info->magic)); + start_info->magic[sizeof(start_info->magic) - 1] = '\0'; start_info->nr_pages = dom->total_pages; start_info->shared_info = shinfo << PAGE_SHIFT_X86; start_info->pt_base = dom->pgtables_seg.vstart; @@ -457,7 +458,8 @@ static int start_info_x86_64(struct xc_d xc_dom_printf("%s: called\n", __FUNCTION__); memset(start_info, 0, sizeof(*start_info)); - snprintf(start_info->magic, sizeof(start_info->magic), dom->guest_type); + strncpy(start_info->magic, dom->guest_type, sizeof(start_info->magic)); + start_info->magic[sizeof(start_info->magic) - 1] = '\0'; start_info->nr_pages = dom->total_pages; start_info->shared_info = shinfo << PAGE_SHIFT_X86; start_info->pt_base = dom->pgtables_seg.vstart; diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_domain.c Wed Dec 24 12:52:34 2008 +0900 @@ -1061,6 +1061,20 @@ int xc_domain_suppress_spurious_page_fau } +int xc_domain_debug_control(int xc, uint32_t domid, uint32_t sop, uint32_t vcpu) +{ + DECLARE_DOMCTL; + + memset(&domctl, 0, sizeof(domctl)); + domctl.domain = (domid_t)domid; + domctl.cmd = XEN_DOMCTL_debug_op; + domctl.u.debug_op.op = sop; + domctl.u.debug_op.vcpu = vcpu; + + return do_domctl(xc, &domctl); +} + + /* * Local variables: * mode: C diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_domain_restore.c --- a/tools/libxc/xc_domain_restore.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_domain_restore.c Wed Dec 24 12:52:34 2008 +0900 @@ -490,6 +490,22 @@ int xc_domain_restore(int xc_handle, int continue; } + if ( j == -4 ) + { + uint64_t vm86_tss; + + /* Skip padding 4 bytes then read the vm86 TSS location. */ + if ( read_exact(io_fd, &vm86_tss, sizeof(uint32_t)) || + read_exact(io_fd, &vm86_tss, sizeof(uint64_t)) ) + { + ERROR("error read the address of the vm86 TSS"); + goto out; + } + + xc_set_hvm_param(xc_handle, dom, HVM_PARAM_VM86_TSS, vm86_tss); + continue; + } + if ( j == 0 ) break; /* our work here is done */ diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_domain_save.c --- a/tools/libxc/xc_domain_save.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_domain_save.c Wed Dec 24 12:52:34 2008 +0900 @@ -1388,18 +1388,30 @@ int xc_domain_save(int xc_handle, int io if ( hvm ) { struct { - int minusthree; + int id; uint32_t pad; - uint64_t ident_pt; - } chunk = { -3, 0 }; - + uint64_t data; + } chunk = { 0, }; + + chunk.id = -3; xc_get_hvm_param(xc_handle, dom, HVM_PARAM_IDENT_PT, - (unsigned long *)&chunk.ident_pt); - - if ( (chunk.ident_pt != 0) && + (unsigned long *)&chunk.data); + + if ( (chunk.data != 0) && write_exact(io_fd, &chunk, sizeof(chunk)) ) { PERROR("Error when writing the ident_pt for EPT guest"); + goto out; + } + + chunk.id = -4; + xc_get_hvm_param(xc_handle, dom, HVM_PARAM_VM86_TSS, + (unsigned long *)&chunk.data); + + if ( (chunk.data != 0) && + write_exact(io_fd, &chunk, sizeof(chunk)) ) + { + PERROR("Error when writing the vm86 TSS for guest"); goto out; } } diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_pm.c --- a/tools/libxc/xc_pm.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_pm.c Wed Dec 24 12:52:34 2008 +0900 @@ -23,8 +23,13 @@ * */ +#include <errno.h> +#include <stdbool.h> #include "xc_private.h" +/* + * Get PM statistic info + */ int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px) { DECLARE_SYSCTL; @@ -168,3 +173,136 @@ int xc_pm_reset_cxstat(int xc_handle, in return xc_sysctl(xc_handle, &sysctl); } + + +/* + * 1. Get PM parameter + * 2. Provide user PM control + */ +int xc_get_cpufreq_para(int xc_handle, int cpuid, + struct xc_get_cpufreq_para *user_para) +{ + DECLARE_SYSCTL; + int ret = 0; + struct xen_get_cpufreq_para *sys_para = &sysctl.u.pm_op.get_para; + bool has_num = user_para->cpu_num && + user_para->freq_num && + user_para->gov_num; + + if ( (xc_handle < 0) || !user_para ) + return -EINVAL; + + if ( has_num ) + { + if ( (!user_para->affected_cpus) || + (!user_para->scaling_available_frequencies) || + (!user_para->scaling_available_governors) ) + return -EINVAL; + + if ( (ret = lock_pages(user_para->affected_cpus, + user_para->cpu_num * sizeof(uint32_t))) ) + goto unlock_1; + if ( (ret = lock_pages(user_para->scaling_available_frequencies, + user_para->freq_num * sizeof(uint32_t))) ) + goto unlock_2; + if ( (ret = lock_pages(user_para->scaling_available_governors, + user_para->gov_num * CPUFREQ_NAME_LEN * sizeof(char))) ) + goto unlock_3; + + set_xen_guest_handle(sys_para->affected_cpus, + user_para->affected_cpus); + set_xen_guest_handle(sys_para->scaling_available_frequencies, + user_para->scaling_available_frequencies); + set_xen_guest_handle(sys_para->scaling_available_governors, + user_para->scaling_available_governors); + } + + sysctl.cmd = XEN_SYSCTL_pm_op; + sysctl.u.pm_op.cmd = GET_CPUFREQ_PARA; + sysctl.u.pm_op.cpuid = cpuid; + sys_para->cpu_num = user_para->cpu_num; + sys_para->freq_num = user_para->freq_num; + sys_para->gov_num = user_para->gov_num; + + ret = xc_sysctl(xc_handle, &sysctl); + if ( ret ) + { + if ( errno == EAGAIN ) + { + user_para->cpu_num = sys_para->cpu_num; + user_para->freq_num = sys_para->freq_num; + user_para->gov_num = sys_para->gov_num; + ret = -errno; + } + + if ( has_num ) + goto unlock_4; + goto unlock_1; + } + else + { + user_para->cpuinfo_cur_freq = sys_para->cpuinfo_cur_freq; + user_para->cpuinfo_max_freq = sys_para->cpuinfo_max_freq; + user_para->cpuinfo_min_freq = sys_para->cpuinfo_min_freq; + user_para->scaling_cur_freq = sys_para->scaling_cur_freq; + user_para->scaling_max_freq = sys_para->scaling_max_freq; + user_para->scaling_min_freq = sys_para->scaling_min_freq; + + memcpy(user_para->scaling_driver, + sys_para->scaling_driver, CPUFREQ_NAME_LEN); + memcpy(user_para->scaling_governor, + sys_para->scaling_governor, CPUFREQ_NAME_LEN); + + /* copy to user_para no matter what cpufreq governor */ + XC_BUILD_BUG_ON(sizeof(((struct xc_get_cpufreq_para *)0)->u) != + sizeof(((struct xen_get_cpufreq_para *)0)->u)); + + memcpy(&user_para->u, &sys_para->u, sizeof(sys_para->u)); + } + +unlock_4: + unlock_pages(user_para->scaling_available_governors, + user_para->gov_num * CPUFREQ_NAME_LEN * sizeof(char)); +unlock_3: + unlock_pages(user_para->scaling_available_frequencies, + user_para->freq_num * sizeof(uint32_t)); +unlock_2: + unlock_pages(user_para->affected_cpus, + user_para->cpu_num * sizeof(uint32_t)); +unlock_1: + return ret; +} + +int xc_set_cpufreq_gov(int xc_handle, int cpuid, char *govname) +{ + DECLARE_SYSCTL; + char *scaling_governor = sysctl.u.pm_op.set_gov.scaling_governor; + + if ( (xc_handle < 0) || (!govname) ) + return -EINVAL; + + sysctl.cmd = XEN_SYSCTL_pm_op; + sysctl.u.pm_op.cmd = SET_CPUFREQ_GOV; + sysctl.u.pm_op.cpuid = cpuid; + strncpy(scaling_governor, govname, CPUFREQ_NAME_LEN); + scaling_governor[CPUFREQ_NAME_LEN - 1] = '\0'; + + return xc_sysctl(xc_handle, &sysctl); +} + +int xc_set_cpufreq_para(int xc_handle, int cpuid, + int ctrl_type, int ctrl_value) +{ + DECLARE_SYSCTL; + + if ( xc_handle < 0 ) + return -EINVAL; + + sysctl.cmd = XEN_SYSCTL_pm_op; + sysctl.u.pm_op.cmd = SET_CPUFREQ_PARA; + sysctl.u.pm_op.cpuid = cpuid; + sysctl.u.pm_op.set_para.ctrl_type = ctrl_type; + sysctl.u.pm_op.set_para.ctrl_value = ctrl_value; + + return xc_sysctl(xc_handle, &sysctl); +} diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_private.h --- a/tools/libxc/xc_private.h Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_private.h Wed Dec 24 12:52:34 2008 +0900 @@ -42,6 +42,9 @@ #define DEBUG 1 #define INFO 1 #define PROGRESS 0 + +/* Force a compilation error if condition is true */ +#define XC_BUILD_BUG_ON(p) ((void)sizeof(struct { int:-!!(p); })) /* ** Define max dirty page cache to permit during save/restore -- need to balance diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xc_ptrace.c --- a/tools/libxc/xc_ptrace.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xc_ptrace.c Wed Dec 24 12:52:34 2008 +0900 @@ -524,10 +524,20 @@ xc_ptrace( /* XXX we can still have problems if the user switches threads * during single-stepping - but that just seems retarded */ - ctxt[cpu].c.user_regs.eflags |= PSL_T; - if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu, - &ctxt[cpu]))) - goto out_error_domctl; + /* Try to enalbe Monitor Trap Flag for HVM, and fall back to TF + * if no MTF support + */ + if ( !current_is_hvm || + xc_domain_debug_control(xc_handle, + current_domid, + XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON, + cpu) ) + { + ctxt[cpu].c.user_regs.eflags |= PSL_T; + if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu, + &ctxt[cpu]))) + goto out_error_domctl; + } /* FALLTHROUGH */ case PTRACE_CONT: @@ -538,15 +548,22 @@ xc_ptrace( { FOREACH_CPU(cpumap, index) { cpu = index - 1; - if (fetch_regs(xc_handle, cpu, NULL)) - goto out_error; - /* Clear trace flag */ - if ( ctxt[cpu].c.user_regs.eflags & PSL_T ) + if ( !current_is_hvm || + xc_domain_debug_control(xc_handle, + current_domid, + XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF, + cpu) ) { - ctxt[cpu].c.user_regs.eflags &= ~PSL_T; - if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, - cpu, &ctxt[cpu]))) - goto out_error_domctl; + if (fetch_regs(xc_handle, cpu, NULL)) + goto out_error; + /* Clear trace flag */ + if ( ctxt[cpu].c.user_regs.eflags & PSL_T ) + { + ctxt[cpu].c.user_regs.eflags &= ~PSL_T; + if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, + cpu, &ctxt[cpu]))) + goto out_error_domctl; + } } } } diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xenctrl.h Wed Dec 24 12:52:34 2008 +0900 @@ -1111,6 +1111,12 @@ int xc_domain_set_target(int xc_handle, uint32_t domid, uint32_t target); +/* Control the domain for debug */ +int xc_domain_debug_control(int xc_handle, + uint32_t domid, + uint32_t sop, + uint32_t vcpu); + #if defined(__i386__) || defined(__x86_64__) int xc_cpuid_check(int xc, const unsigned int *input, @@ -1161,4 +1167,46 @@ int xc_pm_reset_cxstat(int xc_handle, in int xc_cpu_online(int xc_handle, int cpu); int xc_cpu_offline(int xc_handle, int cpu); + +/* + * cpufreq para name of this structure named + * same as sysfs file name of native linux + */ +typedef xen_userspace_t xc_userspace_t; +typedef xen_ondemand_t xc_ondemand_t; + +struct xc_get_cpufreq_para { + /* IN/OUT variable */ + uint32_t cpu_num; + uint32_t freq_num; + uint32_t gov_num; + + /* for all governors */ + /* OUT variable */ + uint32_t *affected_cpus; + uint32_t *scaling_available_frequencies; + char *scaling_available_governors; + char scaling_driver[CPUFREQ_NAME_LEN]; + + uint32_t cpuinfo_cur_freq; + uint32_t cpuinfo_max_freq; + uint32_t cpuinfo_min_freq; + uint32_t scaling_cur_freq; + + char scaling_governor[CPUFREQ_NAME_LEN]; + uint32_t scaling_max_freq; + uint32_t scaling_min_freq; + + /* for specific governor */ + union { + xc_userspace_t userspace; + xc_ondemand_t ondemand; + } u; +}; + +int xc_get_cpufreq_para(int xc_handle, int cpuid, + struct xc_get_cpufreq_para *user_para); +int xc_set_cpufreq_gov(int xc_handle, int cpuid, char *govname); +int xc_set_cpufreq_para(int xc_handle, int cpuid, + int ctrl_type, int ctrl_value); #endif /* XENCTRL_H */ diff -r 9837303a4708 -r 07f26e047fbf tools/libxc/xg_private.c --- a/tools/libxc/xg_private.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/libxc/xg_private.c Wed Dec 24 12:52:34 2008 +0900 @@ -131,6 +131,7 @@ char *xc_inflate_buffer(const char *in_b /* Inflate in one pass/call */ sts = inflate(&zStream, Z_FINISH); + inflateEnd(&zStream); if ( sts != Z_STREAM_END ) { ERROR("inflate failed, sts %d\n", sts); diff -r 9837303a4708 -r 07f26e047fbf tools/misc/xen-detect.c --- a/tools/misc/xen-detect.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/misc/xen-detect.c Wed Dec 24 12:52:34 2008 +0900 @@ -50,17 +50,25 @@ static int check_for_xen(void) { uint32_t eax, ebx, ecx, edx; char signature[13]; + uint32_t base; - cpuid(0x40000000, &eax, &ebx, &ecx, &edx); - *(uint32_t *)(signature + 0) = ebx; - *(uint32_t *)(signature + 4) = ecx; - *(uint32_t *)(signature + 8) = edx; - signature[12] = '\0'; + for ( base = 0x40000000; base < 0x40001000; base += 0x100 ) + { + cpuid(base, &eax, &ebx, &ecx, &edx); - if ( strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002) ) - return 0; + *(uint32_t *)(signature + 0) = ebx; + *(uint32_t *)(signature + 4) = ecx; + *(uint32_t *)(signature + 8) = edx; + signature[12] = '\0'; - cpuid(0x40000001, &eax, &ebx, &ecx, &edx); + if ( !strcmp("XenVMMXenVMM", signature) && (eax >= (base + 2)) ) + goto found; + } + + return 0; + + found: + cpuid(base + 1, &eax, &ebx, &ecx, &edx); printf("Running in %s context on Xen v%d.%d.\n", pv_context ? "PV" : "HVM", (uint16_t)(eax >> 16), (uint16_t)eax); return 1; diff -r 9837303a4708 -r 07f26e047fbf tools/misc/xenpm.c --- a/tools/misc/xenpm.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/misc/xenpm.c Wed Dec 24 12:52:34 2008 +0900 @@ -16,199 +16,591 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. */ +/* to eliminate warning on `strndup' */ +#define _GNU_SOURCE + #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <getopt.h> #include <errno.h> #include <xenctrl.h> #include <inttypes.h> -int main(int argc, char **argv) -{ +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +/* help message */ +void show_help(void) +{ + fprintf(stderr, + "Usage:\n" + " xenpm get-cpuidle-states [cpuid]: list cpu idle information on CPU cpuid or all CPUs.\n" + " xenpm get-cpufreq-states [cpuid]: list cpu frequency information on CPU cpuid or all CPUs.\n" + " xenpm get-cpufreq-para [cpuid]: list cpu frequency information on CPU cpuid or all CPUs.\n" + " xenpm set-scaling-maxfreq <cpuid> <HZ>: set max cpu frequency <HZ> on CPU <cpuid>.\n" + " xenpm set-scaling-minfreq <cpuid> <HZ>: set min cpu frequency <HZ> on CPU <cpuid>.\n" + " xenpm set-scaling-governor <cpuid> <name>: set scaling governor on CPU <cpuid>.\n" + " xenpm set-scaling-speed <cpuid> <num>: set scaling speed on CPU <cpuid>.\n" + " xenpm set-sampling-rate <cpuid> <num>: set sampling rate on CPU <cpuid>.\n" + " xenpm set-up-threshold <cpuid> <num>: set up threshold on CPU <cpuid>.\n"); +} + +/* wrapper function */ +int help_func(int xc_fd, int cpuid, uint32_t value) +{ + show_help(); + return 0; +} + +/* show cpu idle information on CPU cpuid */ +static int show_cx_cpuid(int xc_fd, int cpuid) +{ + int i, ret = 0; + int max_cx_num = 0; + struct xc_cx_stat cxstatinfo, *cxstat = &cxstatinfo; + + ret = xc_pm_get_max_cx(xc_fd, cpuid, &max_cx_num); + if ( ret ) + { + if ( errno == ENODEV ) + { + fprintf(stderr, "Xen cpuidle is not enabled!\n"); + return -ENODEV; + } + else + { + fprintf(stderr, "[CPU%d] failed to get max C-state\n", cpuid); + return -EINVAL; + } + } + + cxstat->triggers = malloc(max_cx_num * sizeof(uint64_t)); + if ( !cxstat->triggers ) + { + fprintf(stderr, "[CPU%d] failed to malloc for C-states triggers\n", cpuid); + return -ENOMEM; + } + cxstat->residencies = malloc(max_cx_num * sizeof(uint64_t)); + if ( !cxstat->residencies ) + { + fprintf(stderr, "[CPU%d] failed to malloc for C-states residencies\n", cpuid); + free(cxstat->triggers); + return -ENOMEM; + } + + ret = xc_pm_get_cxstat(xc_fd, cpuid, cxstat); + if( ret ) + { + fprintf(stderr, "[CPU%d] failed to get C-states statistics " + "information\n", cpuid); + free(cxstat->triggers); + free(cxstat->residencies); + return -EINVAL; + } + + printf("cpu id : %d\n", cpuid); + printf("total C-states : %d\n", cxstat->nr); + printf("idle time(ms) : %"PRIu64"\n", + cxstat->idle_time/1000000UL); + for ( i = 0; i < cxstat->nr; i++ ) + { + printf("C%d : transition [%020"PRIu64"]\n", + i, cxstat->triggers[i]); + printf(" residency [%020"PRIu64" ms]\n", + cxstat->residencies[i]/1000000UL); + } + + free(cxstat->triggers); + free(cxstat->residencies); + + printf("\n"); + return 0; +} + +int cxstates_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret = 0; + xc_physinfo_t physinfo = { 0 }; + + if ( cpuid < 0 ) + { + /* show cxstates on all cpu */ + ret = xc_physinfo(xc_fd, &physinfo); + if ( ret ) + { + fprintf(stderr, "failed to get the processor information\n"); + } + else + { + int i; + for ( i = 0; i < physinfo.nr_cpus; i++ ) + { + if ( (ret = show_cx_cpuid(xc_fd, i)) == -ENODEV ) + break; + } + } + } + else + ret = show_cx_cpuid(xc_fd, cpuid); + + return ret; +} + +/* show cpu frequency information on CPU cpuid */ +static int show_px_cpuid(int xc_fd, int cpuid) +{ + int i, ret = 0; + int max_px_num = 0; + struct xc_px_stat pxstatinfo, *pxstat = &pxstatinfo; + + ret = xc_pm_get_max_px(xc_fd, cpuid, &max_px_num); + if ( ret ) + { + if ( errno == ENODEV ) + { + printf("Xen cpufreq is not enabled!\n"); + return -ENODEV; + } + else + { + fprintf(stderr, "[CPU%d] failed to get max P-state\n", cpuid); + return -EINVAL; + } + } + + pxstat->trans_pt = malloc(max_px_num * max_px_num * + sizeof(uint64_t)); + if ( !pxstat->trans_pt ) + { + fprintf(stderr, "[CPU%d] failed to malloc for P-states transition table\n", cpuid); + return -ENOMEM; + } + pxstat->pt = malloc(max_px_num * sizeof(struct xc_px_val)); + if ( !pxstat->pt ) + { + fprintf(stderr, "[CPU%d] failed to malloc for P-states table\n", cpuid); + free(pxstat->trans_pt); + return -ENOMEM; + } + + ret = xc_pm_get_pxstat(xc_fd, cpuid, pxstat); + if( ret ) + { + fprintf(stderr, "[CPU%d] failed to get P-states statistics information\n", cpuid); + free(pxstat->trans_pt); + free(pxstat->pt); + return -ENOMEM; + } + + printf("cpu id : %d\n", cpuid); + printf("total P-states : %d\n", pxstat->total); + printf("usable P-states : %d\n", pxstat->usable); + printf("current frequency : %"PRIu64" MHz\n", + pxstat->pt[pxstat->cur].freq); + for ( i = 0; i < pxstat->total; i++ ) + { + if ( pxstat->cur == i ) + printf("*P%d", i); + else + printf("P%d ", i); + printf(" : freq [%04"PRIu64" MHz]\n", + pxstat->pt[i].freq); + printf(" transition [%020"PRIu64"]\n", + pxstat->pt[i].count); + printf(" residency [%020"PRIu64" ms]\n", + pxstat->pt[i].residency/1000000UL); + } + + free(pxstat->trans_pt); + free(pxstat->pt); + + printf("\n"); + return 0; +} + +int pxstates_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret = 0; + xc_physinfo_t physinfo = { 0 }; + + if ( cpuid < 0 ) + { + ret = xc_physinfo(xc_fd, &physinfo); + if ( ret ) + { + fprintf(stderr, "failed to get the processor information\n"); + } + else + { + int i; + for ( i = 0; i < physinfo.nr_cpus; i++ ) + { + if ( (ret = show_px_cpuid(xc_fd, i)) == -ENODEV ) + break; + } + } + } + else + ret = show_px_cpuid(xc_fd, cpuid); + + return ret; +} + +/* print out parameters about cpu frequency */ +static void print_cpufreq_para(int cpuid, struct xc_get_cpufreq_para *p_cpufreq) +{ + int i; + + printf("cpu id : %d\n", cpuid); + + printf("affected_cpus :"); + for ( i = 0; i < p_cpufreq->cpu_num; i++ ) + if ( i == cpuid ) + printf(" *%d", p_cpufreq->affected_cpus[i]); + else + printf(" %d", p_cpufreq->affected_cpus[i]); + printf("\n"); + + printf("cpuinfo frequency : max [%u] min [%u] cur [%u]\n", + p_cpufreq->cpuinfo_max_freq, + p_cpufreq->cpuinfo_min_freq, + p_cpufreq->cpuinfo_cur_freq); + + printf("scaling_driver : %s\n", p_cpufreq->scaling_driver); + + printf("scaling_avail_gov : %s\n", + p_cpufreq->scaling_available_governors); + + printf("current_governor : %s\n", p_cpufreq->scaling_governor); + if ( !strncmp(p_cpufreq->scaling_governor, + "userspace", CPUFREQ_NAME_LEN) ) + { + printf(" userspace specific :\n"); + printf(" scaling_setspeed : %u\n", + p_cpufreq->u.userspace.scaling_setspeed); + } + else if ( !strncmp(p_cpufreq->scaling_governor, + "ondemand", CPUFREQ_NAME_LEN) ) + { + printf(" ondemand specific :\n"); + printf(" sampling_rate : max [%u] min [%u] cur [%u]\n", + p_cpufreq->u.ondemand.sampling_rate_max, + p_cpufreq->u.ondemand.sampling_rate_min, + p_cpufreq->u.ondemand.sampling_rate); + printf(" up_threshold : %u\n", + p_cpufreq->u.ondemand.up_threshold); + } + + printf("scaling_avail_freq :"); + for ( i = 0; i < p_cpufreq->freq_num; i++ ) + if ( p_cpufreq->scaling_available_frequencies[i] == p_cpufreq->scaling_cur_freq ) + printf(" *%d", p_cpufreq->scaling_available_frequencies[i]); + else + printf(" %d", p_cpufreq->scaling_available_frequencies[i]); + printf("\n"); + + printf("scaling frequency : max [%u] min [%u] cur [%u]\n", + p_cpufreq->scaling_max_freq, + p_cpufreq->scaling_min_freq, + p_cpufreq->scaling_cur_freq); + printf("\n"); +} + +/* show cpu frequency parameters information on CPU cpuid */ +static int show_cpufreq_para_cpuid(int xc_fd, int cpuid) +{ + int ret = 0; + struct xc_get_cpufreq_para cpufreq_para, *p_cpufreq = &cpufreq_para; + + p_cpufreq->cpu_num = 0; + p_cpufreq->freq_num = 0; + p_cpufreq->gov_num = 0; + p_cpufreq->affected_cpus = NULL; + p_cpufreq->scaling_available_frequencies = NULL; + p_cpufreq->scaling_available_governors = NULL; + + do + { + free(p_cpufreq->affected_cpus); + free(p_cpufreq->scaling_available_frequencies); + free(p_cpufreq->scaling_available_governors); + + p_cpufreq->affected_cpus = NULL; + p_cpufreq->scaling_available_frequencies = NULL; + p_cpufreq->scaling_available_governors = NULL; + + if (!(p_cpufreq->affected_cpus = + malloc(p_cpufreq->cpu_num * sizeof(uint32_t)))) + { + fprintf(stderr, + "[CPU%d] failed to malloc for affected_cpus\n", + cpuid); + ret = -ENOMEM; + goto out; + } + if (!(p_cpufreq->scaling_available_frequencies = + malloc(p_cpufreq->freq_num * sizeof(uint32_t)))) + { + fprintf(stderr, + "[CPU%d] failed to malloc for scaling_available_frequencies\n", + cpuid); + ret = -ENOMEM; + goto out; + } + if (!(p_cpufreq->scaling_available_governors = + malloc(p_cpufreq->gov_num * CPUFREQ_NAME_LEN * sizeof(char)))) + { + fprintf(stderr, + "[CPU%d] failed to malloc for scaling_available_governors\n", + cpuid); + ret = -ENOMEM; + goto out; + } + + ret = xc_get_cpufreq_para(xc_fd, cpuid, p_cpufreq); + } while ( ret && errno == EAGAIN ); + + if ( ret == 0 ) + print_cpufreq_para(cpuid, p_cpufreq); + else if ( errno == ENODEV ) + { + ret = -ENODEV; + fprintf(stderr, "Xen cpufreq is not enabled!\n"); + } + else + fprintf(stderr, + "[CPU%d] failed to get cpufreq parameter\n", + cpuid); + +out: + free(p_cpufreq->scaling_available_governors); + free(p_cpufreq->scaling_available_frequencies); + free(p_cpufreq->affected_cpus); + + return ret; +} + +int cpufreq_para_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret = 0; + xc_physinfo_t physinfo = { 0 }; + + if ( cpuid < 0 ) + { + ret = xc_physinfo(xc_fd, &physinfo); + if ( ret ) + { + fprintf(stderr, "failed to get the processor information\n"); + } + else + { + int i; + for ( i = 0; i < physinfo.nr_cpus; i++ ) + { + if ( (ret = show_cpufreq_para_cpuid(xc_fd, i)) == -ENODEV ) + break; + } + } + } + else + ret = show_cpufreq_para_cpuid(xc_fd, cpuid); + + return ret; +} + +int scaling_max_freq_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret = 0; + + if ( cpuid < 0 ) + { + show_help(); + return -EINVAL; + } + + ret = xc_set_cpufreq_para(xc_fd, cpuid, SCALING_MAX_FREQ, value); + if ( ret ) + { + fprintf(stderr, "[CPU%d] failed to set scaling max freq\n", cpuid); + } + + return ret; +} + +int scaling_min_freq_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret; + + if ( cpuid < 0 ) + { + show_help(); + return -EINVAL; + } + + ret = xc_set_cpufreq_para(xc_fd, cpuid, SCALING_MIN_FREQ, value); + if ( ret ) + { + fprintf(stderr, "[CPU%d] failed to set scaling min freq\n", cpuid); + } + + return ret; +} + +int scaling_speed_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret; + + if ( cpuid < 0 ) + { + show_help(); + return -EINVAL; + } + + ret = xc_set_cpufreq_para(xc_fd, cpuid, SCALING_SETSPEED, value); + if ( ret ) + { + fprintf(stderr, "[CPU%d] failed to set scaling speed\n", cpuid); + } + + return ret; +} + +int scaling_sampling_rate_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret; + + if ( cpuid < 0 ) + { + show_help(); + return -EINVAL; + } + + ret = xc_set_cpufreq_para(xc_fd, cpuid, SAMPLING_RATE, value); + if ( ret ) + { + fprintf(stderr, "[CPU%d] failed to set scaling sampling rate\n", cpuid); + } + + return ret; +} + +int scaling_up_threshold_func(int xc_fd, int cpuid, uint32_t value) +{ + int ret; + + if ( cpuid < 0 ) + { + show_help(); + return -EINVAL; + } + + ret = xc_set_cpufreq_para(xc_fd, cpuid, UP_THRESHOLD, value); + if ( ret ) + { + fprintf(stderr, "[CPU%d] failed to set scaling threshold\n", cpuid); + } + + return ret; +} + +int scaling_governor_func(int xc_fd, int cpuid, char *name) +{ + int ret = 0; + + if ( cpuid < 0 ) + { + show_help(); + return -EINVAL; + } + + ret = xc_set_cpufreq_gov(xc_fd, cpuid, name); + if ( ret ) + { + fprintf(stderr, "failed to set cpufreq governor to %s\n", name); + } + + return ret; +} + +struct { + const char *name; + int (*function)(int xc_fd, int cpuid, uint32_t value); +} main_options[] = { + { "help", help_func }, + { "get-cpuidle-states", cxstates_func }, + { "get-cpufreq-states", pxstates_func }, + { "get-cpufreq-para", cpufreq_para_func }, + { "set-scaling-maxfreq", scaling_max_freq_func }, + { "set-scaling-minfreq", scaling_min_freq_func }, + { "set-scaling-governor", NULL }, + { "set-scaling-speed", scaling_speed_func }, + { "set-sampling-rate", scaling_sampling_rate_func }, + { "set-up-threshold", scaling_up_threshold_func }, +}; + +int main(int argc, char *argv[]) +{ + int i, ret = -EINVAL; int xc_fd; - int i, j, ret = 0; - int cinfo = 0, pinfo = 0; - int ch; - xc_physinfo_t physinfo = { 0 }; - - while ( (ch = getopt(argc, argv, "cp")) != -1 ) - { - switch ( ch ) - { - case 'c': - cinfo = 1; - break; - case 'p': - pinfo = 1; - break; - default: - fprintf(stderr, "%s [-p] [-c]\n", argv[0]); - return -1; - } - } - - if ( !cinfo && !pinfo ) - { - cinfo = 1; - pinfo = 1; + int cpuid = -1; + uint32_t value = 0; + int nr_matches = 0; + int matches_main_options[ARRAY_SIZE(main_options)]; + + if ( argc < 2 ) + { + show_help(); + return ret; + } + + if ( argc > 2 ) + { + if ( sscanf(argv[2], "%d", &cpuid) != 1 ) + cpuid = -1; } xc_fd = xc_interface_open(); if ( xc_fd < 0 ) { fprintf(stderr, "failed to get the handler\n"); - return xc_fd; - } - - ret = xc_physinfo(xc_fd, &physinfo); - if ( ret ) - { - fprintf(stderr, "failed to get the processor information\n"); - xc_interface_close(xc_fd); - return ret; - } - - /* print out the C state information */ - if ( cinfo ) - { - int max_cx_num = 0; - struct xc_cx_stat cxstatinfo, *cxstat = &cxstatinfo; - - for ( i = 0; i < physinfo.nr_cpus; i++ ) - { - ret = xc_pm_get_max_cx(xc_fd, i, &max_cx_num); - if ( ret ) + } + + for ( i = 0; i < ARRAY_SIZE(main_options); i++ ) + { + if ( !strncmp(main_options[i].name, argv[1], strlen(argv[1])) ) + { + matches_main_options[nr_matches++] = i; + } + } + + if ( nr_matches > 1 ) + { + fprintf(stderr, "Ambigious options: "); + for ( i = 0; i < nr_matches; i++ ) + fprintf(stderr, " %s", main_options[matches_main_options[i]].name); + fprintf(stderr, "\n"); + } + else if ( nr_matches == 1 ) + { + if ( !strcmp("set-scaling-governor", main_options[matches_main_options[0]].name) ) + { + char *name = strdup(argv[3]); + ret = scaling_governor_func(xc_fd, cpuid, name); + free(name); + } + else + { + if ( argc > 3 ) { - if ( errno == ENODEV ) - { - fprintf(stderr, "Xen cpuidle is not enabled!\n"); - break; - } - else - { - fprintf(stderr, "[CPU%d] failed to get max C-state\n", i); - continue; - } + if ( sscanf(argv[3], "%d", &value) != 1 ) + value = 0; } - - cxstat->triggers = malloc(max_cx_num * sizeof(uint64_t)); - if ( !cxstat->triggers ) - { - fprintf(stderr, "failed to malloc for C-states triggers\n"); - break; - } - cxstat->residencies = malloc(max_cx_num * sizeof(uint64_t)); - if ( !cxstat->residencies ) - { - fprintf(stderr, "failed to malloc for C-states residencies\n"); - free(cxstat->triggers); - break; - } - - ret = xc_pm_get_cxstat(xc_fd, i, cxstat); - if( ret ) - { - fprintf(stderr, "[CPU%d] failed to get C-states statistics " - "information\n", i); - free(cxstat->triggers); - free(cxstat->residencies); - continue; - } - - printf("cpu id : %d\n", i); - printf("total C-states : %d\n", cxstat->nr); - printf("idle time(ms) : %"PRIu64"\n", - cxstat->idle_time/1000000UL); - for ( j = 0; j < cxstat->nr; j++ ) - { - printf("C%d : transition [%020"PRIu64"]\n", - j, cxstat->triggers[j]); - printf(" residency [%020"PRIu64" ms]\n", - cxstat->residencies[j]*1000000UL/3579/1000000UL); - } - - free(cxstat->triggers); - free(cxstat->residencies); - - printf("\n"); - } - } - - /* print out P state information */ - if ( pinfo ) - { - int max_px_num = 0; - struct xc_px_stat pxstatinfo, *pxstat = &pxstatinfo; - - for ( i = 0; i < physinfo.nr_cpus; i++ ) - { - ret = xc_pm_get_max_px(xc_fd, i, &max_px_num); - if ( ret ) - { - if ( errno == ENODEV ) - { - printf("Xen cpufreq is not enabled!\n"); - break; - } - else - { - fprintf(stderr, "[CPU%d] failed to get max P-state\n", i); - continue; - } - } - - pxstat->trans_pt = malloc(max_px_num * max_px_num * - sizeof(uint64_t)); - if ( !pxstat->trans_pt ) - { - fprintf(stderr, "failed to malloc for P-states " - "transition table\n"); - break; - } - pxstat->pt = malloc(max_px_num * sizeof(struct xc_px_val)); - if ( !pxstat->pt ) - { - fprintf(stderr, "failed to malloc for P-states table\n"); - free(pxstat->trans_pt); - break; - } - - ret = xc_pm_get_pxstat(xc_fd, i, pxstat); - if( ret ) - { - fprintf(stderr, "[CPU%d] failed to get P-states " - "statistics information\n", i); - free(pxstat->trans_pt); - free(pxstat->pt); - continue; - } - - printf("cpu id : %d\n", i); - printf("total P-states : %d\n", pxstat->total); - printf("usable P-states : %d\n", pxstat->usable); - printf("current frequency : %"PRIu64" MHz\n", - pxstat->pt[pxstat->cur].freq); - for ( j = 0; j < pxstat->total; j++ ) - { - if ( pxstat->cur == j ) - printf("*P%d", j); - else - printf("P%d ", j); - printf(" : freq [%04"PRIu64" MHz]\n", - pxstat->pt[j].freq); - printf(" transition [%020"PRIu64"]\n", - pxstat->pt[j].count); - printf(" residency [%020"PRIu64" ms]\n", - pxstat->pt[j].residency/1000000UL); - } - - free(pxstat->trans_pt); - free(pxstat->pt); - - printf("\n"); - } - } + ret = main_options[matches_main_options[0]].function(xc_fd, cpuid, value); + } + } + else + show_help(); xc_interface_close(xc_fd); return ret; diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/lowlevel/acm/acm.c --- a/tools/python/xen/lowlevel/acm/acm.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/lowlevel/acm/acm.c Wed Dec 24 12:52:34 2008 +0900 @@ -68,6 +68,8 @@ static void *__getssid(int domid, uint32 goto out2; } else { *buflen = SSID_BUFFER_SIZE; + free(buf); + buf = NULL; goto out2; } out2: diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/lowlevel/flask/flask.c --- a/tools/python/xen/lowlevel/flask/flask.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/lowlevel/flask/flask.c Wed Dec 24 12:52:34 2008 +0900 @@ -55,6 +55,7 @@ static PyObject *pyflask_context_to_sid( xc_handle = xc_interface_open(); if (xc_handle < 0) { errno = xc_handle; + free(buf); return PyErr_SetFromErrno(xc_error_obj); } diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/lowlevel/xc/xc.c --- a/tools/python/xen/lowlevel/xc/xc.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/lowlevel/xc/xc.c Wed Dec 24 12:52:34 2008 +0900 @@ -678,19 +678,22 @@ static PyObject *pyxc_get_device_group(X if ( rc < 0 ) { - free(sdev_array); - return pyxc_error_to_exception(); + free(sdev_array); + return pyxc_error_to_exception(); } if ( !num_sdevs ) { - free(sdev_array); - return Py_BuildValue("s", ""); + free(sdev_array); + return Py_BuildValue("s", ""); } group_str = calloc(num_sdevs, sizeof(dev_str)); if (group_str == NULL) + { + free(sdev_array); return PyErr_NoMemory(); + } for ( i = 0; i < num_sdevs; i++ ) { diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/lowlevel/xs/xs.c --- a/tools/python/xen/lowlevel/xs/xs.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/lowlevel/xs/xs.c Wed Dec 24 12:52:34 2008 +0900 @@ -336,15 +336,19 @@ static PyObject *xspy_set_permissions(Xs xs_set_error(EINVAL); goto exit; } + xsperms_n = PyList_Size(perms); - xsperms = calloc(xsperms_n, sizeof(struct xs_permissions)); + /* NB. alloc +1 so we can change the owner if necessary. */ + xsperms = calloc(xsperms_n + 1, sizeof(struct xs_permissions)); if (!xsperms) { xs_set_error(ENOMEM); goto exit; } + tuple0 = PyTuple_New(0); if (!tuple0) goto exit; + for (i = 0; i < xsperms_n; i++) { /* Read/write perms. Set these. */ int p_read = 0, p_write = 0; @@ -357,6 +361,17 @@ static PyObject *xspy_set_permissions(Xs if (p_write) xsperms[i].perms |= XS_PERM_WRITE; } + + /* + * Is the caller trying to restrict access to the first specified + * domain? If so then it cannot be owner, so we force dom0 as owner. + */ + if (xsperms_n && xsperms[0].perms && xsperms[0].id) { + memmove(&xsperms[1], &xsperms[0], xsperms_n * sizeof(*xsperms)); + xsperms[0].id = xsperms[0].perms = 0; + xsperms_n++; + } + Py_BEGIN_ALLOW_THREADS result = xs_set_permissions(xh, th, path, xsperms, xsperms_n); Py_END_ALLOW_THREADS diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/xend/XendCheckpoint.py --- a/tools/python/xen/xend/XendCheckpoint.py Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/xend/XendCheckpoint.py Wed Dec 24 12:52:34 2008 +0900 @@ -253,7 +253,7 @@ def restore(xd, fd, dominfo = None, paus # set memory limit xc.domain_setmaxmem(dominfo.getDomid(), maxmem) - balloon.free(memory + shadow) + balloon.free(memory + shadow, dominfo) shadow_cur = xc.shadow_mem_control(dominfo.getDomid(), shadow / 1024) dominfo.info['shadow_memory'] = shadow_cur diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/xend/XendConfig.py Wed Dec 24 12:52:34 2008 +0900 @@ -1289,7 +1289,6 @@ class XendConfig(dict): pass if dev_type == 'vbd': - dev_info['bootable'] = 0 if dev_info.get('dev', '').startswith('ioemu:'): dev_info['driver'] = 'ioemu' else: @@ -1325,7 +1324,7 @@ class XendConfig(dict): if param not in target: target[param] = [] if dev_uuid not in target[param]: - if dev_type == 'vbd': + if dev_type == 'vbd' and 'bootable' not in dev_info: # Compat hack -- mark first disk bootable dev_info['bootable'] = int(not target[param]) target[param].append(dev_uuid) @@ -1333,8 +1332,9 @@ class XendConfig(dict): if 'vbd_refs' not in target: target['vbd_refs'] = [] if dev_uuid not in target['vbd_refs']: - # Compat hack -- mark first disk bootable - dev_info['bootable'] = int(not target['vbd_refs']) + if 'bootable' not in dev_info: + # Compat hack -- mark first disk bootable + dev_info['bootable'] = int(not target['vbd_refs']) target['vbd_refs'].append(dev_uuid) elif dev_type == 'vfb': diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Dec 24 12:52:34 2008 +0900 @@ -517,7 +517,8 @@ class XendDomainInfo: # HVM domain shuts itself down only if it has PV drivers if self.info.is_hvm(): hvm_pvdrv = xc.hvm_get_param(self.domid, HVM_PARAM_CALLBACK_IRQ) - if not hvm_pvdrv: + hvm_s_state = xc.hvm_get_param(self.domid, HVM_PARAM_ACPI_S_STATE) + if not hvm_pvdrv or hvm_s_state != 0: code = REVERSE_DOMAIN_SHUTDOWN_REASONS[reason] log.info("HVM save:remote shutdown dom %d!", self.domid) xc.domain_shutdown(self.domid, code) @@ -2104,7 +2105,7 @@ class XendDomainInfo: # overhead is greater for some types of domain than others. For # example, an x86 HVM domain will have a default shadow-pagetable # allocation of 1MB. We free up 2MB here to be on the safe side. - balloon.free(2*1024) # 2MB should be plenty + balloon.free(2*1024, self) # 2MB should be plenty ssidref = 0 if security.on() == xsconstants.XS_POLICY_USE: @@ -2298,7 +2299,7 @@ class XendDomainInfo: vtd_mem = ((vtd_mem + 1023) / 1024) * 1024 # Make sure there's enough RAM available for the domain - balloon.free(memory + shadow + vtd_mem) + balloon.free(memory + shadow + vtd_mem, self) # Set up the shadow memory shadow_cur = xc.shadow_mem_control(self.domid, shadow / 1024) @@ -2715,7 +2716,7 @@ class XendDomainInfo: # The domain might already have some shadow memory overhead_kb -= xc.shadow_mem_control(self.domid) * 1024 if overhead_kb > 0: - balloon.free(overhead_kb) + balloon.free(overhead_kb, self) def _unwatchVm(self): """Remove the watch on the VM path, if any. Idempotent. Nothrow diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/xend/balloon.py --- a/tools/python/xen/xend/balloon.py Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/xend/balloon.py Wed Dec 24 12:52:34 2008 +0900 @@ -67,7 +67,7 @@ def get_dom0_target_alloc(): raise VmError('Failed to query target memory allocation of dom0.') return kb -def free(need_mem): +def free(need_mem ,self): """Balloon out memory from the privileged domain so that there is the specified required amount (in KiB) free. """ @@ -121,6 +121,40 @@ def free(need_mem): max_free_mem = total_mem - dom0_alloc if need_mem >= max_free_mem: retries = rlimit + + # Check whethercurrent machine is a numa system and the new + # created hvm has all its vcpus in the same node, if all the + # conditions above are fit. We will wait until all the pages + # in scrub list are freed (if waiting time go beyond 20s, + # we will stop waiting it.) + if physinfo['nr_nodes'] > 1 and retries == 0: + oldnode = -1 + waitscrub = 1 + vcpus = self.info['cpus'][0] + for vcpu in vcpus: + nodenum = 0 + for node in physinfo['node_to_cpu']: + for cpu in node: + if vcpu == cpu: + if oldnode == -1: + oldnode = nodenum + elif oldnode != nodenum: + waitscrub = 0 + nodenum = nodenum + 1 + + if waitscrub == 1 and scrub_mem > 0: + log.debug("wait for scrub %s", scrub_mem) + while scrub_mem > 0 and retries < rlimit: + time.sleep(sleep_time) + physinfo = xc.physinfo() + free_mem = physinfo['free_memory'] + scrub_mem = physinfo['scrub_memory'] + retries += 1 + sleep_time += SLEEP_TIME_GROWTH + log.debug("scrub for %d times", retries) + + retries = 0 + sleep_time = SLEEP_TIME_GROWTH while retries < rlimit: physinfo = xc.physinfo() diff -r 9837303a4708 -r 07f26e047fbf tools/python/xen/xend/server/blkif.py --- a/tools/python/xen/xend/server/blkif.py Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/python/xen/xend/server/blkif.py Wed Dec 24 12:52:34 2008 +0900 @@ -78,6 +78,10 @@ class BlkifController(DevController): if uuid: back['uuid'] = uuid + bootable = config.get('bootable', None) + if bootable != None: + back['bootable'] = str(bootable) + if security.on() == xsconstants.XS_POLICY_USE: self.do_access_control(config, uname) @@ -143,11 +147,12 @@ class BlkifController(DevController): config = DevController.getDeviceConfiguration(self, devid, transaction) if transaction is None: devinfo = self.readBackend(devid, 'dev', 'type', 'params', 'mode', - 'uuid') + 'uuid', 'bootable') else: devinfo = self.readBackendTxn(transaction, devid, - 'dev', 'type', 'params', 'mode', 'uuid') - dev, typ, params, mode, uuid = devinfo + 'dev', 'type', 'params', 'mode', 'uuid', + 'bootable') + dev, typ, params, mode, uuid, bootable = devinfo if dev: if transaction is None: @@ -165,6 +170,8 @@ class BlkifController(DevController): config['mode'] = mode if uuid: config['uuid'] = uuid + if bootable != None: + config['bootable'] = int(bootable) proto = self.readFrontend(devid, 'protocol') if proto: diff -r 9837303a4708 -r 07f26e047fbf tools/xcutils/xc_save.c --- a/tools/xcutils/xc_save.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/xcutils/xc_save.c Wed Dec 24 12:52:34 2008 +0900 @@ -166,18 +166,12 @@ static int suspend(void) { unsigned long sx_state = 0; - /* Nothing to do if the guest is in an ACPI sleep state. */ + /* Cannot notify guest to shut itself down if it's in ACPI sleep state. */ if (si.flags & XCFLAGS_HVM) xc_get_hvm_param(si.xc_fd, si.domid, HVM_PARAM_ACPI_S_STATE, &sx_state); - if (sx_state != 0) { - /* notify xend that it can do device migration */ - printf("suspended\n"); - fflush(stdout); - return 1; - } - - if (si.suspend_evtchn >= 0) + + if ((sx_state == 0) && (si.suspend_evtchn >= 0)) return evtchn_suspend(); return compat_suspend(); diff -r 9837303a4708 -r 07f26e047fbf tools/xenpmd/xenpmd.c --- a/tools/xenpmd/xenpmd.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/xenpmd/xenpmd.c Wed Dec 24 12:52:34 2008 +0900 @@ -297,7 +297,6 @@ int get_next_battery_info_or_status(DIR if ( !info_or_status ) return 0; - memset(line_info, 0, 256); if (type == BIF) memset(info_or_status, 0, sizeof(struct battery_info)); else @@ -307,11 +306,8 @@ int get_next_battery_info_or_status(DIR if ( !file ) return 0; - while ( fgets(line_info, 1024, file) != NULL ) - { + while ( fgets(line_info, sizeof(line_info), file) != NULL ) parse_battery_info_or_status(line_info, type, info_or_status); - memset(line_info, 0, 256); - } fclose(file); return 1; diff -r 9837303a4708 -r 07f26e047fbf tools/xenstat/xentop/xentop.c --- a/tools/xenstat/xentop/xentop.c Wed Dec 24 12:50:57 2008 +0900 +++ b/tools/xenstat/xentop/xentop.c Wed Dec 24 12:52:34 2008 +0900 @@ -254,7 +254,7 @@ static void fail(const char *str) { if(cwin != NULL && !isendwin()) endwin(); - fprintf(stderr, str); + fprintf(stderr, "%s", str); exit(1); } diff -r 9837303a4708 -r 07f26e047fbf unmodified_drivers/linux-2.6/Makefile --- a/unmodified_drivers/linux-2.6/Makefile Wed Dec 24 12:50:57 2008 +0900 +++ b/unmodified_drivers/linux-2.6/Makefile Wed Dec 24 12:52:34 2008 +0900 @@ -4,3 +4,4 @@ obj-m += balloon/ obj-m += balloon/ obj-m += blkfront/ obj-m += netfront/ +obj-m += scsifront/ diff -r 9837303a4708 -r 07f26e047fbf unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h --- a/unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h Wed Dec 24 12:50:57 2008 +0900 +++ b/unmodified_drivers/linux-2.6/compat-include/xen/platform-compat.h Wed Dec 24 12:52:34 2008 +0900 @@ -147,7 +147,9 @@ extern char *kasprintf(gfp_t gfp, const * RHEL_VERSION */ #if !defined(RHEL_VERSION) || (RHEL_VERSION == 4 && RHEL_UPDATE < 5) +#if !defined(RHEL_MAJOR) || (RHEL_MAJOR == 4 && RHEL_MINOR < 5) typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *); +#endif #endif #endif diff -r 9837303a4708 -r 07f26e047fbf unmodified_drivers/linux-2.6/overrides.mk --- a/unmodified_drivers/linux-2.6/overrides.mk Wed Dec 24 12:50:57 2008 +0900 +++ b/unmodified_drivers/linux-2.6/overrides.mk Wed Dec 24 12:52:34 2008 +0900 @@ -15,3 +15,4 @@ _XEN_CPPFLAGS += -include $(objtree)/inc EXTRA_CFLAGS += $(_XEN_CPPFLAGS) EXTRA_AFLAGS += $(_XEN_CPPFLAGS) +CPPFLAGS := -I$(M)/include $(CPPFLAGS) diff -r 9837303a4708 -r 07f26e047fbf unmodified_drivers/linux-2.6/scsifront/Kbuild --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unmodified_drivers/linux-2.6/scsifront/Kbuild Wed Dec 24 12:52:34 2008 +0900 @@ -0,0 +1,6 @@ +include $(M)/overrides.mk + +obj-m += xen-scsi.o + +xen-scsi-objs := scsifront.o xenbus.o + diff -r 9837303a4708 -r 07f26e047fbf unmodified_drivers/linux-2.6/scsifront/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/unmodified_drivers/linux-2.6/scsifront/Makefile Wed Dec 24 12:52:34 2008 +0900 @@ -0,0 +1,3 @@ +ifneq ($(KERNELRELEASE),) +include $(src)/Kbuild +endif diff -r 9837303a4708 -r 07f26e047fbf xen/arch/ia64/xen/cpufreq/cpufreq.c --- a/xen/arch/ia64/xen/cpufreq/cpufreq.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/ia64/xen/cpufreq/cpufreq.c Wed Dec 24 12:52:34 2008 +0900 @@ -275,6 +275,7 @@ acpi_cpufreq_cpu_exit (struct cpufreq_po } static struct cpufreq_driver acpi_cpufreq_driver = { + .name = "acpi-cpufreq", .verify = acpi_cpufreq_verify, .target = acpi_cpufreq_target, .get = acpi_cpufreq_get, diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/Makefile --- a/xen/arch/x86/Makefile Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/Makefile Wed Dec 24 12:52:34 2008 +0900 @@ -37,7 +37,6 @@ obj-y += numa.o obj-y += numa.o obj-y += pci.o obj-y += physdev.o -obj-y += rwlock.o obj-y += setup.o obj-y += shutdown.o obj-y += smp.o diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/acpi/cpu_idle.c --- a/xen/arch/x86/acpi/cpu_idle.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/acpi/cpu_idle.c Wed Dec 24 12:52:34 2008 +0900 @@ -71,7 +71,8 @@ static struct acpi_processor_power *__re static void print_acpi_power(uint32_t cpu, struct acpi_processor_power *power) { - uint32_t i; + uint32_t i, idle_usage = 0; + uint64_t res, idle_res = 0; printk("==cpu%d==\n", cpu); printk("active state:\t\tC%d\n", @@ -81,14 +82,21 @@ static void print_acpi_power(uint32_t cp for ( i = 1; i < power->count; i++ ) { + res = acpi_pm_tick_to_ns(power->states[i].time); + idle_usage += power->states[i].usage; + idle_res += res; + printk((power->last_state && power->last_state->idx == i) ? " *" : " "); printk("C%d:\t", i); printk("type[C%d] ", power->states[i].type); printk("latency[%03d] ", power->states[i].latency); printk("usage[%08d] ", power->states[i].usage); - printk("duration[%"PRId64"]\n", power->states[i].time); - } + printk("duration[%"PRId64"]\n", res); + } + printk(" C0:\tusage[%08d] duration[%"PRId64"]\n", + idle_usage, NOW() - idle_res); + } static void dump_cx(unsigned char key) @@ -317,8 +325,6 @@ static void acpi_processor_idle(void) * stopped by H/W. Without carefully handling of TSC/APIC stop issues, * deep C state can't work correctly. */ - /* preparing TSC stop */ - cstate_save_tsc(); /* preparing APIC stop */ lapic_timer_off(); @@ -751,8 +757,7 @@ int pmstat_get_cx_stat(uint32_t cpuid, s int pmstat_get_cx_stat(uint32_t cpuid, struct pm_cx_stat *stat) { const struct acpi_processor_power *power = processor_powers[cpuid]; - struct vcpu *v = idle_vcpu[cpuid]; - uint64_t usage; + uint64_t usage, res, idle_usage = 0, idle_res = 0; int i; if ( power == NULL ) @@ -765,20 +770,26 @@ int pmstat_get_cx_stat(uint32_t cpuid, s stat->last = power->last_state ? power->last_state->idx : 0; stat->nr = power->count; - stat->idle_time = v->runstate.time[RUNSTATE_running]; - if ( v->is_running ) - stat->idle_time += NOW() - v->runstate.state_entry_time; - - for ( i = 0; i < power->count; i++ ) - { - usage = power->states[i].usage; - if ( copy_to_guest_offset(stat->triggers, i, &usage, 1) ) + stat->idle_time = get_cpu_idle_time(cpuid); + + for ( i = power->count - 1; i >= 0; i-- ) + { + if ( i != 0 ) + { + usage = power->states[i].usage; + res = acpi_pm_tick_to_ns(power->states[i].time); + idle_usage += usage; + idle_res += res; + } + else + { + usage = idle_usage; + res = NOW() - idle_res; + } + if ( copy_to_guest_offset(stat->triggers, i, &usage, 1) || + copy_to_guest_offset(stat->residencies, i, &res, 1) ) return -EFAULT; } - for ( i = 0; i < power->count; i++ ) - if ( copy_to_guest_offset(stat->residencies, i, - &power->states[i].time, 1) ) - return -EFAULT; return 0; } diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/acpi/cpufreq/cpufreq.c --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c Wed Dec 24 12:52:34 2008 +0900 @@ -131,9 +131,12 @@ struct drv_cmd { u32 val; }; -static void do_drv_read(struct drv_cmd *cmd) -{ +static void do_drv_read(void *drvcmd) +{ + struct drv_cmd *cmd; u32 h; + + cmd = (struct drv_cmd *)drvcmd; switch (cmd->type) { case SYSTEM_INTEL_MSR_CAPABLE: @@ -174,7 +177,13 @@ static void drv_read(struct drv_cmd *cmd { cmd->val = 0; - do_drv_read(cmd); + ASSERT(cpus_weight(cmd->mask) == 1); + + /* to reduce IPI for the sake of performance */ + if (cpu_isset(smp_processor_id(), cmd->mask)) + do_drv_read((void *)cmd); + else + on_selected_cpus( cmd->mask, do_drv_read, (void *)cmd, 0, 1); } static void drv_write(struct drv_cmd *cmd) @@ -184,13 +193,21 @@ static void drv_write(struct drv_cmd *cm static u32 get_cur_val(cpumask_t mask) { + struct cpufreq_policy *policy; struct processor_performance *perf; struct drv_cmd cmd; + unsigned int cpu; if (unlikely(cpus_empty(mask))) return 0; - switch (drv_data[first_cpu(mask)]->cpu_feature) { + cpu = first_cpu(mask); + policy = cpufreq_cpu_policy[cpu]; + + if (!policy) + return 0; + + switch (drv_data[policy->cpu]->cpu_feature) { case SYSTEM_INTEL_MSR_CAPABLE: cmd.type = SYSTEM_INTEL_MSR_CAPABLE; cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; @@ -205,7 +222,7 @@ static u32 get_cur_val(cpumask_t mask) return 0; } - cmd.mask = mask; + cmd.mask = cpumask_of_cpu(cpu); drv_read(&cmd); return cmd.val; @@ -255,28 +272,43 @@ static void __get_measured_perf(void *p static unsigned int get_measured_perf(unsigned int cpu) { - unsigned int retval, perf_percent; + struct cpufreq_policy *policy; + unsigned int perf_percent; cpumask_t cpumask; if (!cpu_online(cpu)) return 0; - cpumask = cpumask_of_cpu(cpu); - on_selected_cpus(cpumask, __get_measured_perf, (void *)&perf_percent,0,1); - - retval = drv_data[cpu]->max_freq * perf_percent / 100; - return retval; + policy = cpufreq_cpu_policy[cpu]; + if (!policy) + return 0; + + /* Usually we take the short path (no IPI) for the sake of performance. */ + if (cpu == smp_processor_id()) { + __get_measured_perf((void *)&perf_percent); + } else { + cpumask = cpumask_of_cpu(cpu); + on_selected_cpus(cpumask, __get_measured_perf, + (void *)&perf_percent,0,1); + } + + return drv_data[cpu]->max_freq * perf_percent / 100; } static unsigned int get_cur_freq_on_cpu(unsigned int cpu) { - struct acpi_cpufreq_data *data = drv_data[cpu]; + struct cpufreq_policy *policy; + struct acpi_cpufreq_data *data; unsigned int freq; + policy = cpufreq_cpu_policy[cpu]; + if (!policy) + return 0; + + data = drv_data[policy->cpu]; if (unlikely(data == NULL || - data->acpi_data == NULL || data->freq_table == NULL)) { - return 0; - } + data->acpi_data == NULL || data->freq_table == NULL)) + return 0; freq = extract_freq(get_cur_val(cpumask_of_cpu(cpu)), data); return freq; @@ -327,16 +359,10 @@ static int acpi_cpufreq_target(struct cp next_perf_state = data->freq_table[next_state].index; if (perf->state == next_perf_state) { - if (unlikely(policy->resume)) { - printk(KERN_INFO "Called after resume, resetting to P%d\n", - next_perf_state); + if (unlikely(policy->resume)) policy->resume = 0; - } - else { - printk(KERN_DEBUG "Already at target state (P%d)\n", - next_perf_state); + else return 0; - } } switch (data->cpu_feature) { @@ -555,6 +581,7 @@ static int acpi_cpufreq_cpu_exit(struct } static struct cpufreq_driver acpi_cpufreq_driver = { + .name = "acpi-cpufreq", .verify = acpi_cpufreq_verify, .target = acpi_cpufreq_target, .init = acpi_cpufreq_cpu_init, diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/acpi/cpufreq/powernow.c --- a/xen/arch/x86/acpi/cpufreq/powernow.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/acpi/cpufreq/powernow.c Wed Dec 24 12:52:34 2008 +0900 @@ -129,6 +129,16 @@ static int powernow_cpufreq_target(struc return result; } +static int powernow_cpufreq_verify(struct cpufreq_policy *policy) +{ + struct powernow_cpufreq_data *data; + + if (!policy || !(data = drv_data[policy->cpu])) + return -EINVAL; + + return cpufreq_frequency_table_verify(policy, data->freq_table); +} + static int powernow_cpufreq_cpu_init(struct cpufreq_policy *policy) { unsigned int i; @@ -243,6 +253,7 @@ static int powernow_cpufreq_cpu_exit(str } static struct cpufreq_driver powernow_cpufreq_driver = { + .verify = powernow_cpufreq_verify, .target = powernow_cpufreq_target, .init = powernow_cpufreq_cpu_init, .exit = powernow_cpufreq_cpu_exit diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/apic.c --- a/xen/arch/x86/apic.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/apic.c Wed Dec 24 12:52:34 2008 +0900 @@ -99,8 +99,11 @@ void __init apic_intr_init(void) /* Performance Counters Interrupt */ set_intr_gate(PMU_APIC_VECTOR, pmu_apic_interrupt); - /* thermal monitor LVT interrupt */ -#ifdef CONFIG_X86_MCE_P4THERMAL + /* CMCI Correctable Machine Check Interrupt */ + set_intr_gate(CMCI_APIC_VECTOR, cmci_interrupt); + + /* thermal monitor LVT interrupt, for P4 and latest Intel CPU*/ +#ifdef CONFIG_X86_MCE_THERMAL set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); #endif } @@ -172,12 +175,17 @@ void clear_local_APIC(void) } /* lets not touch this if we didn't frob it */ -#ifdef CONFIG_X86_MCE_P4THERMAL +#ifdef CONFIG_X86_MCE_THERMAL if (maxlvt >= 5) { v = apic_read(APIC_LVTTHMR); apic_write_around(APIC_LVTTHMR, v | APIC_LVT_MASKED); } #endif + + if (maxlvt >= 6) { + v = apic_read(APIC_CMCI); + apic_write_around(APIC_CMCI, v | APIC_LVT_MASKED); + } /* * Clean APIC state for other OSs: */ @@ -189,10 +197,13 @@ void clear_local_APIC(void) if (maxlvt >= 4) apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); -#ifdef CONFIG_X86_MCE_P4THERMAL +#ifdef CONFIG_X86_MCE_THERMAL if (maxlvt >= 5) apic_write_around(APIC_LVTTHMR, APIC_LVT_MASKED); #endif + if (maxlvt >= 6) + apic_write_around(APIC_CMCI, APIC_LVT_MASKED); + v = GET_APIC_VERSION(apic_read(APIC_LVR)); if (APIC_INTEGRATED(v)) { /* !82489DX */ if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */ @@ -597,6 +608,7 @@ static struct { unsigned int apic_spiv; unsigned int apic_lvtt; unsigned int apic_lvtpc; + unsigned int apic_lvtcmci; unsigned int apic_lvt0; unsigned int apic_lvt1; unsigned int apic_lvterr; @@ -608,7 +620,7 @@ int lapic_suspend(void) int lapic_suspend(void) { unsigned long flags; - + int maxlvt = get_maxlvt(); if (!apic_pm_state.active) return 0; @@ -620,6 +632,11 @@ int lapic_suspend(void) apic_pm_state.apic_spiv = apic_read(APIC_SPIV); apic_pm_state.apic_lvtt = apic_read(APIC_LVTT); apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC); + + if (maxlvt >= 6) { + apic_pm_state.apic_lvtcmci = apic_read(APIC_CMCI); + } + apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0); apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1); apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR); @@ -637,6 +654,7 @@ int lapic_resume(void) { unsigned int l, h; unsigned long flags; + int maxlvt = get_maxlvt(); if (!apic_pm_state.active) return 0; @@ -669,6 +687,11 @@ int lapic_resume(void) apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); + + if (maxlvt >= 6) { + apic_write(APIC_CMCI, apic_pm_state.apic_lvtcmci); + } + apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); apic_write(APIC_LVTT, apic_pm_state.apic_lvtt); apic_write(APIC_TDCR, apic_pm_state.apic_tdcr); diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/amd.c --- a/xen/arch/x86/cpu/amd.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/amd.c Wed Dec 24 12:52:34 2008 +0900 @@ -461,8 +461,10 @@ static void __devinit init_amd(struct cp if (cpuid_eax(0x80000000) >= 0x80000007) { c->x86_power = cpuid_edx(0x80000007); - if (c->x86_power & (1<<8)) + if (c->x86_power & (1<<8)) { set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability); + set_bit(X86_FEATURE_NOSTOP_TSC, c->x86_capability); + } } #ifdef CONFIG_X86_HT diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/intel.c --- a/xen/arch/x86/cpu/intel.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/intel.c Wed Dec 24 12:52:34 2008 +0900 @@ -218,6 +218,10 @@ static void __devinit init_intel(struct if ((c->x86 == 0xf && c->x86_model >= 0x03) || (c->x86 == 0x6 && c->x86_model >= 0x0e)) set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability); + if (cpuid_edx(0x80000007) & (1u<<8)) { + set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability); + set_bit(X86_FEATURE_NOSTOP_TSC, c->x86_capability); + } start_vmx(); } diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/mcheck/Makefile --- a/xen/arch/x86/cpu/mcheck/Makefile Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/mcheck/Makefile Wed Dec 24 12:52:34 2008 +0900 @@ -3,8 +3,7 @@ obj-y += amd_k8.o obj-y += amd_k8.o obj-y += amd_f10.o obj-y += mce.o +obj-y += mce_intel.o obj-y += non-fatal.o -obj-y += p4.o obj-$(x86_32) += p5.o -obj-$(x86_32) += p6.o obj-$(x86_32) += winchip.o diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/mcheck/amd_k8.c --- a/xen/arch/x86/cpu/mcheck/amd_k8.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/mcheck/amd_k8.c Wed Dec 24 12:52:34 2008 +0900 @@ -219,7 +219,7 @@ void k8_machine_check(struct cpu_user_re show_execution_state(regs); } x86_mcinfo_dump(mc_data); - panic("End of MCE. Use mcelog to decode above error codes.\n"); + mc_panic("End of MCE. Use mcelog to decode above error codes.\n"); } /* If Dom0 registered a machine check handler, which is only possible @@ -248,7 +248,7 @@ void k8_machine_check(struct cpu_user_re /* Dom0 is impacted. Since noone can't handle * this error, panic! */ x86_mcinfo_dump(mc_data); - panic("MCE occured in Dom0, which it can't handle\n"); + mc_panic("MCE occured in Dom0, which it can't handle\n"); /* UNREACHED */ } else { diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/mcheck/k7.c --- a/xen/arch/x86/cpu/mcheck/k7.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/mcheck/k7.c Wed Dec 24 12:52:34 2008 +0900 @@ -14,6 +14,7 @@ #include <asm/msr.h> #include "mce.h" +#include "x86_mca.h" /* Machine Check Handler For AMD Athlon/Duron */ static fastcall void k7_machine_check(struct cpu_user_regs * regs, long error_code) @@ -57,9 +58,9 @@ static fastcall void k7_machine_check(st } if (recover&2) - panic ("CPU context corrupt"); + mc_panic ("CPU context corrupt"); if (recover&1) - panic ("Unable to continue"); + mc_panic ("Unable to continue"); printk (KERN_EMERG "Attempting to continue.\n"); mcgstl &= ~(1<<2); wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth); diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/mcheck/mce.c --- a/xen/arch/x86/cpu/mcheck/mce.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/mcheck/mce.c Wed Dec 24 12:52:34 2008 +0900 @@ -9,6 +9,7 @@ #include <xen/config.h> #include <xen/smp.h> #include <xen/errno.h> +#include <xen/console.h> #include <asm/processor.h> #include <asm/system.h> @@ -26,7 +27,7 @@ EXPORT_SYMBOL_GPL(nr_mce_banks); /* non- * to physical cpus present in the machine. * The more physical cpus are available, the more entries you need. */ -#define MAX_MCINFO 10 +#define MAX_MCINFO 20 struct mc_machine_notify { struct mc_info mc; @@ -109,6 +110,12 @@ static void amd_mcheck_init(struct cpuin } } +/*check the existence of Machine Check*/ +int mce_available(struct cpuinfo_x86 *c) +{ + return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA); +} + /* This has to be run for each processor */ void mcheck_init(struct cpuinfo_x86 *c) { @@ -134,11 +141,13 @@ void mcheck_init(struct cpuinfo_x86 *c) #ifndef CONFIG_X86_64 if (c->x86==5) intel_p5_mcheck_init(c); - if (c->x86==6) - intel_p6_mcheck_init(c); #endif - if (c->x86==15) - intel_p4_mcheck_init(c); + /*If it is P6 or P4 family, including CORE 2 DUO series*/ + if (c->x86 == 6 || c->x86==15) + { + printk(KERN_DEBUG "MCE: Intel newly family MC Init\n"); + intel_mcheck_init(c); + } break; #ifndef CONFIG_X86_64 @@ -412,7 +421,7 @@ void x86_mcinfo_dump(struct mc_info *mi) if (mic == NULL) return; if (mic->type != MC_TYPE_BANK) - continue; + goto next; mc_bank = (struct mcinfo_bank *)mic; @@ -425,6 +434,7 @@ void x86_mcinfo_dump(struct mc_info *mi) printk(" at %16"PRIx64, mc_bank->mc_addr); printk("\n"); +next: mic = x86_mcinfo_next(mic); /* next entry */ if ((mic == NULL) || (mic->size == 0)) break; @@ -574,3 +584,15 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u return ret; } + +void mc_panic(char *s) +{ + console_start_sync(); + printk("Fatal machine check: %s\n", s); + printk("\n" + "****************************************\n" + "\n" + " The processor has reported a hardware error which cannot\n" + " be recovered from. Xen will now reboot the machine.\n"); + panic("HARDWARE ERROR"); +} diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/mcheck/mce.h --- a/xen/arch/x86/cpu/mcheck/mce.h Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/mcheck/mce.h Wed Dec 24 12:52:34 2008 +0900 @@ -1,14 +1,22 @@ #include <xen/init.h> +#include <asm/types.h> #include <asm/traps.h> +#include <asm/atomic.h> +#include <asm/percpu.h> + /* Init functions */ void amd_nonfatal_mcheck_init(struct cpuinfo_x86 *c); void amd_k7_mcheck_init(struct cpuinfo_x86 *c); void amd_k8_mcheck_init(struct cpuinfo_x86 *c); void amd_f10_mcheck_init(struct cpuinfo_x86 *c); -void intel_p4_mcheck_init(struct cpuinfo_x86 *c); + + +void intel_mcheck_timer(struct cpuinfo_x86 *c); void intel_p5_mcheck_init(struct cpuinfo_x86 *c); -void intel_p6_mcheck_init(struct cpuinfo_x86 *c); +void intel_mcheck_init(struct cpuinfo_x86 *c); +void mce_intel_feature_init(struct cpuinfo_x86 *c); + void winchip_mcheck_init(struct cpuinfo_x86 *c); /* Function pointer used in the handlers to collect additional information @@ -19,12 +27,11 @@ extern int (*mc_callback_bank_extended)( uint16_t bank, uint64_t status); +int mce_available(struct cpuinfo_x86 *c); /* Helper functions used for collecting error telemetry */ struct mc_info *x86_mcinfo_getptr(void); void x86_mcinfo_clear(struct mc_info *mi); int x86_mcinfo_add(struct mc_info *mi, void *mcinfo); void x86_mcinfo_dump(struct mc_info *mi); +void mc_panic(char *s); -/* Global variables */ -extern int mce_disabled; -extern unsigned int nr_mce_banks; diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/mcheck/mce_intel.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/cpu/mcheck/mce_intel.c Wed Dec 24 12:52:34 2008 +0900 @@ -0,0 +1,632 @@ +#include <xen/init.h> +#include <xen/types.h> +#include <xen/irq.h> +#include <xen/event.h> +#include <xen/kernel.h> +#include <xen/smp.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/msr.h> +#include "mce.h" +#include "x86_mca.h" + +DEFINE_PER_CPU(cpu_banks_t, mce_banks_owned); + +static int nr_intel_ext_msrs = 0; +static int cmci_support = 0; +extern int firstbank; + +#ifdef CONFIG_X86_MCE_THERMAL +static void unexpected_thermal_interrupt(struct cpu_user_regs *regs) +{ + printk(KERN_ERR "Thermal: CPU%d: Unexpected LVT TMR interrupt!\n", + smp_processor_id()); + add_taint(TAINT_MACHINE_CHECK); +} + +/* P4/Xeon Thermal transition interrupt handler */ +static void intel_thermal_interrupt(struct cpu_user_regs *regs) +{ + u32 l, h; + unsigned int cpu = smp_processor_id(); + static s_time_t next[NR_CPUS]; + + ack_APIC_irq(); + if (NOW() < next[cpu]) + return; + + next[cpu] = NOW() + MILLISECS(5000); + rdmsr(MSR_IA32_THERM_STATUS, l, h); + if (l & 0x1) { + printk(KERN_EMERG "CPU%d: Temperature above threshold\n", cpu); + printk(KERN_EMERG "CPU%d: Running in modulated clock mode\n", + cpu); + add_taint(TAINT_MACHINE_CHECK); + } else { + printk(KERN_INFO "CPU%d: Temperature/speed normal\n", cpu); + } +} + +/* Thermal interrupt handler for this CPU setup */ +static void (*vendor_thermal_interrupt)(struct cpu_user_regs *regs) + = unexpected_thermal_interrupt; + +fastcall void smp_thermal_interrupt(struct cpu_user_regs *regs) +{ + irq_enter(); + vendor_thermal_interrupt(regs); + irq_exit(); +} + +/* P4/Xeon Thermal regulation detect and init */ +static void intel_init_thermal(struct cpuinfo_x86 *c) +{ + u32 l, h; + int tm2 = 0; + unsigned int cpu = smp_processor_id(); + + /* Thermal monitoring */ + if (!cpu_has(c, X86_FEATURE_ACPI)) + return; /* -ENODEV */ + + /* Clock modulation */ + if (!cpu_has(c, X86_FEATURE_ACC)) + return; /* -ENODEV */ + + /* first check if its enabled already, in which case there might + * be some SMM goo which handles it, so we can't even put a handler + * since it might be delivered via SMI already -zwanem. + */ + rdmsr (MSR_IA32_MISC_ENABLE, l, h); + h = apic_read(APIC_LVTTHMR); + if ((l & (1<<3)) && (h & APIC_DM_SMI)) { + printk(KERN_DEBUG "CPU%d: Thermal monitoring handled by SMI\n",cpu); + return; /* -EBUSY */ + } + + if (cpu_has(c, X86_FEATURE_TM2) && (l & (1 << 13))) + tm2 = 1; + + /* check whether a vector already exists, temporarily masked? */ + if (h & APIC_VECTOR_MASK) { + printk(KERN_DEBUG "CPU%d: Thermal LVT vector (%#x) already installed\n", + cpu, (h & APIC_VECTOR_MASK)); + return; /* -EBUSY */ + } + + /* The temperature transition interrupt handler setup */ + h = THERMAL_APIC_VECTOR; /* our delivery vector */ + h |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */ + apic_write_around(APIC_LVTTHMR, h); + + rdmsr (MSR_IA32_THERM_INTERRUPT, l, h); + wrmsr (MSR_IA32_THERM_INTERRUPT, l | 0x03 , h); + + /* ok we're good to go... */ + vendor_thermal_interrupt = intel_thermal_interrupt; + + rdmsr (MSR_IA32_MISC_ENABLE, l, h); + wrmsr (MSR_IA32_MISC_ENABLE, l | (1<<3), h); + + l = apic_read (APIC_LVTTHMR); + apic_write_around (APIC_LVTTHMR, l & ~APIC_LVT_MASKED); + printk (KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n", + cpu, tm2 ? "TM2" : "TM1"); + return; +} +#endif /* CONFIG_X86_MCE_THERMAL */ + +static inline void intel_get_extended_msrs(struct mcinfo_extended *mc_ext) +{ + if (nr_intel_ext_msrs == 0) + return; + + /*this function will called when CAP(9).MCG_EXT_P = 1*/ + memset(mc_ext, 0, sizeof(struct mcinfo_extended)); + mc_ext->common.type = MC_TYPE_EXTENDED; + mc_ext->common.size = sizeof(mc_ext); + mc_ext->mc_msrs = 10; + + mc_ext->mc_msr[0].reg = MSR_IA32_MCG_EAX; + rdmsrl(MSR_IA32_MCG_EAX, mc_ext->mc_msr[0].value); + mc_ext->mc_msr[1].reg = MSR_IA32_MCG_EBX; + rdmsrl(MSR_IA32_MCG_EBX, mc_ext->mc_msr[1].value); + mc_ext->mc_msr[2].reg = MSR_IA32_MCG_ECX; + rdmsrl(MSR_IA32_MCG_ECX, mc_ext->mc_msr[2].value); + + mc_ext->mc_msr[3].reg = MSR_IA32_MCG_EDX; + rdmsrl(MSR_IA32_MCG_EDX, mc_ext->mc_msr[3].value); + mc_ext->mc_msr[4].reg = MSR_IA32_MCG_ESI; + rdmsrl(MSR_IA32_MCG_ESI, mc_ext->mc_msr[4].value); + mc_ext->mc_msr[5].reg = MSR_IA32_MCG_EDI; + rdmsrl(MSR_IA32_MCG_EDI, mc_ext->mc_msr[5].value); + + mc_ext->mc_msr[6].reg = MSR_IA32_MCG_EBP; + rdmsrl(MSR_IA32_MCG_EBP, mc_ext->mc_msr[6].value); + mc_ext->mc_msr[7].reg = MSR_IA32_MCG_ESP; + rdmsrl(MSR_IA32_MCG_ESP, mc_ext->mc_msr[7].value); + mc_ext->mc_msr[8].reg = MSR_IA32_MCG_EFLAGS; + rdmsrl(MSR_IA32_MCG_EFLAGS, mc_ext->mc_msr[8].value); + mc_ext->mc_msr[9].reg = MSR_IA32_MCG_EIP; + rdmsrl(MSR_IA32_MCG_EIP, mc_ext->mc_msr[9].value); +} + +/* machine_check_poll might be called by following types: + * 1. called when do mcheck_init. + * 2. called in cmci interrupt handler + * 3. called in polling handler + * It will generate a new mc_info item if found CE/UC errors. DOM0 is the + * consumer. +*/ +static int machine_check_poll(struct mc_info *mi, int calltype) +{ + int exceptions = (read_cr4() & X86_CR4_MCE); + int i, nr_unit = 0, uc = 0, pcc = 0; + uint64_t status, addr; + struct mcinfo_global mcg; + struct mcinfo_extended mce; + unsigned int cpu; + struct domain *d; + + cpu = smp_processor_id(); + + if (!mi) { + printk(KERN_ERR "mcheck_poll: Failed to get mc_info entry\n"); + return 0; + } + x86_mcinfo_clear(mi); + + memset(&mcg, 0, sizeof(mcg)); + mcg.common.type = MC_TYPE_GLOBAL; + mcg.common.size = sizeof(mcg); + /*If called from cpu-reset check, don't need to fill them. + *If called from cmci context, we'll try to fill domid by memory addr + */ + mcg.mc_domid = -1; + mcg.mc_vcpuid = -1; + if (calltype == MC_FLAG_POLLED || calltype == MC_FLAG_RESET) + mcg.mc_flags = MC_FLAG_POLLED; + else if (calltype == MC_FLAG_CMCI) + mcg.mc_flags = MC_FLAG_CMCI; + mcg.mc_socketid = phys_proc_id[cpu]; + mcg.mc_coreid = cpu_core_id[cpu]; + mcg.mc_apicid = cpu_physical_id(cpu); + mcg.mc_core_threadid = mcg.mc_apicid & ( 1 << (smp_num_siblings - 1)); + rdmsrl(MSR_IA32_MCG_STATUS, mcg.mc_gstatus); + + for ( i = 0; i < nr_mce_banks; i++ ) { + struct mcinfo_bank mcb; + /*For CMCI, only owners checks the owned MSRs*/ + if ( !test_bit(i, __get_cpu_var(mce_banks_owned)) && + (calltype & MC_FLAG_CMCI) ) + continue; + rdmsrl(MSR_IA32_MC0_STATUS + 4 * i, status); + + if (! (status & MCi_STATUS_VAL) ) + continue; + /* + * Uncorrected events are handled by the exception + * handler when it is enabled. But when the exception + * is disabled such as when mcheck_init, log everything. + */ + if ((status & MCi_STATUS_UC) && exceptions) + continue; + + if (status & MCi_STATUS_UC) + uc = 1; + if (status & MCi_STATUS_PCC) + pcc = 1; + + memset(&mcb, 0, sizeof(mcb)); + mcb.common.type = MC_TYPE_BANK; + mcb.common.size = sizeof(mcb); + mcb.mc_bank = i; + mcb.mc_status = status; + if (status & MCi_STATUS_MISCV) + rdmsrl(MSR_IA32_MC0_MISC + 4 * i, mcb.mc_misc); + if (status & MCi_STATUS_ADDRV) { + rdmsrl(MSR_IA32_MC0_ADDR + 4 * i, addr); + d = maddr_get_owner(addr); + if ( d && (calltype == MC_FLAG_CMCI || calltype == MC_FLAG_POLLED) ) + mcb.mc_domid = d->domain_id; + } + if (cmci_support) + rdmsrl(MSR_IA32_MC0_CTL2 + i, mcb.mc_ctrl2); + if (calltype == MC_FLAG_CMCI) + rdtscll(mcb.mc_tsc); + x86_mcinfo_add(mi, &mcb); + nr_unit++; + add_taint(TAINT_MACHINE_CHECK); + /*Clear state for this bank */ + wrmsrl(MSR_IA32_MC0_STATUS + 4 * i, 0); + printk(KERN_DEBUG "mcheck_poll: bank%i CPU%d status[%"PRIx64"]\n", + i, cpu, status); + printk(KERN_DEBUG "mcheck_poll: CPU%d, SOCKET%d, CORE%d, APICID[%d], " + "thread[%d]\n", cpu, mcg.mc_socketid, + mcg.mc_coreid, mcg.mc_apicid, mcg.mc_core_threadid); + + } + /*if pcc = 1, uc must be 1*/ + if (pcc) + mcg.mc_flags |= MC_FLAG_UNCORRECTABLE; + else if (uc) + mcg.mc_flags |= MC_FLAG_RECOVERABLE; + else /*correctable*/ + mcg.mc_flags |= MC_FLAG_CORRECTABLE; + + if (nr_unit && nr_intel_ext_msrs && + (mcg.mc_gstatus & MCG_STATUS_EIPV)) { + intel_get_extended_msrs(&mce); + x86_mcinfo_add(mi, &mce); + } + if (nr_unit) + x86_mcinfo_add(mi, &mcg); + /*Clear global state*/ + return nr_unit; +} + +static fastcall void intel_machine_check(struct cpu_user_regs * regs, long error_code) +{ + /* MACHINE CHECK Error handler will be sent in another patch, + * simply copy old solutions here. This code will be replaced + * by upcoming machine check patches + */ + + int recover=1; + u32 alow, ahigh, high, low; + u32 mcgstl, mcgsth; + int i; + + rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); + if (mcgstl & (1<<0)) /* Recoverable ? */ + recover=0; + + printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", + smp_processor_id(), mcgsth, mcgstl); + + for (i=0; i<nr_mce_banks; i++) { + rdmsr (MSR_IA32_MC0_STATUS+i*4,low, high); + if (high & (1<<31)) { + if (high & (1<<29)) + recover |= 1; + if (high & (1<<25)) + recover |= 2; + printk (KERN_EMERG "Bank %d: %08x%08x", i, high, low); + high &= ~(1<<31); + if (high & (1<<27)) { + rdmsr (MSR_IA32_MC0_MISC+i*4, alow, ahigh); + printk ("[%08x%08x]", ahigh, alow); + } + if (high & (1<<26)) { + rdmsr (MSR_IA32_MC0_ADDR+i*4, alow, ahigh); + printk (" at %08x%08x", ahigh, alow); + } + printk ("\n"); + } + } + + if (recover & 2) + mc_panic ("CPU context corrupt"); + if (recover & 1) + mc_panic ("Unable to continue"); + + printk(KERN_EMERG "Attempting to continue.\n"); + /* + * Do not clear the MSR_IA32_MCi_STATUS if the error is not + * recoverable/continuable.This will allow BIOS to look at the MSRs + * for errors if the OS could not log the error. + */ + for (i=0; i<nr_mce_banks; i++) { + u32 msr; + msr = MSR_IA32_MC0_STATUS+i*4; + rdmsr (msr, low, high); + if (high&(1<<31)) { + /* Clear it */ + wrmsr(msr, 0UL, 0UL); + /* Serialize */ + wmb(); + add_taint(TAINT_MACHINE_CHECK); + } + } + mcgstl &= ~(1<<2); + wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth); +} + +static DEFINE_SPINLOCK(cmci_discover_lock); +static DEFINE_PER_CPU(cpu_banks_t, no_cmci_banks); + +/* + * Discover bank sharing using the algorithm recommended in the SDM. + */ +static int do_cmci_discover(int i) +{ + unsigned msr = MSR_IA32_MC0_CTL2 + i; + u64 val; + + rdmsrl(msr, val); + /* Some other CPU already owns this bank. */ + if (val & CMCI_EN) { + clear_bit(i, __get_cpu_var(mce_banks_owned)); + goto out; + } + wrmsrl(msr, val | CMCI_EN | CMCI_THRESHOLD); + rdmsrl(msr, val); + + if (!(val & CMCI_EN)) { + /* This bank does not support CMCI. Polling timer has to handle it. */ + set_bit(i, __get_cpu_var(no_cmci_banks)); + return 0; + } + set_bit(i, __get_cpu_var(mce_banks_owned)); +out: + clear_bit(i, __get_cpu_var(no_cmci_banks)); + return 1; +} + +static void cmci_discover(void) +{ + unsigned long flags; + int i; + + printk(KERN_DEBUG "CMCI: find owner on CPU%d\n", smp_processor_id()); + + spin_lock_irqsave(&cmci_discover_lock, flags); + + for (i = 0; i < nr_mce_banks; i++) + if (!test_bit(i, __get_cpu_var(mce_banks_owned))) + do_cmci_discover(i); + + spin_unlock_irqrestore(&cmci_discover_lock, flags); + + printk(KERN_DEBUG "CMCI: CPU%d owner_map[%lx], no_cmci_map[%lx]\n", + smp_processor_id(), + *((unsigned long *)__get_cpu_var(mce_banks_owned)), + *((unsigned long *)__get_cpu_var(no_cmci_banks))); +} + +/* + * Define an owner for each bank. Banks can be shared between CPUs + * and to avoid reporting events multiple times always set up one + * CPU as owner. + * + * The assignment has to be redone when CPUs go offline and + * any of the owners goes away. Also pollers run in parallel so we + * have to be careful to update the banks in a way that doesn't + * lose or duplicate events. + */ + +static void mce_set_owner(void) +{ + if (!cmci_support || mce_disabled == 1) + return; + + cmci_discover(); +} + +static void __cpu_mcheck_distribute_cmci(void *unused) +{ + cmci_discover(); +} + +void cpu_mcheck_distribute_cmci(void) +{ + if (cmci_support && !mce_disabled) + on_each_cpu(__cpu_mcheck_distribute_cmci, NULL, 0, 0); +} + +static void clear_cmci(void) +{ + int i; + + if (!cmci_support || mce_disabled == 1) + return; + + printk(KERN_DEBUG "CMCI: clear_cmci support on CPU%d\n", + smp_processor_id()); + + for (i = 0; i < nr_mce_banks; i++) { + unsigned msr = MSR_IA32_MC0_CTL2 + i; + u64 val; + if (!test_bit(i, __get_cpu_var(mce_banks_owned))) + continue; + rdmsrl(msr, val); + if (val & (CMCI_EN|CMCI_THRESHOLD_MASK)) + wrmsrl(msr, val & ~(CMCI_EN|CMCI_THRESHOLD_MASK)); + clear_bit(i, __get_cpu_var(mce_banks_owned)); + } +} + +void cpu_mcheck_disable(void) +{ + clear_in_cr4(X86_CR4_MCE); + + if (cmci_support && !mce_disabled) + clear_cmci(); +} + +static void intel_init_cmci(struct cpuinfo_x86 *c) +{ + u32 l, apic; + int cpu = smp_processor_id(); + + if (!mce_available(c) || !cmci_support) { + printk(KERN_DEBUG "CMCI: CPU%d has no CMCI support\n", cpu); + return; + } + + apic = apic_read(APIC_CMCI); + if ( apic & APIC_VECTOR_MASK ) + { + printk(KERN_WARNING "CPU%d CMCI LVT vector (%#x) already installed\n", + cpu, ( apic & APIC_VECTOR_MASK )); + return; + } + + apic = CMCI_APIC_VECTOR; + apic |= (APIC_DM_FIXED | APIC_LVT_MASKED); + apic_write_around(APIC_CMCI, apic); + + l = apic_read(APIC_CMCI); + apic_write_around(APIC_CMCI, l & ~APIC_LVT_MASKED); +} + +fastcall void smp_cmci_interrupt(struct cpu_user_regs *regs) +{ + int nr_unit; + struct mc_info *mi = x86_mcinfo_getptr(); + int cpu = smp_processor_id(); + + ack_APIC_irq(); + irq_enter(); + printk(KERN_DEBUG "CMCI: cmci_intr happen on CPU%d\n", cpu); + nr_unit = machine_check_poll(mi, MC_FLAG_CMCI); + if (nr_unit) { + x86_mcinfo_dump(mi); + if (dom0 && guest_enabled_event(dom0->vcpu[0], VIRQ_MCA)) + send_guest_global_virq(dom0, VIRQ_MCA); + } + irq_exit(); +} + +void mce_intel_feature_init(struct cpuinfo_x86 *c) +{ + +#ifdef CONFIG_X86_MCE_THERMAL + intel_init_thermal(c); +#endif + intel_init_cmci(c); +} + +static void mce_cap_init(struct cpuinfo_x86 *c) +{ + u32 l, h; + + rdmsr (MSR_IA32_MCG_CAP, l, h); + if ((l & MCG_CMCI_P) && cpu_has_apic) + cmci_support = 1; + + nr_mce_banks = l & 0xff; + if (nr_mce_banks > MAX_NR_BANKS) + printk(KERN_WARNING "MCE: exceed max mce banks\n"); + if (l & MCG_EXT_P) + { + nr_intel_ext_msrs = (l >> MCG_EXT_CNT) & 0xff; + printk (KERN_INFO "CPU%d: Intel Extended MCE MSRs (%d) available\n", + smp_processor_id(), nr_intel_ext_msrs); + } + /* for most of p6 family, bank 0 is an alias bios MSR. + * But after model>1a, bank 0 is available*/ + if ( c->x86 == 6 && c->x86_vendor == X86_VENDOR_INTEL + && c->x86_model < 0x1A) + firstbank = 1; + else + firstbank = 0; +} + +static void mce_init(void) +{ + u32 l, h; + int i, nr_unit; + struct mc_info *mi = x86_mcinfo_getptr(); + clear_in_cr4(X86_CR4_MCE); + /* log the machine checks left over from the previous reset. + * This also clears all registers*/ + + nr_unit = machine_check_poll(mi, MC_FLAG_RESET); + /*in the boot up stage, not expect inject to DOM0, but go print out + */ + if (nr_unit > 0) + x86_mcinfo_dump(mi); + + set_in_cr4(X86_CR4_MCE); + rdmsr (MSR_IA32_MCG_CAP, l, h); + if (l & MCG_CTL_P) /* Control register present ? */ + wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); + + for (i = firstbank; i < nr_mce_banks; i++) + { + /*Some banks are shared across cores, use MCi_CTRL to judge whether + * this bank has been initialized by other cores already.*/ + rdmsr(MSR_IA32_MC0_CTL + 4*i, l, h); + if (!l & !h) + { + /*if ctl is 0, this bank is never initialized*/ + printk(KERN_DEBUG "mce_init: init bank%d\n", i); + wrmsr (MSR_IA32_MC0_CTL + 4*i, 0xffffffff, 0xffffffff); + wrmsr (MSR_IA32_MC0_STATUS + 4*i, 0x0, 0x0); + } + } + if (firstbank) /*if cmci enabled, firstbank = 0*/ + wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0); +} + +/*p4/p6 faimily has similar MCA initialization process*/ +void intel_mcheck_init(struct cpuinfo_x86 *c) +{ + mce_cap_init(c); + printk (KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", + smp_processor_id()); + /* machine check is available */ + machine_check_vector = intel_machine_check; + mce_init(); + mce_intel_feature_init(c); + mce_set_owner(); +} + +/* + * Periodic polling timer for "silent" machine check errors. If the + * poller finds an MCE, poll faster. When the poller finds no more + * errors, poll slower +*/ +static struct timer mce_timer; + +#define MCE_PERIOD 4000 +#define MCE_MIN 2000 +#define MCE_MAX 32000 + +static u64 period = MCE_PERIOD; +static int adjust = 0; + +static void mce_intel_checkregs(void *info) +{ + int nr_unit; + struct mc_info *mi = x86_mcinfo_getptr(); + + if( !mce_available(¤t_cpu_data)) + return; + nr_unit = machine_check_poll(mi, MC_FLAG_POLLED); + if (nr_unit) + { + x86_mcinfo_dump(mi); + adjust++; + if (dom0 && guest_enabled_event(dom0->vcpu[0], VIRQ_MCA)) + send_guest_global_virq(dom0, VIRQ_MCA); + } +} + +static void mce_intel_work_fn(void *data) +{ + on_each_cpu(mce_intel_checkregs, data, 1, 1); + if (adjust) { + period = period / (adjust + 1); + printk(KERN_DEBUG "mcheck_poll: Find error, shorten interval " + "to %"PRIu64"\n", period); + } + else { + period *= 2; + } + if (period > MCE_MAX) + period = MCE_MAX; + if (period < MCE_MIN) + period = MCE_MIN; + set_timer(&mce_timer, NOW() + MILLISECS(period)); + adjust = 0; +} + +void intel_mcheck_timer(struct cpuinfo_x86 *c) +{ + printk(KERN_DEBUG "mcheck_poll: Init_mcheck_timer\n"); + init_timer(&mce_timer, mce_intel_work_fn, NULL, 0); + set_timer(&mce_timer, NOW() + MILLISECS(MCE_PERIOD)); +} + diff -r 9837303a4708 -r 07f26e047fbf xen/arch/x86/cpu/mcheck/non-fatal.c --- a/xen/arch/x86/cpu/mcheck/non-fatal.c Wed Dec 24 12:50:57 2008 +0900 +++ b/xen/arch/x86/cpu/mcheck/non-fatal.c Wed Dec 24 12:52:34 2008 +0900 @@ -19,8 +19,8 @@ #include <asm/msr.h> #include "mce.h" - -static int firstbank; +#include "x86_mca.h" +int firstbank = 0; static struct timer mce_timer; #define MCE_PERIOD MILLISECS(15000) @@ -61,13 +61,8 @@ static int __init init_nonfatal_mce_chec struct cpuinfo_x86 *c = &boot_cpu_data; /* Check for MCE support */ - if (!cpu_has(c, X86_FEATURE_MCE)) + if (!mce_available(c)) return -ENODEV; - - /* Check for PPro style MCA */ - if (!cpu_has(c, X86_FEATURE_MCA)) - return -ENODEV; - /* * Check for non-fatal errors every MCE_RATE s _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |