📄 mips_malta.c
字号:
qemu_chr_printf(s->display, "+--------+\r\n"); qemu_chr_printf(s->display, "\n"); qemu_chr_printf(s->display, "Malta ASCII\r\n"); qemu_chr_printf(s->display, "+--------+\r\n"); qemu_chr_printf(s->display, "+ +\r\n"); qemu_chr_printf(s->display, "+--------+\r\n"); malta_fpga_reset(s); qemu_register_reset(malta_fpga_reset, s); return s;}/* Audio support */#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) { fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name); exit(1); } else { if (pci_bus) { c->init.init_pci (pci_bus, s); } } } } } }}#endif/* Network support */static void network_init (PCIBus *pci_bus){ int i; NICInfo *nd; for(i = 0; i < nb_nics; i++) { nd = &nd_table[i]; if (!nd->model) { nd->model = "pcnet"; } if (i == 0 && strcmp(nd->model, "pcnet") == 0) { /* The malta board has a PCNet card using PCI SLOT 11 */ pci_nic_init(pci_bus, nd, 88); } else { pci_nic_init(pci_bus, nd, -1); } }}/* ROM and pseudo bootloader The following code implements a very very simple bootloader. It first loads the registers a0 to a3 to the values expected by the OS, and then jump at the kernel address. The bootloader should pass the locations of the kernel arguments and environment variables tables. Those tables contain the 32-bit address of NULL terminated strings. The environment variables table should be terminated by a NULL address. For a simpler implementation, the number of kernel arguments is fixed to two (the name of the kernel and the command line), and the two tables are actually the same one. The registers a0 to a3 should contain the following values: a0 - number of kernel arguments a1 - 32-bit address of the kernel arguments table a2 - 32-bit address of the environment variables table a3 - RAM size in bytes*/static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr){ uint32_t *p; /* Small bootloader */ p = (uint32_t *) (phys_ram_base + bios_offset); stl_raw(p++, 0x0bf00010); /* j 0x1fc00040 */ stl_raw(p++, 0x00000000); /* nop */ /* Second part of the bootloader */ p = (uint32_t *) (phys_ram_base + bios_offset + 0x040); stl_raw(p++, 0x3c040000); /* lui a0, 0 */ stl_raw(p++, 0x34840002); /* ori a0, a0, 2 */ stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */ stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */ stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */ stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */ stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff)); /* lui ra, high(kernel_addr) */; stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff)); /* ori ra, ra, low(kernel_addr) */ stl_raw(p++, 0x03e00008); /* jr ra */ stl_raw(p++, 0x00000000); /* nop */}static void prom_set(int index, const char *string, ...){ va_list ap; int32_t *p; int32_t table_addr; char *s; if (index >= ENVP_NB_ENTRIES) return; p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND); p += index; if (string == NULL) { stl_raw(p, 0); return; } table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE; s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr); stl_raw(p, table_addr); va_start(ap, string); vsnprintf (s, ENVP_ENTRY_SIZE, string, ap); va_end(ap);}/* Kernel */static int64_t load_kernel (CPUState *env){ int64_t kernel_addr = 0; int index = 0; long initrd_size; if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", env->kernel_filename); exit(1); } /* load initrd */ initrd_size = 0; if (env->initrd_filename) { initrd_size = load_image(env->initrd_filename, phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); if (initrd_size == (target_ulong) -1) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", env->initrd_filename); exit(1); } } /* Store command line. */ prom_set(index++, env->kernel_filename); if (initrd_size > 0) prom_set(index++, "rd_start=0x" TLSZ " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline); else prom_set(index++, env->kernel_cmdline); /* Setup minimum environment variables */ prom_set(index++, "memsize"); prom_set(index++, "%i", env->ram_size); prom_set(index++, "modetty0"); prom_set(index++, "38400n8r"); prom_set(index++, NULL); return kernel_addr;}static void main_cpu_reset(void *opaque){ CPUState *env = opaque; cpu_reset(env); /* The bootload does not need to be rewritten as it is located in a read only location. The kernel location and the arguments table location does not change. */ if (env->kernel_filename) load_kernel (env);}void mips_malta_init (int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename){ char buf[1024]; unsigned long bios_offset; int64_t kernel_addr; PCIBus *pci_bus; CPUState *env; RTCState *rtc_state; /* fdctrl_t *floppy_controller; */ MaltaFPGAState *malta_fpga; int ret; env = cpu_init(); register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); /* allocate RAM */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); /* Map the bios at two physical locations, as on the real board */ bios_offset = ram_size + vga_ram_size; cpu_register_physical_memory(0x1e000000LL, BIOS_SIZE, bios_offset | IO_MEM_ROM); cpu_register_physical_memory(0x1fc00000LL, BIOS_SIZE, bios_offset | IO_MEM_ROM); /* Load a BIOS image except if a kernel image has been specified. In the later case, just write a small bootloader to the flash location. */ if (kernel_filename) { env->ram_size = ram_size; env->kernel_filename = kernel_filename; env->kernel_cmdline = kernel_cmdline; env->initrd_filename = initrd_filename; kernel_addr = load_kernel(env); write_bootloader(env, bios_offset, kernel_addr); } else { snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); ret = load_image(buf, phys_ram_base + bios_offset); if (ret != BIOS_SIZE) { fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", buf); exit(1); } } /* Board ID = 0x420 (Malta Board with CoreLV) XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should map to the board ID. */ stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420); /* Init internal devices */ cpu_mips_clock_init(env); cpu_mips_irqctrl_init(); /* FPGA */ malta_fpga = malta_fpga_init(0x1f000000LL); /* Interrupt controller */ isa_pic = pic_init(pic_irq_request, env); /* Northbridge */ pci_bus = pci_gt64120_init(isa_pic); /* Southbridge */ piix4_init(pci_bus, 80); pci_piix3_ide_init(pci_bus, bs_table, 81); usb_uhci_init(pci_bus, 82); piix4_pm_init(pci_bus, 83); pit = pit_init(0x40, 0); DMA_init(0); /* Super I/O */ kbd_init(); rtc_state = rtc_init(0x70, 8); serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); parallel_init(0x378, 7, parallel_hds[0]); /* XXX: The floppy controller does not work correctly, something is probably wrong. floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */ /* Sound card */#ifdef HAS_AUDIO audio_init(pci_bus);#endif /* Network card */ network_init(pci_bus);}QEMUMachine mips_malta_machine = { "malta", "MIPS Malta Core LV", mips_malta_init,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -