⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pc.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
    /* Actual code */    p = bootsect;    *p++ = 0xfa;                /* CLI */    *p++ = 0xfc;                /* CLD */    for (i = 0; i < 6; i++) {        if (i == 1)             /* Skip CS */            continue;        *p++ = 0xb8;            /* MOV AX,imm16 */        *p++ = segs[i];        *p++ = segs[i] >> 8;        *p++ = 0x8e;            /* MOV <seg>,AX */        *p++ = 0xc0 + (i << 3);    }    for (i = 0; i < 8; i++) {        *p++ = 0x66;            /* 32-bit operand size */        *p++ = 0xb8 + i;        /* MOV <reg>,imm32 */        *p++ = gpr[i];        *p++ = gpr[i] >> 8;        *p++ = gpr[i] >> 16;        *p++ = gpr[i] >> 24;    }    *p++ = 0xea;                /* JMP FAR */    *p++ = ip;                  /* IP */    *p++ = ip >> 8;    *p++ = segs[1];             /* CS */    *p++ = segs[1] >> 8;    bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));}/* * Evil helper for non-relocatable kernels * * So it works out like this: * *  0x100000  - Xen HVM firmware lives here. Kernel wants to boot here * * You can't both live there and HVM firmware is needed first, thus * our plan is * *  0x200000              - kernel is loaded here by QEMU *  0x200000+kernel_size  - helper code is put here by QEMU * * code32_switch in kernel header is set to point at out helper * code at 0x200000+kernel_size * * Our helper basically does memmove(0x100000,0x200000,kernel_size) * and then jmps to  0x1000000. * * So we've overwritten the HVM firmware (which was no longer * needed) and the non-relocatable kernel can happily boot * at its usual address. * * Simple, eh ? * * Well the assembler needed to do this is fairly short: * *  # Load segments *    cld                          *    cli                          *    movl $0x18,%eax *    mov %ax,%ds                  *    mov %ax,%es                  *    mov %ax,%fs                  *    mov %ax,%gs                  *    mov %ax,%ss                  * *  # Move the kernel into position *    xor    %edx,%edx             *_doloop:                         *    movzbl 0x600000(%edx),%eax   *    mov    %al,0x100000(%edx)    *    add    $0x1,%edx             *    cmp    $0x500000,%edx        *    jne    _doloop               * *  # start kernel *    xorl %ebx,%ebx               *    mov    $0x100000,%ecx        *    jmp    *%ecx                 * */static void setup_relocator(target_phys_addr_t addr, target_phys_addr_t src, target_phys_addr_t dst, size_t len){  /* Now this assembler corresponds to follow machine code, with our args from QEMU spliced in :-) */  unsigned char buf[] = {    /* Load segments */    0xfc,                         /* cld               */    0xfa,                         /* cli               */     0xb8, 0x18, 0x00, 0x00, 0x00, /* mov    $0x18,%eax */    0x8e, 0xd8,                   /* mov    %eax,%ds   */    0x8e, 0xc0,                   /* mov    %eax,%es   */    0x8e, 0xe0,                   /* mov    %eax,%fs   */    0x8e, 0xe8,                   /* mov    %eax,%gs   */    0x8e, 0xd0,                   /* mov    %eax,%ss   */    0x31, 0xd2,                   /* xor    %edx,%edx  */      /* Move the kernel into position */    0x0f, 0xb6, 0x82, (src&0xff), ((src>>8)&0xff), ((src>>16)&0xff), ((src>>24)&0xff), /*   movzbl $src(%edx),%eax */    0x88, 0x82, (dst&0xff), ((dst>>8)&0xff), ((dst>>16)&0xff), ((dst>>24)&0xff),       /*   mov    %al,$dst(%edx)  */    0x83, 0xc2, 0x01,                                                                  /*   add    $0x1,%edx       */    0x81, 0xfa, (len&0xff), ((len>>8)&0xff), ((len>>16)&0xff), ((len>>24)&0xff),       /*   cmp    $len,%edx       */    0x75, 0xe8,                                                                        /*   jne    13 <_doloop>    */    /* Start kernel */    0x31, 0xdb,                                                                        /*   xor    %ebx,%ebx       */    0xb9, (dst&0xff), ((dst>>8)&0xff), ((dst>>16)&0xff), ((dst>>24)&0xff),             /*   mov    $dst,%ecx  */    0xff, 0xe1,                                                                        /*   jmp    *%ecx           */  };  cpu_physical_memory_rw(addr, buf, sizeof(buf), 1);  fprintf(stderr, "qemu: helper at 0x%x of size %d bytes, to move kernel of %d bytes from 0x%x to 0x%x\n",	  (int)addr, (int)sizeof(buf), (int)len, (int)src, (int)dst);}static long get_file_size(FILE *f){    long where, size;    /* XXX: on Unix systems, using fstat() probably makes more sense */    where = ftell(f);    fseek(f, 0, SEEK_END);    size = ftell(f);    fseek(f, where, SEEK_SET);    return size;}static int fread2guest(target_phys_addr_t dst_addr, size_t nbytes, FILE *f){    size_t offset = 0;    while (nbytes) {        uint8_t buf[4096];	size_t count = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;	if (fread(buf, 1, count, f) != count)	    return -1;	cpu_physical_memory_rw(dst_addr+offset, buf, count, 1);	offset += count;	nbytes -= count;    }    return 0;}static void load_linux(const char *kernel_filename,                       const char *initrd_filename,                       const char *kernel_cmdline){    uint16_t protocol;    uint32_t gpr[8];    uint16_t seg[6];    uint16_t real_seg;    int setup_size, kernel_size, initrd_size, cmdline_size;    unsigned long end_low_ram;    uint32_t initrd_max;    uint8_t header[1024];    target_phys_addr_t real_addr, reloc_prot_addr, prot_addr, cmdline_addr, initrd_addr;    size_t ncmdline;    FILE *f, *fi;    /* Align to 16 bytes as a paranoia measure */    cmdline_size = (strlen(kernel_cmdline)+16) & ~15;    /* load the kernel header */    f = fopen(kernel_filename, "rb");    if (!f || !(kernel_size = get_file_size(f)) ||        fread(header, 1, 1024, f) != 1024) {        fprintf(stderr, "qemu: could not load kernel '%s'\n",                kernel_filename);        exit(1);    }    /* kernel protocol version */    fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));    if (ldl_p(header+0x202) == 0x53726448)        protocol = lduw_p(header+0x206);    else        protocol = 0;    fprintf(stderr, "header protocol: %x\n", protocol);    if (protocol < 0x200 || !(header[0x211] & 0x01)) {        /* Low kernel */        real_addr    = 0x90000;        cmdline_addr = 0x9a000 - cmdline_size;        prot_addr    = 0x10000;	reloc_prot_addr = prot_addr;    } else if (protocol < 0x202) {        /* High but ancient kernel */        real_addr    = 0x90000;        cmdline_addr = 0x9a000 - cmdline_size;        prot_addr    = 0x100000;	reloc_prot_addr = 0x200000;    } else {        /* High and recent kernel */        real_addr    = 0x10000;        cmdline_addr = 0x20000;        prot_addr    = 0x100000;	reloc_prot_addr = 0x200000;    }    fprintf(stderr,            "qemu: real_addr     = %#zx\n"            "qemu: cmdline_addr  = %#zx\n"            "qemu: prot_addr     = %#zx\n",            (size_t)real_addr,            (size_t)cmdline_addr,            (size_t)prot_addr);    /* 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);    end_low_ram = (end_low_ram << 12) - (64*1024);    /* highest address for loading the initrd */    initrd_max = (protocol >= 0x203) ? ldl_p(header+0x22c) : 0x37ffffff;    initrd_max = MIN(initrd_max, (uint32_t)end_low_ram);    /* kernel command line */    ncmdline = strlen(kernel_cmdline);    if (ncmdline > 4095) {        ncmdline = 4095;	((uint8_t*)kernel_cmdline)[4095] = '\0';    }    fprintf(stderr, "qemu: kernel_cmdline: %#zx ('%s')\n", ncmdline, kernel_cmdline);    cpu_physical_memory_rw(cmdline_addr, (uint8_t*)kernel_cmdline, ncmdline+1, 1);    if (protocol >= 0x202) {        stl_p(header+0x228, cmdline_addr);    } else {        stw_p(header+0x20, 0xA33F);        stw_p(header+0x22, cmdline_addr-real_addr);    }    /* loader type */    /* High nybble = B reserved for Qemu; low nybble is revision number.       If this code is substantially changed, you may want to consider       incrementing the revision. */    if (protocol >= 0x200)        header[0x210] = 0xB0;    /* heap */    if (protocol >= 0x201) {        header[0x211] |= 0x80;  /* CAN_USE_HEAP */        stw_p(header+0x224, cmdline_addr-real_addr-0x200);    }    /* load initrd */    if (initrd_filename) {        if (protocol < 0x200) {            fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");            exit(1);        }        fi = fopen(initrd_filename, "rb");        if (!fi) {            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",                    initrd_filename);            exit(1);        }        initrd_size = get_file_size(fi);        initrd_addr = ((initrd_max-initrd_size) & ~4095);        fprintf(stderr, "qemu: loading initrd (%#x bytes) at %#zx\n",                initrd_size, initrd_addr);	if (fread2guest(initrd_addr, initrd_size, fi) < 0) {	    fprintf(stderr, "qemu: read error on initial ram disk '%s'\n",		    initrd_filename);	    exit(1);	}        fclose(fi);        stl_p(header+0x218, initrd_addr);        stl_p(header+0x21c, initrd_size);    }    setup_size = header[0x1f1];    if (setup_size == 0)        setup_size = 4;    setup_size = (setup_size+1)*512;    kernel_size -= setup_size;  /* Size of protected-mode code */    /* Urgh, Xen's HVM firmware lives at 0x100000, but that's also the     * address Linux wants to start life at prior to relocatable support     */    if (prot_addr != reloc_prot_addr) {        if (protocol >= 0x205 && (header[0x234] & 1)) {	    /* Relocatable automatically */	    stl_p(header+0x214, reloc_prot_addr);	    fprintf(stderr, "qemu: kernel is relocatable\n");	} else {	    /* Setup a helper which moves  kernel back to	     * its expected addr after firmware has got out	     * of the way. We put a helper at  reloc_prot_addr+kernel_size.	     * It moves kernel from reloc_prot_addr to prot_addr and	     * then jumps to prot_addr. Yes this is sick.	     */	    fprintf(stderr, "qemu: kernel is NOT relocatable\n");	    stl_p(header+0x214, reloc_prot_addr + kernel_size);	    setup_relocator(reloc_prot_addr + kernel_size, reloc_prot_addr, prot_addr, kernel_size);	}    }    fprintf(stderr, "qemu: loading kernel real mode (%#x bytes) at %#zx\n",	    setup_size-1024, real_addr);    fprintf(stderr, "qemu: loading kernel protected mode (%#x bytes) at %#zx\n",	    kernel_size, reloc_prot_addr);    /* store the finalized header and load the rest of the kernel */    cpu_physical_memory_rw(real_addr, header, 1024, 1);    if (fread2guest(real_addr+1024, setup_size-1024, f) < 0 ||        fread2guest(reloc_prot_addr, kernel_size, f) < 0) {	fprintf(stderr, "qemu: loading kernel protected mode (%#x bytes) at %#zx\n",		kernel_size, reloc_prot_addr);	exit(1);    }    fclose(f);    /* generate bootsector to set up the initial register state */    real_seg = (real_addr) >> 4;    seg[0] = seg[2] = seg[3] = seg[4] = seg[4] = real_seg;    seg[1] = real_seg+0x20;     /* CS */    memset(gpr, 0, sizeof gpr);    gpr[4] = cmdline_addr-real_addr-16; /* SP (-16 is paranoia) */    generate_bootsect(gpr, seg, 0);}#else /* __ia64__ */static void load_linux(const char *kernel_filename,                       const char *initrd_filename,                       const char *kernel_cmdline){    /* Direct Linux boot is unsupported. */}#endifstatic void main_cpu_reset(void *opaque){    CPUState *env = opaque;    cpu_reset(env);}static const int ide_iobase[2] = { 0x1f0, 0x170 };static const int ide_iobase2[2] = { 0x3f6, 0x376 };static const int ide_irq[2] = { 14, 15 };#define NE2000_NB_MAX 6static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };#ifdef HAS_AUDIOstatic void audio_init (PCIBus *pci_bus){    struct soundhw *c;    int audio_enabled = 0;    for (c = soundhw; !audio_enabled && c->name; ++c) {        audio_enabled = c->enabled;    }    if (audio_enabled) {        AudioState *s;        s = AUD_init ();        if (s) {            for (c = soundhw; c->name; ++c) {                if (c->enabled) {                    if (c->isa) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -