1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "qemu/osdep.h"
27#include "qemu/units.h"
28#include "qemu/cutils.h"
29#include "qemu/datadir.h"
30#include "qapi/error.h"
31#include "elf.h"
32#include "kvm_mips.h"
33#include "hw/char/serial.h"
34#include "hw/intc/loongson_liointc.h"
35#include "hw/mips/mips.h"
36#include "hw/mips/cpudevs.h"
37#include "hw/mips/fw_cfg.h"
38#include "hw/mips/loongson3_bootp.h"
39#include "hw/misc/unimp.h"
40#include "hw/intc/i8259.h"
41#include "hw/loader.h"
42#include "hw/isa/superio.h"
43#include "hw/pci/msi.h"
44#include "hw/pci/pci.h"
45#include "hw/pci/pci_host.h"
46#include "hw/pci-host/gpex.h"
47#include "hw/usb.h"
48#include "net/net.h"
49#include "sysemu/kvm.h"
50#include "sysemu/qtest.h"
51#include "sysemu/reset.h"
52#include "sysemu/runstate.h"
53#include "qemu/error-report.h"
54
55#define PM_CNTL_MODE 0x10
56
57#define LOONGSON_MAX_VCPUS 16
58
59
60
61
62
63
64#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
65
66#define UART_IRQ 0
67#define RTC_IRQ 1
68#define PCIE_IRQ_BASE 2
69
70const MemMapEntry virt_memmap[] = {
71 [VIRT_LOWMEM] = { 0x00000000, 0x10000000 },
72 [VIRT_PM] = { 0x10080000, 0x100 },
73 [VIRT_FW_CFG] = { 0x10080100, 0x100 },
74 [VIRT_RTC] = { 0x10081000, 0x1000 },
75 [VIRT_PCIE_PIO] = { 0x18000000, 0x80000 },
76 [VIRT_PCIE_ECAM] = { 0x1a000000, 0x2000000 },
77 [VIRT_BIOS_ROM] = { 0x1fc00000, 0x200000 },
78 [VIRT_UART] = { 0x1fe001e0, 0x8 },
79 [VIRT_LIOINTC] = { 0x3ff01400, 0x64 },
80 [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
81 [VIRT_HIGHMEM] = { 0x80000000, 0x0 },
82};
83
84static const MemMapEntry loader_memmap[] = {
85 [LOADER_KERNEL] = { 0x00000000, 0x4000000 },
86 [LOADER_INITRD] = { 0x04000000, 0x0 },
87 [LOADER_CMDLINE] = { 0x0ff00000, 0x100000 },
88};
89
90static const MemMapEntry loader_rommap[] = {
91 [LOADER_BOOTROM] = { 0x1fc00000, 0x1000 },
92 [LOADER_PARAM] = { 0x1fc01000, 0x10000 },
93};
94
95struct LoongsonMachineState {
96 MachineState parent_obj;
97 MemoryRegion *pio_alias;
98 MemoryRegion *mmio_alias;
99 MemoryRegion *ecam_alias;
100};
101typedef struct LoongsonMachineState LoongsonMachineState;
102
103#define TYPE_LOONGSON_MACHINE MACHINE_TYPE_NAME("loongson3-virt")
104DECLARE_INSTANCE_CHECKER(LoongsonMachineState, LOONGSON_MACHINE, TYPE_LOONGSON_MACHINE)
105
106static struct _loaderparams {
107 uint64_t cpu_freq;
108 uint64_t ram_size;
109 const char *kernel_cmdline;
110 const char *kernel_filename;
111 const char *initrd_filename;
112 uint64_t kernel_entry;
113 uint64_t a0, a1, a2;
114} loaderparams;
115
116static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
117{
118 return 0;
119}
120
121static void loongson3_pm_write(void *opaque, hwaddr addr,
122 uint64_t val, unsigned size)
123{
124 if (addr != PM_CNTL_MODE) {
125 return;
126 }
127
128 switch (val) {
129 case 0x00:
130 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
131 return;
132 case 0xff:
133 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
134 return;
135 default:
136 return;
137 }
138}
139
140static const MemoryRegionOps loongson3_pm_ops = {
141 .read = loongson3_pm_read,
142 .write = loongson3_pm_write,
143 .endianness = DEVICE_NATIVE_ENDIAN,
144 .valid = {
145 .min_access_size = 1,
146 .max_access_size = 1
147 }
148};
149
150#define DEF_LOONGSON3_FREQ (800 * 1000 * 1000)
151
152static uint64_t get_cpu_freq_hz(void)
153{
154#ifdef CONFIG_KVM
155 int ret;
156 uint64_t freq;
157 struct kvm_one_reg freq_reg = {
158 .id = KVM_REG_MIPS_COUNT_HZ,
159 .addr = (uintptr_t)(&freq)
160 };
161
162 if (kvm_enabled()) {
163 ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
164 if (ret >= 0) {
165 return freq * 2;
166 }
167 }
168#endif
169 return DEF_LOONGSON3_FREQ;
170}
171
172static void init_boot_param(void)
173{
174 static void *p;
175 struct boot_params *bp;
176
177 p = g_malloc0(loader_rommap[LOADER_PARAM].size);
178 bp = p;
179
180 bp->efi.smbios.vers = cpu_to_le16(1);
181 init_reset_system(&(bp->reset_system));
182 p += ROUND_UP(sizeof(struct boot_params), 64);
183 init_loongson_params(&(bp->efi.smbios.lp), p,
184 loaderparams.cpu_freq, loaderparams.ram_size);
185
186 rom_add_blob_fixed("params_rom", bp,
187 loader_rommap[LOADER_PARAM].size,
188 loader_rommap[LOADER_PARAM].base);
189
190 g_free(bp);
191
192 loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL,
193 loader_rommap[LOADER_PARAM].base);
194}
195
196static void init_boot_rom(void)
197{
198 const unsigned int boot_code[] = {
199 0x40086000,
200 0x240900E4,
201 0x01094025,
202 0x3C090040,
203 0x01094025,
204 0x40886000,
205 0x00000000,
206 0x40806800,
207 0x00000000,
208 0x400A7801,
209 0x314A00FF,
210 0x3C089000,
211 0x00084438,
212 0x35083FF0,
213 0x00084438,
214 0x35081000,
215 0x314B0003,
216 0x000B5A00,
217 0x010B4025,
218 0x314C000C,
219 0x000C62BC,
220 0x010C4025,
221
222 0xDD020020,
223 0x1040FFFE,
224 0x00000000,
225 0xDD1D0028,
226 0xDD1C0030,
227 0xDD050038,
228 0x00400008,
229 0x00000000,
230 0x1000FFFF,
231 0x00000000,
232
233
234 0x3C0C9000,
235 0x358C0000,
236 0x000C6438,
237 0x358C1008,
238 0x000C6438,
239 0x358C0010,
240 0x240D0000,
241 0xA18D0000,
242 0x1000FFFF,
243 0x00000000,
244
245
246 0x3C0C9000,
247 0x358C0000,
248 0x000C6438,
249 0x358C1008,
250 0x000C6438,
251 0x358C0010,
252 0x240D00FF,
253 0xA18D0000,
254 0x1000FFFF,
255 0x00000000
256 };
257
258 rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
259 loader_rommap[LOADER_BOOTROM].base);
260}
261
262static void fw_cfg_boot_set(void *opaque, const char *boot_device,
263 Error **errp)
264{
265 fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
266}
267
268static void fw_conf_init(unsigned long ram_size)
269{
270 FWCfgState *fw_cfg;
271 hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
272
273 fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
274 fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
275 fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
276 fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
277 fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
278 fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq_hz());
279 qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
280}
281
282static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
283{
284 int ret = 0;
285 void *cmdline_buf;
286 hwaddr cmdline_vaddr;
287 unsigned int *parg_env;
288
289
290 cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
291 cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
292 loader_memmap[LOADER_CMDLINE].base);
293
294
295
296
297
298
299 parg_env = (void *)cmdline_buf;
300
301 ret = (3 + 1) * 4;
302 *parg_env++ = cmdline_vaddr + ret;
303 ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
304
305
306 *parg_env++ = cmdline_vaddr + ret;
307 if (initrd_size > 0)
308 ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
309 "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
310 cpu_mips_phys_to_kseg0(NULL, initrd_offset),
311 initrd_size, loaderparams.kernel_cmdline));
312 else
313 ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
314 loaderparams.kernel_cmdline));
315
316
317 *parg_env++ = cmdline_vaddr + 4 * ret;
318
319 rom_add_blob_fixed("cmdline", cmdline_buf,
320 loader_memmap[LOADER_CMDLINE].size,
321 loader_memmap[LOADER_CMDLINE].base);
322
323 g_free(cmdline_buf);
324
325 loaderparams.a0 = 2;
326 loaderparams.a1 = cmdline_vaddr;
327
328 return 0;
329}
330
331static uint64_t load_kernel(CPUMIPSState *env)
332{
333 long kernel_size;
334 ram_addr_t initrd_offset;
335 uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
336
337 kernel_size = load_elf(loaderparams.kernel_filename, NULL,
338 cpu_mips_kseg0_to_phys, NULL,
339 (uint64_t *)&kernel_entry,
340 (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
341 NULL, 0, EM_MIPS, 1, 0);
342 if (kernel_size < 0) {
343 error_report("could not load kernel '%s': %s",
344 loaderparams.kernel_filename,
345 load_elf_strerror(kernel_size));
346 exit(1);
347 }
348
349
350 initrd_size = 0;
351 initrd_offset = 0;
352 if (loaderparams.initrd_filename) {
353 initrd_size = get_image_size(loaderparams.initrd_filename);
354 if (initrd_size > 0) {
355 initrd_offset = MAX(loader_memmap[LOADER_INITRD].base,
356 ROUND_UP(kernel_high, INITRD_PAGE_SIZE));
357
358 if (initrd_offset + initrd_size > loaderparams.ram_size) {
359 error_report("memory too small for initial ram disk '%s'",
360 loaderparams.initrd_filename);
361 exit(1);
362 }
363
364 initrd_size = load_image_targphys(loaderparams.initrd_filename,
365 initrd_offset,
366 loaderparams.ram_size - initrd_offset);
367 }
368
369 if (initrd_size == (target_ulong) -1) {
370 error_report("could not load initial ram disk '%s'",
371 loaderparams.initrd_filename);
372 exit(1);
373 }
374 }
375
376
377 set_prom_cmdline(initrd_offset, initrd_size);
378
379 return kernel_entry;
380}
381
382static void main_cpu_reset(void *opaque)
383{
384 MIPSCPU *cpu = opaque;
385 CPUMIPSState *env = &cpu->env;
386
387 cpu_reset(CPU(cpu));
388
389
390 if (loaderparams.kernel_filename) {
391 if (cpu == MIPS_CPU(first_cpu)) {
392 env->active_tc.gpr[4] = loaderparams.a0;
393 env->active_tc.gpr[5] = loaderparams.a1;
394 env->active_tc.gpr[6] = loaderparams.a2;
395 env->active_tc.PC = loaderparams.kernel_entry;
396 }
397 env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
398 }
399}
400
401static inline void loongson3_virt_devices_init(MachineState *machine,
402 DeviceState *pic)
403{
404 int i;
405 qemu_irq irq;
406 PCIBus *pci_bus;
407 DeviceState *dev;
408 MemoryRegion *mmio_reg, *ecam_reg;
409 LoongsonMachineState *s = LOONGSON_MACHINE(machine);
410
411 dev = qdev_new(TYPE_GPEX_HOST);
412 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
413 pci_bus = PCI_HOST_BRIDGE(dev)->bus;
414
415 s->ecam_alias = g_new0(MemoryRegion, 1);
416 ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
417 memory_region_init_alias(s->ecam_alias, OBJECT(dev), "pcie-ecam",
418 ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
419 memory_region_add_subregion(get_system_memory(),
420 virt_memmap[VIRT_PCIE_ECAM].base,
421 s->ecam_alias);
422
423 s->mmio_alias = g_new0(MemoryRegion, 1);
424 mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
425 memory_region_init_alias(s->mmio_alias, OBJECT(dev), "pcie-mmio",
426 mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
427 virt_memmap[VIRT_PCIE_MMIO].size);
428 memory_region_add_subregion(get_system_memory(),
429 virt_memmap[VIRT_PCIE_MMIO].base,
430 s->mmio_alias);
431
432 s->pio_alias = g_new0(MemoryRegion, 1);
433 memory_region_init_alias(s->pio_alias, OBJECT(dev), "pcie-pio",
434 get_system_io(), 0,
435 virt_memmap[VIRT_PCIE_PIO].size);
436 memory_region_add_subregion(get_system_memory(),
437 virt_memmap[VIRT_PCIE_PIO].base, s->pio_alias);
438 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
439
440 for (i = 0; i < GPEX_NUM_IRQS; i++) {
441 irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
442 sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
443 gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
444 }
445 msi_nonbroken = true;
446
447 pci_vga_init(pci_bus);
448
449 if (defaults_enabled()) {
450 pci_create_simple(pci_bus, -1, "pci-ohci");
451 usb_create_simple(usb_bus_find(-1), "usb-kbd");
452 usb_create_simple(usb_bus_find(-1), "usb-tablet");
453 }
454
455 for (i = 0; i < nb_nics; i++) {
456 NICInfo *nd = &nd_table[i];
457
458 if (!nd->model) {
459 nd->model = g_strdup("virtio");
460 }
461
462 pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
463 }
464}
465
466static void mips_loongson3_virt_init(MachineState *machine)
467{
468 int i;
469 long bios_size;
470 MIPSCPU *cpu;
471 Clock *cpuclk;
472 CPUMIPSState *env;
473 DeviceState *liointc;
474 char *filename;
475 const char *kernel_cmdline = machine->kernel_cmdline;
476 const char *kernel_filename = machine->kernel_filename;
477 const char *initrd_filename = machine->initrd_filename;
478 ram_addr_t ram_size = machine->ram_size;
479 MemoryRegion *address_space_mem = get_system_memory();
480 MemoryRegion *ram = g_new(MemoryRegion, 1);
481 MemoryRegion *bios = g_new(MemoryRegion, 1);
482 MemoryRegion *iomem = g_new(MemoryRegion, 1);
483
484
485 if (!kvm_enabled()) {
486 if (!machine->cpu_type) {
487 machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
488 }
489 if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
490 error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
491 exit(1);
492 }
493 } else {
494 if (!machine->cpu_type) {
495 machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
496 }
497 if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
498 error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
499 exit(1);
500 }
501 }
502
503 if (ram_size < 512 * MiB) {
504 error_report("Loongson-3 machine needs at least 512MB memory");
505 exit(1);
506 }
507
508
509
510
511
512
513 create_unimplemented_device("mmio fallback 0", 0x10000000, 256 * MiB);
514 create_unimplemented_device("mmio fallback 1", 0x30000000, 256 * MiB);
515
516 liointc = qdev_new("loongson.liointc");
517 sysbus_realize_and_unref(SYS_BUS_DEVICE(liointc), &error_fatal);
518
519 sysbus_mmio_map(SYS_BUS_DEVICE(liointc), 0, virt_memmap[VIRT_LIOINTC].base);
520
521 serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0,
522 qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0),
523 DEVICE_NATIVE_ENDIAN);
524
525 sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base,
526 qdev_get_gpio_in(liointc, RTC_IRQ));
527
528 cpuclk = clock_new(OBJECT(machine), "cpu-refclk");
529 clock_set_hz(cpuclk, DEF_LOONGSON3_FREQ);
530
531 for (i = 0; i < machine->smp.cpus; i++) {
532 int ip;
533
534
535 cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
536
537
538 cpu_mips_irq_init_cpu(cpu);
539 cpu_mips_clock_init(cpu);
540 qemu_register_reset(main_cpu_reset, cpu);
541
542 if (i >= 4) {
543 continue;
544 }
545
546 for (ip = 0; ip < 4 ; ip++) {
547 int pin = i * 4 + ip;
548 sysbus_connect_irq(SYS_BUS_DEVICE(liointc),
549 pin, cpu->env.irq[ip + 2]);
550 }
551 }
552 env = &MIPS_CPU(first_cpu)->env;
553
554
555 memory_region_init_rom(bios, NULL, "loongson3.bios",
556 virt_memmap[VIRT_BIOS_ROM].size, &error_fatal);
557 memory_region_init_alias(ram, NULL, "loongson3.lowmem",
558 machine->ram, 0, virt_memmap[VIRT_LOWMEM].size);
559 memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
560 NULL, "loongson3_pm", virt_memmap[VIRT_PM].size);
561
562 memory_region_add_subregion(address_space_mem,
563 virt_memmap[VIRT_LOWMEM].base, ram);
564 memory_region_add_subregion(address_space_mem,
565 virt_memmap[VIRT_BIOS_ROM].base, bios);
566 memory_region_add_subregion(address_space_mem,
567 virt_memmap[VIRT_HIGHMEM].base, machine->ram);
568 memory_region_add_subregion(address_space_mem,
569 virt_memmap[VIRT_PM].base, iomem);
570
571
572
573
574
575
576 if (kernel_filename) {
577 loaderparams.cpu_freq = get_cpu_freq_hz();
578 loaderparams.ram_size = ram_size;
579 loaderparams.kernel_filename = kernel_filename;
580 loaderparams.kernel_cmdline = kernel_cmdline;
581 loaderparams.initrd_filename = initrd_filename;
582 loaderparams.kernel_entry = load_kernel(env);
583
584 init_boot_rom();
585 init_boot_param();
586 } else {
587 filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
588 machine->firmware ?: LOONGSON3_BIOSNAME);
589 if (filename) {
590 bios_size = load_image_targphys(filename,
591 virt_memmap[VIRT_BIOS_ROM].base,
592 virt_memmap[VIRT_BIOS_ROM].size);
593 g_free(filename);
594 } else {
595 bios_size = -1;
596 }
597
598 if ((bios_size < 0 || bios_size > virt_memmap[VIRT_BIOS_ROM].size) &&
599 !kernel_filename && !qtest_enabled()) {
600 error_report("Could not load MIPS bios '%s'", machine->firmware);
601 exit(1);
602 }
603
604 fw_conf_init(ram_size);
605 }
606
607 loongson3_virt_devices_init(machine, liointc);
608}
609
610static void loongson3v_machine_class_init(ObjectClass *oc, void *data)
611{
612 MachineClass *mc = MACHINE_CLASS(oc);
613
614 mc->desc = "Loongson-3 Virtualization Platform";
615 mc->init = mips_loongson3_virt_init;
616 mc->block_default_type = IF_IDE;
617 mc->max_cpus = LOONGSON_MAX_VCPUS;
618 mc->default_ram_id = "loongson3.highram";
619 mc->default_ram_size = 1600 * MiB;
620 mc->kvm_type = mips_kvm_type;
621 mc->minimum_page_bits = 14;
622}
623
624static const TypeInfo loongson3_machine_types[] = {
625 {
626 .name = TYPE_LOONGSON_MACHINE,
627 .parent = TYPE_MACHINE,
628 .instance_size = sizeof(LoongsonMachineState),
629 .class_init = loongson3v_machine_class_init,
630 }
631};
632
633DEFINE_TYPES(loongson3_machine_types)
634