📄 pc.c
字号:
}/* Generate an initial boot sector which sets state and jump to a specified vector */static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip){ uint8_t bootsect[512], *p; int i; int hda; 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"); 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 */ 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(drives_table[hda].bdrv, bootsect, sizeof(bootsect));}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 void pstrcpy_targphys(target_phys_addr_t dest, int buf_size, const char *source){ static const char nul_byte; const char *nulp; if (buf_size <= 0) return; nulp = memchr(source, 0, buf_size); if (nulp) { cpu_physical_memory_write(dest, source, (nulp - source) + 1); } else { cpu_physical_memory_write(dest, source, buf_size - 1); cpu_physical_memory_write(dest, &nul_byte, 1); }}static void load_linux(const char *kernel_filename, const char *initrd_filename, const char *kernel_cmdline){#ifndef __ia64__ 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, prot_addr, cmdline_addr, initrd_addr; 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 */#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 (protocol < 0x200 || !(header[0x211] & 0x01)) { /* Low kernel */ real_addr = 0x90000; cmdline_addr = 0x9a000 - cmdline_size; prot_addr = 0x10000; } else if (protocol < 0x202) { /* High but ancient kernel */ real_addr = 0x90000; cmdline_addr = 0x9a000 - cmdline_size; prot_addr = 0x100000; } else { /* High and recent kernel */ real_addr = 0x10000; cmdline_addr = 0x20000; prot_addr = 0x100000; }#if 1 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);#endif /* 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 */ pstrcpy_targphys(cmdline_addr, 4096, kernel_cmdline); 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, (size_t)initrd_addr); if (!fread_targphys_ok(initrd_addr, initrd_size, fi)) { 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); } /* store the finalized header and load the rest of the kernel */ cpu_physical_memory_write(real_addr, header, 1024); 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 */ xen_relocator_hook(&prot_addr, protocol, header, kernel_size, real_addr, setup_size-1024); if (!fread_targphys_ok(real_addr+1024, setup_size-1024, f) || !fread_targphys_ok(prot_addr, kernel_size, f)) { fprintf(stderr, "qemu: read error on kernel '%s'\n", kernel_filename); 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);#endif}static 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, qemu_irq *pic){ 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) { c->init.init_isa (s, pic); } else { if (pci_bus) { c->init.init_pci (pci_bus, s); } } } } } }}#endifstatic void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic){ static int nb_ne2k = 0; if (nb_ne2k == NE2000_NB_MAX) return; isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd); nb_ne2k++;}/* PC hardware initialisation */static void pc_init1(ram_addr_t ram_size, int vga_ram_size, const char *boot_device, DisplayState *ds, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, int pci_enabled, const char *cpu_model, const char *direct_pci){ char buf[1024]; int ret, linux_boot, i; ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; ram_addr_t below_4g_mem_size, above_4g_mem_size = 0; int bios_size, isa_bios_size, vga_bios_size; PCIBus *pci_bus; int piix3_devfn = -1; CPUState *env; NICInfo *nd; qemu_irq *cpu_irq; qemu_irq *i8259; int index; BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; BlockDriverState *fd[MAX_FD]; int rc; if (ram_size >= 0xe0000000 ) { above_4g_mem_size = ram_size - 0xe0000000; below_4g_mem_size = 0xe0000000; } else { below_4g_mem_size = ram_size; } qemu_register_boot_set(pc_boot_set); linux_boot = (kernel_filename != NULL); /* init CPUs */ if (cpu_model == NULL) {#ifdef TARGET_X86_64 cpu_model = "qemu64";#else cpu_model = "qemu32";#endif } for(i = 0; i < smp_cpus; i++) { env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to find x86 CPU definition\n"); exit(1); }#ifndef CONFIG_DM if (i != 0) env->hflags |= HF_HALTED_MASK; if (smp_cpus > 1) { /* XXX: enable it in all cases */ env->cpuid_features |= CPUID_APIC; }#endif /* !CONFIG_DM */ register_savevm("cpu", i, 4, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); if (pci_enabled) { apic_init(env); } } vmport_init();#ifndef CONFIG_DM /* allocate RAM */ ram_addr = qemu_ram_alloc(ram_size); cpu_register_physical_memory(0, below_4g_mem_size, ram_addr); /* above 4giga memory allocation */ if (above_4g_mem_size > 0) { cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size, ram_addr + below_4g_mem_size); } /* allocate VGA RAM */ vga_ram_addr = qemu_ram_alloc(vga_ram_size); /* BIOS load */ if (bios_name == NULL) bios_name = BIOS_FILENAME; snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); bios_size = get_image_size(buf); if (bios_size <= 0 || (bios_size % 65536) != 0) { goto bios_error; } bios_offset = qemu_ram_alloc(bios_size); ret = load_image_targphys(buf, bios_offset, bios_size); if (ret != bios_size) { bios_error: fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", buf); exit(1); } /* VGA BIOS load */ if (cirrus_vga_enabled) { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME); } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); } vga_bios_size = get_image_size(buf); if (vga_bios_size <= 0 || vga_bios_size > 65536) goto vga_bios_error; vga_bios_offset = qemu_ram_alloc(65536); ret = load_image_targphys(buf, vga_bios_offset, vga_bios_size); if (ret != vga_bios_size) { vga_bios_error: fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf); exit(1); } /* setup basic memory access */ cpu_register_physical_memory(0xc0000, 0x10000, vga_bios_offset | IO_MEM_ROM); /* map the last 128KB of the BIOS in ISA space */ isa_bios_size = bios_size; if (isa_bios_size > (128 * 1024))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -