Jan Beulich
2007-Mar-02 10:32 UTC
[Xen-devel] [PATCH 2/3] x86: real mode support: get EDD info
Obtain EDD info from BIOS and pass it up to Dom0. Signed-off-by: Jan Beulich <jbeulich@novell.com> Index: 2007-02-27/xen/arch/x86/Makefile ==================================================================--- 2007-02-27.orig/xen/arch/x86/Makefile 2007-02-22 16:14:25.000000000 +0100 +++ 2007-02-27/xen/arch/x86/Makefile 2007-02-22 15:57:24.000000000 +0100 @@ -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-02-27/xen/arch/x86/boot/edd.S ==================================================================--- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2007-02-27/xen/arch/x86/boot/edd.S 2007-02-21 17:45:32.000000000 +0100 @@ -0,0 +1,217 @@ +/* + * BIOS Enhanced Disk Drive support + * Copyright (C) 2002, 2003, 2004 Dell, Inc. + * by Matt Domsch <Matt_Domsch@dell.com> October 2002 + * conformant to T13 Committee www.t13.org + * projects 1572D, 1484D, 1386D, 1226DT + * disk signature read by Matt Domsch <Matt_Domsch@dell.com> + * and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004 + * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net> + * March 2004 + * Command line option parsing, Matt Domsch, November 2004 + * Xen adoption by Jan Beulich <jbeulich@novell.com>, February 2007 + */ + +#include <xen/edd.h> + +# 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-02-27/xen/arch/x86/boot/realmode.S ==================================================================--- 2007-02-27.orig/xen/arch/x86/boot/realmode.S 2007-02-22 16:14:25.000000000 +0100 +++ 2007-02-27/xen/arch/x86/boot/realmode.S 2007-02-22 15:58:16.000000000 +0100 @@ -118,3 +118,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-02-27/xen/arch/x86/boot/x86_32.S ==================================================================--- 2007-02-27.orig/xen/arch/x86/boot/x86_32.S 2007-02-22 16:14:25.000000000 +0100 +++ 2007-02-27/xen/arch/x86/boot/x86_32.S 2007-02-21 18:08:44.000000000 +0100 @@ -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-02-27/xen/arch/x86/boot/x86_64.S ==================================================================--- 2007-02-27.orig/xen/arch/x86/boot/x86_64.S 2007-02-22 16:14:25.000000000 +0100 +++ 2007-02-27/xen/arch/x86/boot/x86_64.S 2007-02-21 17:55:02.000000000 +0100 @@ -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-02-27/xen/arch/x86/platform_hypercall.c ==================================================================--- 2007-02-27.orig/xen/arch/x86/platform_hypercall.c 2007-02-22 16:14:25.000000000 +0100 +++ 2007-02-27/xen/arch/x86/platform_hypercall.c 2007-02-22 16:14:39.000000000 +0100 @@ -17,6 +17,7 @@ #include <xen/trace.h> #include <xen/console.h> #include <xen/iocap.h> +#include <xen/edd.h> #include <xen/guest_access.h> #include <asm/current.h> #include <public/platform.h> @@ -26,8 +27,14 @@ #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,73 @@ 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: + if ( op->u.firmware_info.index < edd.edd_info_nr ) + { + const struct edd_info *info = edd.edd_info + op->u.firmware_info.index; + + op->u.firmware_info.u.disk_info.max_cylinder = info->legacy_max_cylinder; + op->u.firmware_info.u.disk_info.max_head = info->legacy_max_head; + op->u.firmware_info.u.disk_info.sectors_per_track = info->legacy_sectors_per_track; + if ( copy_field_to_guest(u_xenpf_op, op, u.firmware_info.u.disk_info) ) + ret = -EFAULT; + } + else + ret = -ESRCH; + break; + case XEN_FW_EDD_INFO: + if ( op->u.firmware_info.index < edd.edd_info_nr ) + { + const struct edd_info *info = edd.edd_info + op->u.firmware_info.index; + + op->u.firmware_info.u.edd_info.device = info->device; + op->u.firmware_info.u.edd_info.version = info->version; + op->u.firmware_info.u.edd_info.interface = info->interface_support; + if ( copy_field_to_guest(u_xenpf_op, op, u.firmware_info.u.edd_info) ) + ret = -EFAULT; + } + else + ret = -ESRCH; + break; + case XEN_FW_EDD_PARAMS: + if ( op->u.firmware_info.index < edd.edd_info_nr ) + { + u16 length; + + if ( copy_from_compat(&length, op->u.firmware_info.u.edd_params, 1) == 0 ) + { + if ( length > edd.edd_info[op->u.firmware_info.index].params.length ) + length = edd.edd_info[op->u.firmware_info.index].params.length; + if ( copy_to_compat(op->u.firmware_info.u.edd_params, + (u8*)&edd.edd_info[op->u.firmware_info.index].params, + length) ) + ret = -EFAULT; + } + else + ret = -EFAULT; + } + else + ret = -ESRCH; + break; + case XEN_FW_MBR_SIGNATURE: + if ( op->u.firmware_info.index < edd.mbr_signature_nr ) + { + op->u.firmware_info.u.mbr_signature = edd.mbr_signature[op->u.firmware_info.index]; + if ( copy_field_to_guest(u_xenpf_op, op, u.firmware_info.u.mbr_signature) ) + ret = -EFAULT; + } + else + ret = -ESRCH; + break; + default: + ret = -EINVAL; + break; + } + break; + default: ret = -ENOSYS; break; @@ -161,6 +235,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-02-27/xen/include/public/platform.h ==================================================================--- 2007-02-27.orig/xen/include/public/platform.h 2007-02-22 16:14:25.000000000 +0100 +++ 2007-02-27/xen/include/public/platform.h 2007-02-21 14:51:00.000000000 +0100 @@ -114,6 +114,35 @@ 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 */ +#define XEN_FW_EDD_INFO 2 /* from int 13 AH=41 */ +#define XEN_FW_EDD_PARAMS 3 /* from int 13 AH=48 */ +#define XEN_FW_MBR_SIGNATURE 4 +struct xenpf_firmware_info { + /* IN variables. */ + uint32_t type; + uint32_t index; + /* OUT variables. */ + union { + struct { + uint16_t max_cylinder; + uint8_t max_head; + uint8_t sectors_per_track; + } disk_info; + struct { + uint8_t device; + uint8_t version; + uint16_t interface; + } edd_info; + /* first uint16_t of buffer must be set to buffer size */ + XEN_GUEST_HANDLE(void) edd_params; + uint32_t 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 +153,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-02-27/xen/include/xen/edd.h ==================================================================--- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2007-02-27/xen/include/xen/edd.h 2007-02-21 12:19:19.000000000 +0100 @@ -0,0 +1,193 @@ +/* + * xen/include/linux/edd.h + * Copyright (C) 2002, 2003, 2004 Dell Inc. + * by Matt Domsch <Matt_Domsch@dell.com> + * Adopted for Xen (C) 2007 Novell, Inc. + * by Jan Beulich <jbeulich@novell.com> + * + * 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 + * + * In a nutshell, arch/{i386,x86_64}/boot/setup.S populates a scratch + * table in the boot_params that contains a list of BIOS-enumerated + * boot devices. + * In arch/{i386,x86_64}/kernel/setup.c, this information is + * transferred into the edd structure, and in drivers/firmware/edd.c, that + * information is used to identify BIOS boot disk. The code in setup.S + * is very sensitive to the size of these structures. + * + * 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_device_params { + u16 length; + u16 info_flags; + u32 num_default_cylinders; + u32 num_default_heads; + u32 sectors_per_track; + u64 number_of_sectors; + u16 bytes_per_sector; + u32 dpte_ptr; /* 0xFFFFFFFF for our purposes */ + u16 key; /* = 0xBEDD */ + u8 device_path_info_length; /* = 44 */ + u8 reserved2; + u16 reserved3; + u8 host_bus_type[4]; + u8 interface_type[8]; + union { + struct { + u16 base_address; + u16 reserved1; + u32 reserved2; + } __attribute__ ((packed)) isa; + struct { + u8 bus; + u8 slot; + u8 function; + u8 channel; + u32 reserved; + } __attribute__ ((packed)) pci; + /* pcix is same as pci */ + struct { + u64 reserved; + } __attribute__ ((packed)) ibnd; + struct { + u64 reserved; + } __attribute__ ((packed)) xprs; + struct { + u64 reserved; + } __attribute__ ((packed)) htpt; + struct { + u64 reserved; + } __attribute__ ((packed)) unknown; + } interface_path; + union { + struct { + u8 device; + u8 reserved1; + u16 reserved2; + u32 reserved3; + u64 reserved4; + } __attribute__ ((packed)) ata; + struct { + u8 device; + u8 lun; + u8 reserved1; + u8 reserved2; + u32 reserved3; + u64 reserved4; + } __attribute__ ((packed)) atapi; + struct { + u16 id; + u64 lun; + u16 reserved1; + u32 reserved2; + } __attribute__ ((packed)) scsi; + struct { + u64 serial_number; + u64 reserved; + } __attribute__ ((packed)) usb; + struct { + u64 eui; + u64 reserved; + } __attribute__ ((packed)) i1394; + struct { + u64 wwid; + u64 lun; + } __attribute__ ((packed)) fibre; + struct { + u64 identity_tag; + u64 reserved; + } __attribute__ ((packed)) i2o; + struct { + u32 array_number; + u32 reserved1; + u64 reserved2; + } __attribute__ ((packed)) raid; + struct { + u8 device; + u8 reserved1; + u16 reserved2; + u32 reserved3; + u64 reserved4; + } __attribute__ ((packed)) sata; + struct { + u64 reserved1; + u64 reserved2; + } __attribute__ ((packed)) unknown; + } device_path; + u8 reserved4; + u8 checksum; +} __attribute__ ((packed)); + +struct edd_info { + u8 device; + u8 version; + u16 interface_support; + u16 legacy_max_cylinder; + u8 legacy_max_head; + u8 legacy_sectors_per_track; + struct edd_device_params 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 */ Index: 2007-02-27/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c ==================================================================--- 2007-02-27.orig/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c 2007-02-21 16:57:23.000000000 +0100 +++ 2007-02-27/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c 2007-02-21 14:24:52.000000000 +0100 @@ -66,6 +66,7 @@ #include <xen/interface/physdev.h> #include <xen/interface/memory.h> #include <xen/features.h> +#include <xen/firmware.h> #include <xen/xencons.h> #include <setup_arch.h> #include <bios_ebda.h> @@ -740,6 +741,7 @@ struct edd edd; #ifdef CONFIG_EDD_MODULE EXPORT_SYMBOL(edd); #endif +#ifndef CONFIG_XEN /** * copy_edd() - Copy the BIOS EDD information * from boot_params into a safe place. @@ -752,6 +754,7 @@ static inline void copy_edd(void) edd.mbr_signature_nr = EDD_MBR_SIG_NR; edd.edd_info_nr = EDD_NR; } +#endif #else static inline void copy_edd(void) { Index: 2007-02-27/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c ==================================================================--- 2007-02-27.orig/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c 2007-02-21 16:57:23.000000000 +0100 +++ 2007-02-27/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c 2007-02-21 14:25:07.000000000 +0100 @@ -71,6 +71,7 @@ #include <asm/hypervisor.h> #include <xen/interface/nmi.h> #include <xen/features.h> +#include <xen/firmware.h> #include <xen/xencons.h> #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_PHYS(x) ((x) << PAGE_SHIFT) @@ -534,6 +535,7 @@ struct edd edd; #ifdef CONFIG_EDD_MODULE EXPORT_SYMBOL(edd); #endif +#ifndef CONFIG_XEN /** * copy_edd() - Copy the BIOS EDD information * from boot_params into a safe place. @@ -546,6 +548,7 @@ static inline void copy_edd(void) edd.mbr_signature_nr = EDD_MBR_SIG_NR; edd.edd_info_nr = EDD_NR; } +#endif #else static inline void copy_edd(void) { Index: 2007-02-27/linux-2.6-xen-sparse/drivers/firmware/Kconfig ==================================================================--- 2007-02-27.orig/linux-2.6-xen-sparse/drivers/firmware/Kconfig 2007-02-21 16:57:23.000000000 +0100 +++ 2007-02-27/linux-2.6-xen-sparse/drivers/firmware/Kconfig 2007-02-21 14:19:11.000000000 +0100 @@ -8,7 +8,6 @@ menu "Firmware Drivers" config EDD tristate "BIOS Enhanced Disk Drive calls determine boot disk" depends on !IA64 - depends on !XEN help Say Y or M here if you want to enable BIOS Enhanced Disk Drive Services real mode BIOS calls to determine which disk Index: 2007-02-27/linux-2.6-xen-sparse/drivers/xen/core/Makefile ==================================================================--- 2007-02-27.orig/linux-2.6-xen-sparse/drivers/xen/core/Makefile 2007-02-21 16:57:42.000000000 +0100 +++ 2007-02-27/linux-2.6-xen-sparse/drivers/xen/core/Makefile 2007-02-21 17:02:28.000000000 +0100 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := evtchn.o gnttab.o features.o +obj-y := evtchn.o gnttab.o features.o firmware.o obj-$(CONFIG_PROC_FS) += xen_proc.o obj-$(CONFIG_SYSFS) += hypervisor_sysfs.o Index: 2007-02-27/linux-2.6-xen-sparse/drivers/xen/core/firmware.c ==================================================================--- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2007-02-27/linux-2.6-xen-sparse/drivers/xen/core/firmware.c 2007-02-21 17:09:28.000000000 +0100 @@ -0,0 +1,61 @@ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/edd.h> +#include <xen/interface/platform.h> +#include <asm/hypervisor.h> + +#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) +void __init copy_edd(void) +{ + int ret; + xen_platform_op_t op; + + if (!is_initial_xendomain()) + return; + + op.cmd = XENPF_firmware_info; + + for (op.u.firmware_info.index = 0, ret = 0; + ret != -ESRCH && ret != -ENOSYS && edd.edd_info_nr < EDDMAXNR; + ++op.u.firmware_info.index) { + struct edd_info *info = edd.edd_info + edd.edd_info_nr; + + op.u.firmware_info.type = XEN_FW_EDD_INFO; + ret = HYPERVISOR_platform_op(&op); + if (ret) + continue; + info->device = op.u.firmware_info.u.edd_info.device; + info->version = op.u.firmware_info.u.edd_info.version; + info->interface_support = op.u.firmware_info.u.edd_info.interface; + + op.u.firmware_info.type = XEN_FW_DISK_INFO; + ret = HYPERVISOR_platform_op(&op); + if (ret) + continue; + info->legacy_max_cylinder = op.u.firmware_info.u.disk_info.max_cylinder; + info->legacy_max_head = op.u.firmware_info.u.disk_info.max_head; + info->legacy_sectors_per_track = op.u.firmware_info.u.disk_info.sectors_per_track; + + op.u.firmware_info.type = XEN_FW_EDD_PARAMS; + info->params.length = sizeof(info->params); + set_xen_guest_handle(op.u.firmware_info.u.edd_params, &info->params); + ret = HYPERVISOR_platform_op(&op); + if (ret) + continue; + + ++edd.edd_info_nr; + } + + op.u.firmware_info.type = XEN_FW_MBR_SIGNATURE; + for (op.u.firmware_info.index = 0, ret = 0; + ret != -ESRCH && ret != -ENOSYS && edd.mbr_signature_nr < EDD_MBR_SIG_MAX; + ++op.u.firmware_info.index) { + + ret = HYPERVISOR_platform_op(&op); + if (ret) + continue; + edd.mbr_signature[edd.mbr_signature_nr++] = op.u.firmware_info.u.mbr_signature; + } +} +#endif Index: 2007-02-27/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h ==================================================================--- 2007-02-27.orig/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h 2007-02-21 16:57:23.000000000 +0100 +++ 2007-02-27/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h 2007-02-21 14:59:20.000000000 +0100 @@ -209,6 +209,14 @@ HYPERVISOR_dom0_op( } static inline int +HYPERVISOR_platform_op( + xen_platform_op_t *platform_op) +{ + platform_op->interface_version = XENPF_INTERFACE_VERSION; + return _hypercall1(int, platform_op, platform_op); +} + +static inline int HYPERVISOR_set_debugreg( int reg, unsigned long value) { Index: 2007-02-27/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h ==================================================================--- 2007-02-27.orig/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h 2007-02-21 16:57:23.000000000 +0100 +++ 2007-02-27/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h 2007-02-21 15:01:06.000000000 +0100 @@ -212,6 +212,14 @@ HYPERVISOR_dom0_op( } static inline int +HYPERVISOR_platform_op( + xen_platform_op_t *platform_op) +{ + platform_op->interface_version = XENPF_INTERFACE_VERSION; + return _hypercall1(int, platform_op, platform_op); +} + +static inline int HYPERVISOR_set_debugreg( int reg, unsigned long value) { Index: 2007-02-27/linux-2.6-xen-sparse/include/xen/firmware.h ==================================================================--- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2007-02-27/linux-2.6-xen-sparse/include/xen/firmware.h 2007-02-21 14:26:55.000000000 +0100 @@ -0,0 +1,6 @@ +#ifndef __XEN_FIRMWARE_H__ +#define __XEN_FIRMWARE_H__ + +void copy_edd(void); + +#endif /* __XEN_FIRMWARE_H__ */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2007-Mar-02 11:15 UTC
Re: [Xen-devel] [PATCH 2/3] x86: real mode support: get EDD info
On 2/3/07 10:32, "Jan Beulich" <jbeulich@novell.com> wrote:> Obtain EDD info from BIOS and pass it up to Dom0.What data format are the EDD/EDID buffers filled with? The format is not defined in the public headers. Is it simply whatever Linux happens to be using internally? I am still interested in trying out an interface to let dom0 request code to be run in various modes and on various CPUs. This would be attractive in this case, assuming that these BIOS calls could be made later than very early bootstrap, as it would avoid piling code into Xen, and assumptions about info data formats, just because of the environment that the interrogating code needs to be executed in. No doubt it is a larger initial amount of engineering effort up front though. Also I''m not sure if there would be any subtle gotchas to running this skanky BIOS code later in the boot sequence (I''d be optimistic that it''d just work though). -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jan Beulich
2007-Mar-02 11:26 UTC
Re: [Xen-devel] [PATCH 2/3] x86: real mode support: get EDD info
>>> Keir Fraser <keir@xensource.com> 02.03.07 12:15 >>> >On 2/3/07 10:32, "Jan Beulich" <jbeulich@novell.com> wrote: > >> Obtain EDD info from BIOS and pass it up to Dom0. > >What data format are the EDD/EDID buffers filled with? The format is not >defined in the public headers. Is it simply whatever Linux happens to be >using internally?No, this is the BIOS format. Linux uses this directly. I specifically (based on past comment from you) avoided introducing Linux specifics.>I am still interested in trying out an interface to let dom0 request code to >be run in various modes and on various CPUs. This would be attractive in >this case, assuming that these BIOS calls could be made later than very >early bootstrap, as it would avoid piling code into Xen, and assumptions >about info data formats, just because of the environment that the >interrogating code needs to be executed in. No doubt it is a larger initial >amount of engineering effort up front though. Also I''m not sure if there >would be any subtle gotchas to running this skanky BIOS code later in the >boot sequence (I''d be optimistic that it''d just work though).Possible, but especially on x86-64 undesirable in my opinion. Also, I''ll want the base real mode stuff in anyway (regardless of EDD/EDID) in order to be able to set up a VESA frame buffer mode for the console. This clearly should be done by Xen in order to ensure it knows how to access the console in case it is allowed access past dom0 creation. Jan _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2007-Mar-02 11:35 UTC
Re: [Xen-devel] [PATCH 2/3] x86: real mode support: get EDD info
On 2/3/07 11:26, "Jan Beulich" <jbeulich@novell.com> wrote:> Possible, but especially on x86-64 undesirable in my opinion.It''s certainly more of a pain to make the mode switch, but not impossible by any means.> Also, I''ll want > the base real mode stuff in anyway (regardless of EDD/EDID) in order to > be able to set up a VESA frame buffer mode for the console. This clearly > should be done by Xen in order to ensure it knows how to access the > console in case it is allowed access past dom0 creation.Oh yes, we definitely want the mode-switching code in Xen. No doubt about that. The question is whether we pull in the EDD/EDID stuff as well. The fact that the data format is BIOS-defined does make the current approach plausible if not particularly tasteful architecturally speaking (but what BIOS stuff is? :-). -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Petersson, Mats
2007-Mar-02 11:49 UTC
RE: [Xen-devel] [PATCH 2/3] x86: real mode support: get EDD info
> -----Original Message----- > From: xen-devel-bounces@lists.xensource.com > [mailto:xen-devel-bounces@lists.xensource.com] On Behalf Of > Keir Fraser > Sent: 02 March 2007 11:36 > To: Jan Beulich; xen-devel@lists.xensource.com; Keir Fraser > Subject: Re: [Xen-devel] [PATCH 2/3] x86: real mode support: > get EDD info > > On 2/3/07 11:26, "Jan Beulich" <jbeulich@novell.com> wrote: > > > Possible, but especially on x86-64 undesirable in my opinion. > > It''s certainly more of a pain to make the mode switch, but > not impossible by > any means.It''s not that much harder as long as you have some region of (below 1MB is probably best) memory that is 1:1 mapped that you can put the code into. Jump to a 32-bit segment (i.e. cs.attr.large-mode = 0) in low memory, turn off LME in EFER and PG in CR0, then turn off PE in CR0 and you''re in real-mode. Of course to make the environment work for real-mode, there''s a whole bunch of other stuff that needs to be done (interrupt vector table at address zero for example), but that should be the same whether you run 64- or 32-bit code in the first place. -- Mats> > > Also, I''ll want > > the base real mode stuff in anyway (regardless of EDD/EDID) > in order to > > be able to set up a VESA frame buffer mode for the console. > This clearly > > should be done by Xen in order to ensure it knows how to access the > > console in case it is allowed access past dom0 creation. > > Oh yes, we definitely want the mode-switching code in Xen. No > doubt about > that. The question is whether we pull in the EDD/EDID stuff > as well. The > fact that the data format is BIOS-defined does make the > current approach > plausible if not particularly tasteful architecturally > speaking (but what > BIOS stuff is? :-). > > -- Keir > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel