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