📄 pc.c
字号:
isa_bios_size = 128 * 1024; cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, IO_MEM_UNASSIGNED); cpu_register_physical_memory(0x100000 - isa_bios_size, isa_bios_size, (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); { ram_addr_t option_rom_offset; int size, offset; offset = 0; for (i = 0; i < nb_option_roms; i++) { size = get_image_size(option_rom[i]); if (size < 0) { fprintf(stderr, "Could not load option rom '%s'\n", option_rom[i]); exit(1); } if (size > (0x10000 - offset)) goto option_rom_error; option_rom_offset = qemu_ram_alloc(size); ret = load_image_targphys(option_rom[i], option_rom_offset, size); if (ret != size) { option_rom_error: fprintf(stderr, "Too many option ROMS\n"); exit(1); } size = (size + 4095) & ~4095; cpu_register_physical_memory(0xd0000 + offset, size, option_rom_offset | IO_MEM_ROM); offset += size; } } /* map all the bios at the top of memory */ cpu_register_physical_memory((uint32_t)(-bios_size), bios_size, bios_offset | IO_MEM_ROM);#else vga_ram_addr = 0; /* this is not supposed to be used */#endif /* !CONFIG_DM */ bochs_bios_init(); if (linux_boot) load_linux(kernel_filename, initrd_filename, kernel_cmdline); cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); i8259 = i8259_init(cpu_irq[0]); ferr_irq = i8259[13]; if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state, i8259); piix3_devfn = piix3_init(pci_bus, -1); } else { pci_bus = NULL; } /* init basic PC hardware */ register_ioport_write(0x80, 1, 1, ioport80_write, NULL); register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); if (cirrus_vga_enabled) { if (pci_enabled) { pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } else { isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } } else if (vmsvga_enabled) { if (pci_enabled) pci_vmsvga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); else fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } else { if (pci_enabled) { pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size, 0, 0); } else { isa_vga_init(ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); } }#ifdef CONFIG_PASSTHROUGH /* Pass-through Initialization * init libpci even direct_pci is null, as can hotplug a dev runtime */ if ( pci_enabled ) { rc = pt_init(pci_bus, direct_pci); if ( rc < 0 ) { fprintf(logfile, "Error: Initialization failed for pass-through devices\n"); exit(1); } }#endif rtc_state = rtc_init(0x70, i8259[8]); register_ioport_read(0x92, 1, 1, ioport92_read, NULL); register_ioport_write(0x92, 1, 1, ioport92_write, NULL);#ifndef CONFIG_DM if (pci_enabled) { ioapic = ioapic_init(); } pit = pit_init(0x40, i8259[0]); pcspk_init(pit); if (pci_enabled) { pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); }#endif /* !CONFIG_DM */ if (pci_enabled) pci_xen_platform_init(pci_bus); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { serial_init(serial_io[i], i8259[serial_irq[i]], 115200, serial_hds[i]); } } for(i = 0; i < MAX_PARALLEL_PORTS; i++) { if (parallel_hds[i]) { parallel_init(parallel_io[i], i8259[parallel_irq[i]], parallel_hds[i]); } } for(i = 0; i < nb_nics; i++) { nd = &nd_table[i]; if (!nd->model) { if (pci_enabled) { nd->model = "ne2k_pci"; } else { nd->model = "ne2k_isa"; } } if (strcmp(nd->model, "ne2k_isa") == 0) { pc_init_ne2k_isa(nd, i8259); } else if (pci_enabled) { if (strcmp(nd->model, "?") == 0) fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n"); pci_nic_init(pci_bus, nd, -1); } else if (strcmp(nd->model, "?") == 0) { fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n"); exit(1); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit(1); } } if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) { fprintf(stderr, "qemu: too many IDE bus\n"); exit(1); } for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); if (index != -1) hd[i] = drives_table[index].bdrv; else hd[i] = NULL; } if (pci_enabled) { pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259); } else { for(i = 0; i < MAX_IDE_BUS; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]], hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); } }#ifdef HAS_TPM if (has_tpm_device()) tpm_tis_init(&i8259[11]);#endif i8042_init(i8259[1], i8259[12], 0x60); DMA_init(0);#ifdef HAS_AUDIO audio_init(pci_enabled ? pci_bus : NULL, i8259);#endif for(i = 0; i < MAX_FD; i++) { index = drive_get_index(IF_FLOPPY, 0, i); if (index != -1) fd[i] = drives_table[index].bdrv; else fd[i] = NULL; } floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd); cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd); if (pci_enabled && usb_enabled) { usb_uhci_piix3_init(pci_bus, piix3_devfn + 2); } if (pci_enabled && acpi_enabled) { uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */ i2c_bus *smbus; /* TODO: Populate SPD eeprom data. */ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]); if (smbus) { for (i = 0; i < 8; i++) { smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256)); } } } if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } if (pci_enabled) { int max_bus; int bus, unit; void *scsi; max_bus = drive_get_max_bus(IF_SCSI); for (bus = 0; bus <= max_bus; bus++) { scsi = lsi_scsi_init(pci_bus, -1); for (unit = 0; unit < LSI_MAX_DEVS; unit++) { index = drive_get_index(IF_SCSI, bus, unit); if (index == -1) continue; lsi_scsi_attach(scsi, drives_table[index].bdrv, unit); } } } if (pci_enabled) { PCI_EMULATION_INFO *p; for (p = PciEmulationInfoHead; p != NULL; p = p->next) { pci_emulation_init(pci_bus, p); } }}static void pc_init_pci(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, const char *cpu_model, const char *direct_pci){ pc_init1(ram_size, vga_ram_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, 1, cpu_model, direct_pci);}static void pc_init_isa(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, const char *cpu_model, const char *direct_pci){ pc_init1(ram_size, vga_ram_size, boot_device, ds, kernel_filename, kernel_cmdline, initrd_filename, 0, cpu_model, direct_pci);}/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) BIOS will read it and start S3 resume at POST Entry*/void cmos_set_s3_resume(void){ if (rtc_state) rtc_set_memory(rtc_state, 0xF, 0xFE);}QEMUMachine pc_machine = { "pc", "Standard PC", pc_init_pci, VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,};QEMUMachine isapc_machine = { "isapc", "ISA-only PC", pc_init_isa, VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,};/* * 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 void xen_relocator_hook(target_phys_addr_t *prot_addr_upd, uint16_t protocol, const uint8_t header[], int kernel_size, target_phys_addr_t real_addr, int real_size){ target_phys_addr_t prot_addr = *prot_addr_upd; /* Urgh, Xen's HVM firmware lives at 0x100000, but that's also the * address Linux wants to start life at prior to relocatable support */ fprintf(stderr, "checking need for relocation, header protocol: %x\n", protocol); if (prot_addr != 0x10000) { /* old low kernels are OK */ target_phys_addr_t reloc_prot_addr = 0x200000; if (protocol >= 0x205 && (header[0x234] & 1)) { /* Relocatable automatically */ stl_phys(real_addr+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_phys(real_addr+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 protected mode (%x bytes) at %#zx\n", kernel_size, (size_t)reloc_prot_addr); fprintf(stderr, "qemu: loading kernel real mode (%x bytes) at %#zx\n", real_size, (size_t)real_addr); *prot_addr_upd = reloc_prot_addr; }}#ifdef CONFIG_DMvoid vmport_init(void) { }int apic_init(CPUX86State *env) { return 0; }#endif /* CONFIG_DM */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -