diff --git a/elf_ops.h b/elf_ops.h
index 6126565..ab5fd7b 100644
--- a/elf_ops.h
+++ b/elf_ops.h
@@ -156,6 +156,10 @@ static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
     }
 
     if (ELF_MACHINE != ehdr.e_machine)
+#if (ELF_MACHINE == EM_X86_64) && !CONFIG_USER_ONLY
+      /* x86_64 systems can run i386 code as well */
+      if(ehdr.e_machine != EM_386)
+#endif
         goto fail;
 
     if (pentry)
diff --git a/hw/pc.c b/hw/pc.c
index b4f0db7..4c5ee94 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -480,6 +480,416 @@ static long get_file_size(FILE *f)
     return size;
 }
 
+/* Generate an initial boot sector which sets state and jump to
+   a specified vector */
+static void generate_bootsect_multiboot(uint32_t mh_entry_addr, uint32_t bootinfo)
+{
+    uint8_t bootsect[512], *p, *pgdt, *pmmaploop;
+    uint32_t ip;
+    int i;
+    int hda;
+    int mmaploop;
+
+    hda = drive_get_index(IF_IDE, 0, 0);
+    if (hda == -1) {
+	fprintf(stderr, "A disk image must be given for 'hda' when booting "
+		"a Multiboot kernel\n");
+	exit(1);
+    }
+
+    memset(bootsect, 0, sizeof(bootsect));
+
+    /* 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 */
+
+    // 660f011528000000               lgdt        [0x28]
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0x0f;                /* LGDT [0x128] */
+    *p++ = 0x01;
+    *p++ = 0x15;
+    pgdt=p; /* we calculate the gdt position later */
+    p+=4;
+
+    /* Initialize multiboot mmap structs using the 0x15(e820) */
+    *p++ = 0x31;                /* XOR BX,BX */
+    *p++ = 0xdb;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0xbf;                /* MOV EDI,0x9004 */
+    *p++ = 0x04;
+    *p++ = 0x90;
+    *p++ = 0x00;
+    *p++ = 0x00;
+
+    pmmaploop = p;
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0xb8;                /* MOV EAX,0x20 */
+    *p++ = 0x20;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    *p++ = 0x00;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0x89;                /* MOV -4(EDI),EAX */
+    *p++ = 0x47;
+    *p++ = 0xfc;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0xb8;                /* MOV EAX,0x0000e820 */
+    *p++ = 0x20;
+    *p++ = 0xe8;
+    *p++ = 0x00;
+    *p++ = 0x00;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0xba;                /* MOV EDX,0x534d4150 */
+    *p++ = 0x50;
+    *p++ = 0x41;
+    *p++ = 0x4d;
+    *p++ = 0x53;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0xb9;                /* MOV ECX,0x20 */
+    *p++ = 0x20;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    *p++ = 0x00;
+
+    *p++ = 0xcd;                /* INT 0x15 */
+    *p++ = 0x15;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0xb8;                /* MOV EAX, 0x24 */
+    *p++ = 0x24;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    
+    *p++ = 0xf7;                /* MUL AX, BX */
+    *p++ = 0xe3;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0x21;                /* AND EBX, EBX */
+    *p++ = 0xdb;
+
+    /* don't store if bx = 0 */
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0x0f;                /* JZ next instruction */
+    *p++ = 0x84;
+    *p++ = 0x07;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    *p++ = 0x00;
+
+    /* store the amount of blocks in the bootinfo struct */
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0xa3;                /* MOV [bootinfo+0x2c], EAX */
+    *p++ = (bootinfo+0x2c);
+    *p++ = (bootinfo+0x2c) >> 8;
+    *p++ = (bootinfo+0x2c) >> 16;
+    *p++ = (bootinfo+0x2c) >> 24;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0x05;                /* ADD EAX, 0x9004 */
+    *p++ = 0x04;
+    *p++ = 0x90;
+    *p++ = 0x00;
+    *p++ = 0x00;
+
+    *p++ = 0x89;                /* MOV DI, AX */
+    *p++ = 0xc7;
+
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0x21;                /* AND EBX, EBX */
+    *p++ = 0xdb;
+
+    /* process next entry */
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0x67;                /* 32-bit addr size */
+    *p++ = 0x0f;                /* JNZ mmaploop */
+    *p++ = 0x85;
+    mmaploop = (int)((long)pmmaploop) - ((long)p) - 4;
+    *p++ = mmaploop;
+    *p++ = mmaploop >> 8;
+    *p++ = mmaploop >> 16;
+    *p++ = mmaploop >> 24;
+    
+    /* get us to protected mode now */
+    
+    *p++ = 0x66;
+    *p++ = 0xb8;                /* MOV EAX,0x01 */
+    *p++ = 0x01;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    
+    *p++ = 0x0f;                /* MOV CR0,EAX */
+    *p++ = 0x22;
+    *p++ = 0xc0;
+
+    /* the JMP sets CS for us and gets us to 32-bit */
+    ip = 0x00007c00 + (p - bootsect) + 8; // set i to the IP after the JMP
+    *p++ = 0x66;                /* 32-bit operand size */
+    *p++ = 0xea;                /* JMP */
+    *p++ = ip;        /* IP */
+    *p++ = ip >> 8;
+    *p++ = ip >> 16;
+    *p++ = ip >> 24;
+    *p++ = 0x08;
+    *p++ = 0x00;
+    
+    /* initialize all other segments */
+    *p++ = 0xb8;                /* MOV EAX,0x10 */
+    *p++ = 0x10;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    *p++ = 0x00;
+    for (i = 0; i < 6; i++) {
+        if (i == 1)                /* Skip CS */
+            continue;
+
+        *p++ = 0x8e;                /* MOV <seg>,EAX */
+        *p++ = 0xc0 + (i << 3);
+    }
+
+    /* EBX contains a pointer to the bootinfo struct */
+    *p++ = 0xbb;                /* MOV EBX,imm32 */
+    *p++ = bootinfo;
+    *p++ = bootinfo >> 8;
+    *p++ = bootinfo >> 16;
+    *p++ = bootinfo >> 24;
+
+    /* EAX has to contain the following magic */
+    *p++ = 0xb8;                /* MOV EAX,0x2badb002 */
+    *p++ = 0x02;
+    *p++ = 0xb0;
+    *p++ = 0xad;
+    *p++ = 0x2b;
+
+    /* Jump off to the kernel */
+    *p++ = 0xea;                /* JMP */
+    *p++ = mh_entry_addr;        /* IP */
+    *p++ = mh_entry_addr >> 8;
+    *p++ = mh_entry_addr >> 16;
+    *p++ = mh_entry_addr >> 24;
+    *p++ = 0x08;
+    *p++ = 0x00;
+
+    { /* GDT loading */
+        uint32_t gdt_base = 0x00007c00 + (p - bootsect); // 0x00007c00 is the first IP;
+        uint32_t gdtr = gdt_base + 0x28;
+        uint8_t gdt[] = { // GDT base: 0x00000100
+            // 0x00
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            // 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k)
+            0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
+            // 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k)
+            0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00,
+            // 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b)
+            0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00,
+            // 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b)
+            0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00,
+            // 0x28: gdtdesc
+            0x27, 0x00, gdt_base, gdt_base >> 8, gdt_base >> 16, gdt_base >> 24
+        };
+
+        memcpy(p, gdt, sizeof(gdt));
+        p+=sizeof(gdt);
+        *pgdt++ = gdtr;
+        *pgdt++ = gdtr >> 8;
+        *pgdt++ = gdtr >> 16;
+        *pgdt++ = gdtr >> 24;
+    }
+    
+    fprintf(stderr, "qemu: multiboot loader code is %d bytes long.\n", (int)(p-bootsect));
+
+    bdrv_set_boot_sector(drives_table[hda].bdrv, bootsect, sizeof(bootsect));
+}
+
+static int load_multiboot(FILE *f,
+                          const char *kernel_filename,
+                          const char *initrd_filename,
+                          const char *kernel_cmdline,
+                          uint8_t *header)
+{
+    int i, is_multiboot = 0;
+    uint32_t flags = 0;
+    uint32_t mh_entry_addr;
+    uint32_t mh_load_addr;
+    uint32_t mb_kernel_size;
+    uint32_t mb_bootinfo = 0x90000;
+    uint32_t tmp_size;
+
+    // Ok, let's see if it is a multiboot image
+    for(i = 0; i < 8144; i += 4) { // the header is 12x32bit long, so
+                                   // the latest entry may be 8192 - 48
+        if(ldl_p(header+i) == 0x1BADB002) {
+            uint32_t checksum = ldl_p(header+i+8);
+            flags = ldl_p(header+i+4);
+            checksum += flags;
+            checksum += (uint32_t)0x1BADB002;
+            if(!checksum) {
+                is_multiboot = 1;
+                break;
+            }
+        }
+    }
+    
+    if(!is_multiboot) return 0; // no multiboot
+    fprintf(stderr, "qemu: I believe we found a multiboot image!\n");
+
+    if(flags & 0x00000004) { // MULTIBOOT_HEADER_HAS_VBE
+        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
+    } 
+    if(!(flags & 0x00010000)) { // MULTIBOOT_HEADER_HAS_ADDR
+        uint64_t elf_entry;
+        int kernel_size;
+        fclose(f);
+        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+        if(kernel_size < 0) {
+            fprintf(stderr, "Error while loading elf kernel\n");
+            exit(1);
+        }
+        mh_load_addr = mh_entry_addr = elf_entry;
+        mb_kernel_size = kernel_size;
+
+        fprintf(stderr, "qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
+                mb_kernel_size, (size_t)mh_entry_addr);
+    } else {
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
+        uint32_t mh_header_addr = ldl_p(header+i+12);
+        mh_load_addr = ldl_p(header+i+16);
+        uint32_t mh_load_end_addr = ldl_p(header+i+20);
+        uint32_t mh_bss_end_addr = ldl_p(header+i+24);
+        uint8_t *mb_kernel_addr = phys_ram_base + (mh_load_addr);
+        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+
+        mh_entry_addr = ldl_p(header+i+28);
+        mb_kernel_size = get_file_size(f) - mb_kernel_text_offset;
+
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
+        uint32_t mh_mode_type = ldl_p(header+i+32);
+        uint32_t mh_width = ldl_p(header+i+36);
+        uint32_t mh_height = ldl_p(header+i+40);
+        uint32_t mh_depth = ldl_p(header+i+44); */
+        
+        fprintf(stderr, "multiboot: mh_header_addr = %#x\n", mh_header_addr);
+        fprintf(stderr, "multiboot: mh_load_addr = %#x\n", mh_load_addr);
+        fprintf(stderr, "multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
+        fprintf(stderr, "multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
+        
+        fseek(f, mb_kernel_text_offset, SEEK_SET);
+
+        fprintf(stderr, "qemu: loading multiboot kernel (%#x bytes) at %#zx\n",
+                mb_kernel_size, mb_kernel_addr - phys_ram_base);
+
+        if ((tmp_size=fread(mb_kernel_addr, 1, mb_kernel_size, f)) != mb_kernel_size) {
+            fprintf(stderr, "qemu: read error on multiboot kernel '%s' (%#x != %#x)\n", kernel_filename, tmp_size, mb_kernel_size);
+            exit(1);
+        }
+        fclose(f);
+    }
+
+
+    // load modules
+
+    stl_p(phys_ram_base + mb_bootinfo + 20, 0x0); // mods_count
+    if(initrd_filename) {
+        uint32_t mb_mod_info = mb_bootinfo + 0x100;
+        uint32_t mb_mod_cmdline = mb_bootinfo+ 0x300;
+        uint32_t mb_mod_start = mh_load_addr;
+        uint32_t mb_mod_length = mb_kernel_size;
+        char *next_initrd;
+        char *next_space;
+        int mb_mod_count = 0;
+        
+        do {
+            next_initrd = strchr(initrd_filename, ',');
+            if(next_initrd)
+                *next_initrd = '\0';
+            /* if a space comes after the module filename, treat everything after that as parameters */
+            strcpy(phys_ram_base + mb_mod_cmdline, initrd_filename);
+            stl_p(phys_ram_base + mb_mod_info + 8, mb_mod_cmdline); // string
+            mb_mod_cmdline += strlen(initrd_filename) + 1;
+            if(next_space = strchr(initrd_filename, ' '))
+                *next_space = '\0';
+printf("multiboot loading module: %s\n", initrd_filename);
+            f = fopen(initrd_filename, "rb");
+            if(f) {
+                mb_mod_start = (mb_mod_start + mb_mod_length + (TARGET_PAGE_SIZE - 1))
+                             & (TARGET_PAGE_MASK);
+                mb_mod_length = get_file_size(f);
+
+                if ((tmp_size=fread((phys_ram_base + mb_mod_start), 1, mb_mod_length, f))
+                     != mb_mod_length) {
+                    fprintf(stderr, "qemu: read error on multiboot module '%s' (%#x != %#x)\n",
+                            initrd_filename, tmp_size, mb_mod_length);
+                    exit(1);
+                }
+
+                mb_mod_count++;
+                stl_p(phys_ram_base + mb_mod_info + 0, mb_mod_start);
+                stl_p(phys_ram_base + mb_mod_info + 4, mb_mod_start + mb_mod_length);
+printf("mod_start: %#x\nmod_end:   %#x\n", mb_mod_start, mb_mod_start + mb_mod_length);
+                stl_p(phys_ram_base + mb_mod_info + 12, 0x0); // reserved
+            }
+            initrd_filename = next_initrd+1;
+            mb_mod_info += 16;
+        } while(next_initrd);
+        stl_p(phys_ram_base + mb_bootinfo + 20, mb_mod_count); // mods_count
+        stl_p(phys_ram_base + mb_bootinfo + 24, mb_bootinfo + 0x100); // mods_addr
+    }
+
+    /* Commandline support */
+    stl_p(phys_ram_base + mb_bootinfo + 16, mb_bootinfo + 0x200);
+    strcpy((char*)(phys_ram_base + mb_bootinfo + 0x200), kernel_cmdline);
+        
+    // the kernel is where we want it to be now
+
+#define MULTIBOOT_FLAGS_MEMORY (1 << 0)
+#define MULTIBOOT_FLAGS_BOOT_DEVICE (1 << 1)
+#define MULTIBOOT_FLAGS_CMDLINE (1 << 2)
+#define MULTIBOOT_FLAGS_MODULES (1 << 3)
+#define MULTIBOOT_FLAGS_MMAP (1 << 6)
+    stl_p(phys_ram_base + mb_bootinfo, MULTIBOOT_FLAGS_MEMORY
+                                     | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                     | MULTIBOOT_FLAGS_CMDLINE
+                                     | MULTIBOOT_FLAGS_MODULES
+                                     | MULTIBOOT_FLAGS_MMAP);
+    stl_p(phys_ram_base + mb_bootinfo + 4, 640 * 1024); // mem_lower
+    stl_p(phys_ram_base + mb_bootinfo + 8, ram_size); // mem_upper
+    stl_p(phys_ram_base + mb_bootinfo + 12, 0x8001ffff); // XXX: use the -boot switch?
+    stl_p(phys_ram_base + mb_bootinfo + 48, 0x9000); // mmap_addr
+
+    fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+
+    generate_bootsect_multiboot(mh_entry_addr, mb_bootinfo);
+    
+    return 1; // yes, we are multiboot
+}
+
 static void load_linux(const char *kernel_filename,
 		       const char *initrd_filename,
 		       const char *kernel_cmdline)
@@ -490,7 +900,7 @@ static void load_linux(const char *kernel_filename,
     uint16_t real_seg;
     int setup_size, kernel_size, initrd_size, cmdline_size;
     uint32_t initrd_max;
-    uint8_t header[1024];
+    uint8_t header[8192];
     uint8_t *real_addr, *prot_addr, *cmdline_addr, *initrd_addr;
     FILE *f, *fi;
 
@@ -500,7 +910,7 @@ static void load_linux(const char *kernel_filename,
     /* load the kernel header */
     f = fopen(kernel_filename, "rb");
     if (!f || !(kernel_size = get_file_size(f)) ||
-	fread(header, 1, 1024, f) != 1024) {
+	fread(header, 1, 8192, f) != 8192) {
 	fprintf(stderr, "qemu: could not load kernel '%s'\n",
 		kernel_filename);
 	exit(1);
@@ -510,10 +920,15 @@ static void load_linux(const char *kernel_filename,
 #if 0
     fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
 #endif
-    if (ldl_p(header+0x202) == 0x53726448)
-	protocol = lduw_p(header+0x206);
-    else
-	protocol = 0;
+    if (ldl_p(header+0x202) == 0x53726448) {
+        protocol = lduw_p(header+0x206);
+    } else {
+        // This looks like a multiboot kernel. If it is, let's stop 
+        // treating it like Linux.
+        if(load_multiboot(f,kernel_filename,initrd_filename, kernel_cmdline, header))
+            return;
+        protocol = 0;
+    }
 
     if (protocol < 0x200 || !(header[0x211] & 0x01)) {
 	/* Low kernel */
@@ -606,7 +1021,7 @@ static void load_linux(const char *kernel_filename,
     }
 
     /* store the finalized header and load the rest of the kernel */
-    memcpy(real_addr, header, 1024);
+    memcpy(real_addr, header, 8192);
 
     setup_size = header[0x1f1];
     if (setup_size == 0)
@@ -615,7 +1030,7 @@ static void load_linux(const char *kernel_filename,
     setup_size = (setup_size+1)*512;
     kernel_size -= setup_size;	/* Size of protected-mode code */
 
-    if (fread(real_addr+1024, 1, setup_size-1024, f) != setup_size-1024 ||
+    if (fread(real_addr+8192, 1, setup_size-8192, f) != setup_size-8192 ||
 	fread(prot_addr, 1, kernel_size, f) != kernel_size) {
 	fprintf(stderr, "qemu: read error on kernel '%s'\n",
 		kernel_filename);
