On Thu, Jan 31, 2008 at 06:31:09PM +0100, Alexander Graf wrote: > > On Jan 31, 2008, at 10:58 AM, Kevin Wolf wrote: > >> Hi, >> >> I like this idea. When I just tried to load my multiboot kernel it >> failed, though, because of the following piece of code: >> >>> + // XXX: multiboot header may be within the first 8192 bytes, >>> but header >>> + // is only the first 1024 >>> + >>> + // Ok, let's see if it is a multiboot image >>> + for(i=0; i<(256 - 12); i+=4) { // the header is 12x32bit long >>> + if(ldl_p(header+i) == 0x1BADB002) { >> >> I wonder if there is any reason why you didn't just replace the 1024 >> by >> 8192 in load_linux but added an XXX. Would this cause any problems I >> missed? With this change and replacing 256 by 8192 in the above code >> it >> works for my kernel, too. >> >> Anyway, I think the for condition should be i < 4 * (256 - 12), even >> without changing the 1024. > > This version should fix the long header issue. I made the linux loader > fetch the first 8kb as header, so multiboot can search through all > necessary data. > > I also implemented module parameters. Kevin needed this to boot a > homebrew kernel. You can now pass commandline parameters to the > multiboot modules by adding them after the filename, seperated through a > space. This is the very same approach grub takes. > > To boot a xen kernel you would give a command line like this: > > qemu -hda image -kernel xen -initrd "vmlinux-xen root=/dev/hda,initrd- > xen" > > This way the vmlinux module gets the command line parameter "root=/dev/ > hda". > > > 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; > + } > +
Is it really necessary to have *that much* assembly code within hw/pc.c? I would rather see multiboot support as a small image generated from C and/or assembly code, loaded either with -hda or with a new option having the same effect. This code could read the NVRAM to get the variables it needs. -- .''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [EMAIL PROTECTED] | [EMAIL PROTECTED] `- people.debian.org/~aurel32 | www.aurel32.net