Index: 2007-05-14/xen/arch/x86/Makefile =================================================================== --- 2007-05-14.orig/xen/arch/x86/Makefile 2007-07-02 12:05:34.000000000 +0200 +++ 2007-05-14/xen/arch/x86/Makefile 2007-07-02 11:55:01.000000000 +0200 @@ -78,7 +78,7 @@ xen.lds: $(TARGET_SUBARCH)/xen.lds.S $(H boot/mkelf32: boot/mkelf32.c $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -boot/$(TARGET_SUBARCH).o: boot/realmode.S +boot/$(TARGET_SUBARCH).o: boot/realmode.S boot/edd.S .PHONY: clean clean:: Index: 2007-05-14/xen/arch/x86/boot/edd.S =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2007-05-14/xen/arch/x86/boot/edd.S 2007-07-02 12:05:50.000000000 +0200 @@ -0,0 +1,217 @@ +/* + * BIOS Enhanced Disk Drive support + * Copyright (C) 2002, 2003, 2004 Dell, Inc. + * by Matt Domsch October 2002 + * conformant to T13 Committee www.t13.org + * projects 1572D, 1484D, 1386D, 1226DT + * disk signature read by Matt Domsch + * and Andrew Wilks September 2003, June 2004 + * legacy CHS retrieval by Patrick J. LoPresti + * March 2004 + * Command line option parsing, Matt Domsch, November 2004 + * Xen adoption by Jan Beulich , February 2007 + */ + +#include + +# It is assumed that %ds == INITSEG here + + movb $0, (EDD_MBR_SIG_NR_BUF) + movb $0, (EDDNR) + +# Check the command line for options: +# edd=of disables EDD completely (edd=off) +# edd=sk skips the MBR test (edd=skipmbr) +# edd=on re-enables EDD (edd=on) + + pushl %esi + movw $SYM_REAL(edd_mbr_sig_start), %di # Default to edd=on + + movl %cs:SYM_REAL(cmd_line_ptr), %esi + andl %esi, %esi + jz done_cl + +# Convert to a real-mode pointer in fs:si + movl %esi, %eax + shrl $4, %eax + mov %ax, %fs + andw $0xf, %si + +# fs:si has the pointer to the command line now + +# Loop through kernel command line one byte at a time. Just in +# case the loader is buggy and failed to null-terminate the command line +# terminate if we get close enough to the end of the segment that we +# cannot fit "edd=XX"... +cl_atspace: + cmpw $-5, %si # Watch for segment wraparound + jae done_cl + movl %fs:(%si), %eax + andb %al, %al # End of line? + jz done_cl + cmpl $EDD_CL_EQUALS, %eax + jz found_edd_equals + cmpb $0x20, %al # <= space consider whitespace + ja cl_skipword + incw %si + jmp cl_atspace + +cl_skipword: + cmpw $-5, %si # Watch for segment wraparound + jae done_cl + movb %fs:(%si), %al # End of string? + andb %al, %al + jz done_cl + cmpb $0x20, %al + jbe cl_atspace + incw %si + jmp cl_skipword + +found_edd_equals: +# only looking at first two characters after equals +# late overrides early on the command line, so keep going after finding something + movw %fs:4(%si), %ax + cmpw $EDD_CL_OFF, %ax # edd=of + je do_edd_off + cmpw $EDD_CL_SKIP, %ax # edd=sk + je do_edd_skipmbr + cmpw $EDD_CL_ON, %ax # edd=on + je do_edd_on + jmp cl_skipword +do_edd_skipmbr: + movw $SYM_REAL(edd_start), %di + jmp cl_skipword +do_edd_off: + movw $SYM_REAL(edd_done), %di + jmp cl_skipword +do_edd_on: + movw $SYM_REAL(edd_mbr_sig_start), %di + jmp cl_skipword + +done_cl: + popl %esi + jmpw *%di + +# Read the first sector of each BIOS disk device and store the 4-byte signature +edd_mbr_sig_start: + movb $0x80, %dl # from device 80 + movw $EDD_MBR_SIG_BUF, %bx # store buffer ptr in bx +edd_mbr_sig_read: + movl $0xFFFFFFFF, %eax + movl %eax, (%bx) # assume failure + pushw %bx + movb $READ_SECTORS, %ah + movb $1, %al # read 1 sector + movb $0, %dh # at head 0 + movw $1, %cx # cylinder 0, sector 0 + pushw %es + pushw %ds + popw %es + movw $EDDBUF, %bx # disk's data goes into EDDBUF + pushw %dx # work around buggy BIOSes + stc # work around buggy BIOSes + int $0x13 + sti # work around buggy BIOSes + popw %dx + popw %es + popw %bx + jc edd_mbr_sig_done # on failure, we're done. + cmpb $0, %ah # some BIOSes do not set CF + jne edd_mbr_sig_done # on failure, we're done. + movl (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR + movl %eax, (%bx) # store success + incb (EDD_MBR_SIG_NR_BUF) # note that we stored something + incb %dl # increment to next device + addw $4, %bx # increment sig buffer ptr + cmpb $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF) # Out of space? + jb edd_mbr_sig_read # keep looping +edd_mbr_sig_done: + +# Do the BIOS Enhanced Disk Drive calls +# This consists of two calls: +# int 13h ah=41h "Check Extensions Present" +# int 13h ah=48h "Get Device Parameters" +# int 13h ah=08h "Legacy Get Device Parameters" +# +# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use +# in the boot_params at EDDBUF. The first four bytes of which are +# used to store the device number, interface support map and version +# results from fn41. The next four bytes are used to store the legacy +# cylinders, heads, and sectors from fn08. The following 74 bytes are used to +# store the results from fn48. Starting from device 80h, fn41, then fn48 +# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE). +# Then the pointer is incremented to store the data for the next call. +# This repeats until either a device doesn't exist, or until EDDMAXNR +# devices have been stored. +# The one tricky part is that ds:si always points EDDEXTSIZE bytes into +# the structure, and the fn41 and fn08 results are stored at offsets +# from there. This removes the need to increment the pointer for +# every store, and leaves it ready for the fn48 call. +# A second one-byte buffer, EDDNR, in the boot_params stores +# the number of BIOS devices which exist, up to EDDMAXNR. +# In setup.c, copy_edd() stores both boot_params buffers away +# for later use, as they would get overwritten otherwise. +# This code is sensitive to the size of the structs in edd.h +edd_start: + # %ds points to the bootsector + # result buffer for fn48 + movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results + # kept just before that + movb $0x80, %dl # BIOS device 0x80 + +edd_check_ext: + movb $CHECKEXTENSIONSPRESENT, %ah # Function 41 + movw $EDDMAGIC1, %bx # magic + int $0x13 # make the call + jc edd_done # no more BIOS devices + + cmpw $EDDMAGIC2, %bx # is magic right? + jne edd_next # nope, next... + + movb %dl, %ds:-8(%si) # store device number + movb %ah, %ds:-7(%si) # store version + movw %cx, %ds:-6(%si) # store extensions + incb (EDDNR) # note that we stored something + +edd_get_device_params: + movw $EDDPARMSIZE, %ds:(%si) # put size + movw $0x0, %ds:2(%si) # work around buggy BIOSes + movb $GETDEVICEPARAMETERS, %ah # Function 48 + int $0x13 # make the call + # Don't check for fail return + # it doesn't matter. +edd_get_legacy_chs: + xorw %ax, %ax + movw %ax, %ds:-4(%si) + movw %ax, %ds:-2(%si) + # Ralf Brown's Interrupt List says to set ES:DI to + # 0000h:0000h "to guard against BIOS bugs" + pushw %es + movw %ax, %es + movw %ax, %di + pushw %dx # legacy call clobbers %dl + movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08 + int $0x13 # make the call + jc edd_legacy_done # failed + movb %cl, %al # Low 6 bits are max + andb $0x3F, %al # sector number + movb %al, %ds:-1(%si) # Record max sect + movb %dh, %ds:-2(%si) # Record max head number + movb %ch, %al # Low 8 bits of max cyl + shr $6, %cl + movb %cl, %ah # High 2 bits of max cyl + movw %ax, %ds:-4(%si) + +edd_legacy_done: + popw %dx + popw %es + movw %si, %ax # increment si + addw $EDDPARMSIZE+EDDEXTSIZE, %ax + movw %ax, %si + +edd_next: + incb %dl # increment to next device + cmpb $EDDMAXNR, (EDDNR) # Out of space? + jb edd_check_ext # keep looping + +edd_done: Index: 2007-05-14/xen/arch/x86/boot/realmode.S =================================================================== --- 2007-05-14.orig/xen/arch/x86/boot/realmode.S 2007-07-02 12:05:34.000000000 +0200 +++ 2007-05-14/xen/arch/x86/boot/realmode.S 2007-07-02 11:55:01.000000000 +0200 @@ -120,3 +120,26 @@ cmd_line_ptr: .long 0 .Lgdt: .skip 2+4 .Lidt: .skip 2+4 .previous + +#define EDDNR SYM_REAL(eddnr) +#define EDDBUF SYM_REAL(eddbuf) +#define EDD_MBR_SIG_NR_BUF SYM_REAL(edd_mbr_sig_nr_buf) +#define EDD_MBR_SIG_BUF SYM_REAL(edd_mbr_sig_buf) + +edd: +#include "edd.S" + ret + + .section .real.data + .globl eddnr, eddbuf, edd_mbr_sig_nr_buf, edd_mbr_sig_buf + .align 4 +eddbuf: .skip EDDMAXNR * (EDDEXTSIZE + EDDPARMSIZE) +#if EDDMAXNR * (EDDEXTSIZE + EDDPARMSIZE) < 512 +/* Must have space for a full 512-byte sector */ + .skip 512 - EDDMAXNR * (EDDEXTSIZE + EDDPARMSIZE) +#endif + .align 4 +edd_mbr_sig_buf: .skip EDD_MBR_SIG_MAX * 4 +eddnr: .skip 1 +edd_mbr_sig_nr_buf: .skip 1 + .previous Index: 2007-05-14/xen/arch/x86/boot/x86_32.S =================================================================== --- 2007-05-14.orig/xen/arch/x86/boot/x86_32.S 2007-07-02 12:05:34.000000000 +0200 +++ 2007-05-14/xen/arch/x86/boot/x86_32.S 2007-07-02 11:55:01.000000000 +0200 @@ -90,6 +90,9 @@ __start: lea __PAGE_OFFSET(%ebx),%eax push %eax + pushl $SYM_PHYS(edd) + call realmode + #ifdef CONFIG_X86_PAE /* Initialize low and high mappings of all memory with 2MB pages */ mov $SYM_PHYS(idle_pg_table_l2),%edi Index: 2007-05-14/xen/arch/x86/boot/x86_64.S =================================================================== --- 2007-05-14.orig/xen/arch/x86/boot/x86_64.S 2007-07-02 12:05:34.000000000 +0200 +++ 2007-05-14/xen/arch/x86/boot/x86_64.S 2007-07-02 11:55:01.000000000 +0200 @@ -73,6 +73,8 @@ __start: mov %ebx,SYM_PHYS(multiboot_ptr) lss SYM_PHYS(.Lstack_start),%esp + pushl $SYM_PHYS(edd) + call realmode /* We begin by interrogating the CPU for the presence of long mode. */ mov $0x80000000,%eax Index: 2007-05-14/xen/arch/x86/platform_hypercall.c =================================================================== --- 2007-05-14.orig/xen/arch/x86/platform_hypercall.c 2007-07-02 12:05:34.000000000 +0200 +++ 2007-05-14/xen/arch/x86/platform_hypercall.c 2007-07-02 11:55:16.000000000 +0200 @@ -20,14 +20,21 @@ #include #include #include +#include #include #include "cpu/mtrr/mtrr.h" #ifndef COMPAT typedef long ret_t; DEFINE_SPINLOCK(xenpf_lock); +struct edd edd; +# undef copy_from_compat +# define copy_from_compat copy_from_guest +# undef copy_to_compat +# define copy_to_compat copy_to_guest #else extern spinlock_t xenpf_lock; +extern struct edd edd; #endif ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) @@ -151,6 +158,66 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe } break; + case XENPF_firmware_info: + switch ( op->u.firmware_info.type ) + { + case XEN_FW_DISK_INFO: { + const struct edd_info *info; + u16 length; + + ret = -ESRCH; + if ( op->u.firmware_info.index >= edd.edd_info_nr ) + break; + + info = edd.edd_info + op->u.firmware_info.index; + + /* Transfer the EDD info block. */ + ret = -EFAULT; + if ( copy_from_compat(&length, op->u.firmware_info.u. + disk_info.edd_params, 1) ) + break; + if ( length > info->edd_device_params.length ) + length = info->edd_device_params.length; + if ( copy_to_compat(op->u.firmware_info.u.disk_info.edd_params, + (u8 *)&info->edd_device_params, + length) ) + break; + + /* Transfer miscellaneous other information values. */ +#define C(x) op->u.firmware_info.u.disk_info.x = info->x + C(device); + C(version); + C(interface_support); + C(legacy_max_cylinder); + C(legacy_max_head); + C(legacy_sectors_per_track); +#undef C + + ret = (copy_field_to_guest(u_xenpf_op, op, + u.firmware_info.u.disk_info) + ? -EFAULT : 0); + break; + } + case XEN_FW_DISK_MBR_SIGNATURE: + ret = -ESRCH; + if ( op->u.firmware_info.index >= edd.mbr_signature_nr ) + break; + + op->u.firmware_info.u.disk_mbr_signature.device = + 0x80 + op->u.firmware_info.index; + op->u.firmware_info.u.disk_mbr_signature.mbr_signature = + edd.mbr_signature[op->u.firmware_info.index]; + + ret = (copy_field_to_guest(u_xenpf_op, op, + u.firmware_info.u.disk_mbr_signature) + ? -EFAULT : 0); + break; + default: + ret = -EINVAL; + break; + } + break; + default: ret = -ENOSYS; break; @@ -161,6 +228,19 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe return ret; } +#ifndef COMPAT +static int __init firmware_init(void) +{ + memcpy(edd.mbr_signature, edd_mbr_sig_buf, sizeof(edd.mbr_signature)); + memcpy(edd.edd_info, eddbuf, sizeof(edd.edd_info)); + edd.mbr_signature_nr = edd_mbr_sig_nr_buf; + edd.edd_info_nr = eddnr; + + return 0; +} +__initcall(firmware_init); +#endif + /* * Local variables: * mode: C Index: 2007-05-14/xen/include/public/platform.h =================================================================== --- 2007-05-14.orig/xen/include/public/platform.h 2007-07-02 12:05:34.000000000 +0200 +++ 2007-05-14/xen/include/public/platform.h 2007-07-02 11:55:01.000000000 +0200 @@ -114,6 +114,37 @@ struct xenpf_platform_quirk { typedef struct xenpf_platform_quirk xenpf_platform_quirk_t; DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t); +#define XENPF_firmware_info 50 +#define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */ +#define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */ +struct xenpf_firmware_info { + /* IN variables. */ + uint32_t type; + uint32_t index; + /* OUT variables. */ + union { + struct { + /* Int13, Fn48: Check Extensions Present. */ + uint8_t device; /* %dl: bios device number */ + uint8_t version; /* %ah: major version */ + uint16_t interface_support; /* %cx: support bitmap */ + /* Int13, Fn08: Legacy Get Device Parameters. */ + uint16_t legacy_max_cylinder; /* %cl[7:6]:%ch: max cyl # */ + uint8_t legacy_max_head; /* %dh: max head # */ + uint8_t legacy_sectors_per_track; /* %cl[5:0]: max sector # */ + /* Int13, Fn41: Get Device Parameters (as filled into %ds:%esi). */ + /* NB. First uint16_t of buffer must be set to buffer size. */ + XEN_GUEST_HANDLE(void) edd_params; + } disk_info; /* XEN_FW_DISK_INFO */ + struct { + uint8_t device; /* bios device number */ + uint32_t mbr_signature; /* offset 0x1b8 in mbr */ + } disk_mbr_signature; /* XEN_FW_DISK_MBR_SIGNATURE */ + } u; +}; +typedef struct xenpf_firmware_info xenpf_firmware_info_t; +DEFINE_XEN_GUEST_HANDLE(xenpf_firmware_info_t); + struct xen_platform_op { uint32_t cmd; uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ @@ -124,6 +155,7 @@ struct xen_platform_op { struct xenpf_read_memtype read_memtype; struct xenpf_microcode_update microcode; struct xenpf_platform_quirk platform_quirk; + struct xenpf_firmware_info firmware_info; uint8_t pad[128]; } u; }; Index: 2007-05-14/xen/include/asm-x86/edd.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2007-05-14/xen/include/asm-x86/edd.h 2007-07-02 11:27:08.000000000 +0200 @@ -0,0 +1,90 @@ +/* + * xen/include/linux/edd.h + * Copyright (C) 2002, 2003, 2004 Dell Inc. + * by Matt Domsch + * Adopted for Xen (C) 2007 Novell, Inc. + * by Jan Beulich + * + * structures and definitions for the int 13h, ax={41,48}h + * BIOS Enhanced Disk Drive Services + * This is based on the T13 group document D1572 Revision 0 (August 14 2002) + * available at http://www.t13.org/docs2002/d1572r0.pdf. It is + * very similar to D1484 Revision 3 http://www.t13.org/docs2002/d1484r3.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2.0 as published by + * the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _XEN_EDD_H +#define _XEN_EDD_H + +#define EDDMAXNR 6 /* number of edd_info structs starting at eddbuf */ +#define EDDEXTSIZE 8 /* change these if you muck with the structures */ +#define EDDPARMSIZE 74 +#define CHECKEXTENSIONSPRESENT 0x41 +#define GETDEVICEPARAMETERS 0x48 +#define LEGACYGETDEVICEPARAMETERS 0x08 +#define EDDMAGIC1 0x55AA +#define EDDMAGIC2 0xAA55 + + +#define READ_SECTORS 0x02 /* int13 AH=0x02 is READ_SECTORS command */ +#define EDD_MBR_SIG_OFFSET 0x1B8 /* offset of signature in the MBR */ +#define EDD_MBR_SIG_MAX 16 /* max number of signatures to store */ +#define EDD_CL_EQUALS 0x3d646465 /* "edd=" */ +#define EDD_CL_OFF 0x666f /* "of" for off */ +#define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */ +#define EDD_CL_ON 0x6e6f /* "on" for on */ + +#ifndef __ASSEMBLY__ + +#define EDD_EXT_FIXED_DISK_ACCESS (1 << 0) +#define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1) +#define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2) +#define EDD_EXT_64BIT_EXTENSIONS (1 << 3) + +#define EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT (1 << 0) +#define EDD_INFO_GEOMETRY_VALID (1 << 1) +#define EDD_INFO_REMOVABLE (1 << 2) +#define EDD_INFO_WRITE_VERIFY (1 << 3) +#define EDD_INFO_MEDIA_CHANGE_NOTIFICATION (1 << 4) +#define EDD_INFO_LOCKABLE (1 << 5) +#define EDD_INFO_NO_MEDIA_PRESENT (1 << 6) +#define EDD_INFO_USE_INT13_FN50 (1 << 7) + +struct edd_info { + /* Int13, Fn48: Check Extensions Present. */ + u8 device; /* %dl: device */ + u8 version; /* %ah: major version */ + u16 interface_support; /* %cx: interface support bitmap */ + /* Int13, Fn08: Legacy Get Device Parameters. */ + u16 legacy_max_cylinder; /* %cl[7:6]:%ch: maximum cylinder number */ + u8 legacy_max_head; /* %dh: maximum head number */ + u8 legacy_sectors_per_track; /* %cl[5:0]: maximum sector number */ + /* Int13, Fn41: Get Device Parameters (as filled into %ds:%esi). */ + struct { + u16 length; + u8 data[72]; + } edd_device_params; +} __attribute__ ((packed)); + +struct edd { + unsigned int mbr_signature[EDD_MBR_SIG_MAX]; + struct edd_info edd_info[EDDMAXNR]; + unsigned char mbr_signature_nr; + unsigned char edd_info_nr; +}; + +extern unsigned char eddnr, edd_mbr_sig_nr_buf; +extern struct edd_info eddbuf[]; +extern unsigned int edd_mbr_sig_buf[]; + +#endif /*!__ASSEMBLY__ */ + +#endif /* _XEN_EDD_H */