File kernel-boot-hvm.patch of Package xen

Direct kernel boot to HVM guests has regression from xen-3.3 to xen-4.0.
Foreport this feature to latest qemu-xen. Make a fake boot sector with given
kernel and initrd, which could be accessed by hvmloader.

Signed-off-by: Chunyan Liu <cyliu@novell.com>

Index: xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/block.c
===================================================================
--- xen-4.6.1-testing.orig/tools/qemu-xen-traditional-dir-remote/block.c
+++ xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/block.c
@@ -596,6 +596,16 @@ int bdrv_read(BlockDriverState *bs, int6
 
     if (bdrv_check_request(bs, sector_num, nb_sectors))
 	return -EIO;
+
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+            memcpy(buf, bs->boot_sector_data, 512);
+        sector_num++;
+        nb_sectors--;
+        buf += 512;
+        if (nb_sectors == 0)
+            return 0;
+    }
+
     if (drv->bdrv_pread) {
         int ret, len;
         len = nb_sectors * 512;
@@ -631,6 +641,10 @@ int bdrv_write(BlockDriverState *bs, int
     if (bdrv_check_request(bs, sector_num, nb_sectors))
         return -EIO;
 
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(bs->boot_sector_data, buf, 512);
+    }
+
     if (drv->bdrv_pwrite) {
         int ret, len, count = 0;
         len = nb_sectors * 512;
@@ -934,6 +948,16 @@ void bdrv_guess_geometry(BlockDriverStat
     }
 }
 
+/* force a given boot sector. */
+void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
+{
+    bs->boot_sector_enabled = 1;
+    if (size > 512)
+        size = 512;
+    memcpy(bs->boot_sector_data, data, size);
+    memset(bs->boot_sector_data + size, 0, 512 - size);
+}
+
 void bdrv_set_geometry_hint(BlockDriverState *bs,
                             int cyls, int heads, int secs)
 {
@@ -1464,6 +1488,14 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDri
     if (bdrv_check_request(bs, sector_num, nb_sectors))
         return NULL;
 
+    /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(buf, bs->boot_sector_data, 512);
+        sector_num++;
+        nb_sectors--;
+        buf += 512;
+    }
+
     ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
 
     if (ret) {
@@ -1489,6 +1521,10 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDr
     if (bdrv_check_request(bs, sector_num, nb_sectors))
         return NULL;
 
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(bs->boot_sector_data, buf, 512);
+    }
+
     ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
 
     if (ret) {
Index: xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/block_int.h
===================================================================
--- xen-4.6.1-testing.orig/tools/qemu-xen-traditional-dir-remote/block_int.h
+++ xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/block_int.h
@@ -122,6 +122,9 @@ struct BlockDriverState {
     BlockDriver *drv; /* NULL means no media */
     void *opaque;
 
+    int boot_sector_enabled;
+    uint8_t boot_sector_data[512];
+
     char filename[1024];
     char backing_file[1024]; /* if non zero, the image is a diff of
                                 this file image */
Index: xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/hw/pc.c
===================================================================
--- xen-4.6.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/pc.c
+++ xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/hw/pc.c
@@ -473,45 +473,28 @@ static void bochs_bios_init(void)
 
 /* Generate an initial boot sector which sets state and jump to
    a specified vector */
-static void generate_bootsect(uint8_t *option_rom,
-                              uint32_t gpr[8], uint16_t segs[6], uint16_t ip)
+static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip)
 {
-    uint8_t rom[512], *p, *reloc;
-    uint8_t sum;
+    uint8_t bootsect[512], *p;
     int i;
+    int hda;
 
-    memset(rom, 0, sizeof(rom));
+    hda = drive_get_index(IF_IDE, 0, 0);
+    if (hda == -1) {
+	fprintf(stderr, "A disk image must be given for 'hda' when booting "
+		"a Linux kernel\n(if you really don't want it, use /dev/zero)\n");
+	exit(1);
+    }
+    memset(bootsect, 0, sizeof(bootsect));
 
-    p = rom;
-    /* Make sure we have an option rom signature */
-    *p++ = 0x55;
-    *p++ = 0xaa;
-
-    /* ROM size in sectors*/
-    *p++ = 1;
-
-    /* Hook int19 */
-
-    *p++ = 0x50;		/* push ax */
-    *p++ = 0x1e;		/* push ds */
-    *p++ = 0x31; *p++ = 0xc0;	/* xor ax, ax */
-    *p++ = 0x8e; *p++ = 0xd8;	/* mov ax, ds */
-
-    *p++ = 0xc7; *p++ = 0x06;   /* movvw _start,0x64 */
-    *p++ = 0x64; *p++ = 0x00;
-    reloc = p;
-    *p++ = 0x00; *p++ = 0x00;
-
-    *p++ = 0x8c; *p++ = 0x0e;   /* mov cs,0x66 */
-    *p++ = 0x66; *p++ = 0x00;
-
-    *p++ = 0x1f;		/* pop ds */
-    *p++ = 0x58;		/* pop ax */
-    *p++ = 0xcb;		/* lret */
-    
-    /* Actual code */
-    *reloc = (p - rom);
+    /* Copy the MSDOS partition table if possible */
+    bdrv_read(drives_table[hda].bdrv, 0, bootsect, 1);
+    /* Make sure we have a partition signature */
+    bootsect[510] = 0x55;
+    bootsect[511] = 0xaa;
 
+     /* Actual code */
+    p = bootsect;
     *p++ = 0xfa;		/* CLI */
     *p++ = 0xfc;		/* CLD */
 
@@ -541,13 +524,7 @@ static void generate_bootsect(uint8_t *o
     *p++ = segs[1];		/* CS */
     *p++ = segs[1] >> 8;
 
-    /* sign rom */
-    sum = 0;
-    for (i = 0; i < (sizeof(rom) - 1); i++)
-        sum += rom[i];
-    rom[sizeof(rom) - 1] = -sum;
-
-    memcpy(option_rom, rom, sizeof(rom));
+    bdrv_set_boot_sector(drives_table[hda].bdrv, bootsect, sizeof(bootsect));
 }
 
 static long get_file_size(FILE *f)
@@ -564,8 +541,7 @@ static long get_file_size(FILE *f)
     return size;
 }
 
-static void load_linux(uint8_t *option_rom,
-                       const char *kernel_filename,
+static void load_linux(const char *kernel_filename,
 		       const char *initrd_filename,
 		       const char *kernel_cmdline)
 {
@@ -631,7 +607,9 @@ static void load_linux(uint8_t *option_r
 
     /* Special pages are placed at end of low RAM: pick an arbitrary one and
      * subtract a suitably large amount of padding (64kB) to skip BIOS data. */
-    xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &end_low_ram);
+    //xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &end_low_ram);
+    /* BUFIO Page beyond last_pfn, use 0x7ffc instead. Fix ME. */
+    end_low_ram = 0x7ffc;
     end_low_ram = (end_low_ram << 12) - (64*1024);
 
     /* highest address for loading the initrd */
@@ -720,7 +698,7 @@ static void load_linux(uint8_t *option_r
     memset(gpr, 0, sizeof gpr);
     gpr[4] = cmdline_addr-real_addr-16;	/* SP (-16 is paranoia) */
 
-    generate_bootsect(option_rom, gpr, seg, 0);
+    generate_bootsect(gpr, seg, 0);
 #endif
 }
 
@@ -930,14 +908,6 @@ vga_bios_error:
         int size, offset;
 
         offset = 0;
-        if (linux_boot) {
-            option_rom_offset = qemu_ram_alloc(TARGET_PAGE_SIZE);
-            load_linux(phys_ram_base + option_rom_offset,
-                       kernel_filename, initrd_filename, kernel_cmdline);
-            cpu_register_physical_memory(0xd0000, TARGET_PAGE_SIZE,
-                                         option_rom_offset | IO_MEM_ROM);
-            offset = TARGET_PAGE_SIZE;
-        }
 
         for (i = 0; i < nb_option_roms; i++) {
             size = get_image_size(option_rom[i]);
@@ -971,6 +941,9 @@ vga_bios_error:
 
     bochs_bios_init();
 
+    if (linux_boot)
+        load_linux(kernel_filename, initrd_filename, kernel_cmdline);
+
     i8259 = i8259_init(NULL);
     ferr_irq = i8259[13];
 
Index: xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/block.h
===================================================================
--- xen-4.6.1-testing.orig/tools/qemu-xen-traditional-dir-remote/block.h
+++ xen-4.6.1-testing/tools/qemu-xen-traditional-dir-remote/block.h
@@ -82,6 +82,7 @@ int64_t bdrv_getlength(BlockDriverState
 void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
 void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
 int bdrv_commit(BlockDriverState *bs);
+void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
 /* async block I/O */
 typedef struct BlockDriverAIOCB BlockDriverAIOCB;
 typedef void BlockDriverCompletionFunc(void *opaque, int ret);