qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] x86 Multiboot support (extended)


From: Aurelien Jarno
Subject: Re: [Qemu-devel] [PATCH] x86 Multiboot support (extended)
Date: Wed, 12 Mar 2008 00:44:19 +0100
User-agent: Mutt/1.5.17+20080114 (2008-01-14)

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
 `. `'   address@hidden         | address@hidden
   `-    people.debian.org/~aurel32 | www.aurel32.net




reply via email to

[Prev in Thread] Current Thread [Next in Thread]