* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/char/serial.h"
#include "elf.h"
#include "hw/timer/mc146818rtc.h"
#include "hw/timer/i8254.h"
-#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "exec/address-spaces.h"
#include "hw/sysbus.h" /* SysBusDevice */
#include "qemu/error-report.h"
#include "hw/empty_slot.h"
#include "sysemu/kvm.h"
+#include "exec/semihost.h"
+#include "hw/mips/cps.h"
//#define DEBUG_BOARD_INIT
uint32_t i2coe;
uint32_t i2cout;
uint32_t i2csel;
- CharDriverState *display;
+ CharBackend display;
char display_text[9];
SerialState *uart;
+ bool display_inited;
} MaltaFPGAState;
#define TYPE_MIPS_MALTA "mips-malta"
typedef struct {
SysBusDevice parent_obj;
+ MIPSCPSState *cps;
qemu_irq *i8259;
} MaltaState;
}
leds_text[8] = '\0';
- qemu_chr_fe_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
- qemu_chr_fe_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
+ qemu_chr_fe_printf(&s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n",
+ leds_text);
+ qemu_chr_fe_printf(&s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|",
+ s->display_text);
}
/*
snprintf(s->display_text, 9, " ");
}
-static void malta_fpga_led_init(CharDriverState *chr)
+static void malta_fgpa_display_event(void *opaque, int event)
{
- qemu_chr_fe_printf(chr, "\e[HMalta LEDBAR\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
- qemu_chr_fe_printf(chr, "+ +\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
- qemu_chr_fe_printf(chr, "\n");
- qemu_chr_fe_printf(chr, "Malta ASCII\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
- qemu_chr_fe_printf(chr, "+ +\r\n");
- qemu_chr_fe_printf(chr, "+--------+\r\n");
+ MaltaFPGAState *s = opaque;
+
+ if (event == CHR_EVENT_OPENED && !s->display_inited) {
+ qemu_chr_fe_printf(&s->display, "\e[HMalta LEDBAR\r\n");
+ qemu_chr_fe_printf(&s->display, "+--------+\r\n");
+ qemu_chr_fe_printf(&s->display, "+ +\r\n");
+ qemu_chr_fe_printf(&s->display, "+--------+\r\n");
+ qemu_chr_fe_printf(&s->display, "\n");
+ qemu_chr_fe_printf(&s->display, "Malta ASCII\r\n");
+ qemu_chr_fe_printf(&s->display, "+--------+\r\n");
+ qemu_chr_fe_printf(&s->display, "+ +\r\n");
+ qemu_chr_fe_printf(&s->display, "+--------+\r\n");
+ s->display_inited = true;
+ }
}
static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
- hwaddr base, qemu_irq uart_irq, CharDriverState *uart_chr)
+ hwaddr base, qemu_irq uart_irq, Chardev *uart_chr)
{
MaltaFPGAState *s;
+ Chardev *chr;
s = (MaltaFPGAState *)g_malloc0(sizeof(MaltaFPGAState));
memory_region_add_subregion(address_space, base, &s->iomem_lo);
memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
- s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
+ chr = qemu_chr_new("fpga", "vc:320x200");
+ qemu_chr_fe_init(&s->display, chr, NULL);
+ qemu_chr_fe_set_handlers(&s->display, NULL, NULL,
+ malta_fgpa_display_event, s, NULL, true);
s->uart = serial_mm_init(address_space, base + 0x900, 3, uart_irq,
230400, uart_chr, DEVICE_NATIVE_ENDIAN);
a3 - RAM size in bytes
*/
-static void write_bootloader (CPUMIPSState *env, uint8_t *base,
- int64_t run_addr, int64_t kernel_entry)
+static void write_bootloader(uint8_t *base, int64_t run_addr,
+ int64_t kernel_entry)
{
uint32_t *p;
/* Second part of the bootloader */
p = (uint32_t *) (base + 0x580);
- stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */
+
+ if (semihosting_get_argc()) {
+ /* Preserve a0 content as arguments have been passed */
+ stl_p(p++, 0x00000000); /* nop */
+ } else {
+ stl_p(p++, 0x24040002); /* addiu a0, zero, 2 */
+ }
stl_p(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
stl_p(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */
stl_p(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
stl_p(p++, 0x00000000); /* nop */
stl_p(p++, 0x0ff0021c); /* jal 870 */
stl_p(p++, 0x00000000); /* nop */
- stl_p(p++, 0x08000205); /* j 814 */
+ stl_p(p++, 0x1000fff9); /* b 814 */
stl_p(p++, 0x00000000); /* nop */
stl_p(p++, 0x01a00009); /* jalr t5 */
stl_p(p++, 0x01602021); /* move a0,t3 */
if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
(uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
- big_endian, ELF_MACHINE, 1) < 0) {
+ big_endian, EM_MIPS, 1, 0) < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loaderparams.kernel_filename);
exit(1);
if (kvm_enabled()) {
/* Start running from the bootloader we wrote to end of RAM */
- env->active_tc.PC = 0x40000000 + loaderparams.ram_size;
+ env->active_tc.PC = 0x40000000 + loaderparams.ram_low_size;
}
}
-static void cpu_request_exit(void *opaque, int irq, int level)
+static void create_cpu_without_cps(const char *cpu_model,
+ qemu_irq *cbus_irq, qemu_irq *i8259_irq)
{
- CPUState *cpu = current_cpu;
+ CPUMIPSState *env;
+ MIPSCPU *cpu;
+ int i;
+
+ for (i = 0; i < smp_cpus; i++) {
+ cpu = cpu_mips_init(cpu_model);
+ if (cpu == NULL) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+
+ /* Init internal devices */
+ cpu_mips_irq_init_cpu(cpu);
+ cpu_mips_clock_init(cpu);
+ qemu_register_reset(main_cpu_reset, cpu);
+ }
+
+ cpu = MIPS_CPU(first_cpu);
+ env = &cpu->env;
+ *i8259_irq = env->irq[2];
+ *cbus_irq = env->irq[4];
+}
+
+static void create_cps(MaltaState *s, const char *cpu_model,
+ qemu_irq *cbus_irq, qemu_irq *i8259_irq)
+{
+ Error *err = NULL;
+ s->cps = g_new0(MIPSCPSState, 1);
+
+ object_initialize(s->cps, sizeof(MIPSCPSState), TYPE_MIPS_CPS);
+ qdev_set_parent_bus(DEVICE(s->cps), sysbus_get_default());
+
+ object_property_set_str(OBJECT(s->cps), cpu_model, "cpu-model", &err);
+ object_property_set_int(OBJECT(s->cps), smp_cpus, "num-vp", &err);
+ object_property_set_bool(OBJECT(s->cps), true, "realized", &err);
+ if (err != NULL) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1);
+
+ *i8259_irq = get_cps_irq(s->cps, 3);
+ *cbus_irq = NULL;
+}
+
+static void create_cpu(MaltaState *s, const char *cpu_model,
+ qemu_irq *cbus_irq, qemu_irq *i8259_irq)
+{
+ if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+ cpu_model = "20Kc";
+#else
+ cpu_model = "24Kf";
+#endif
+ }
- if (cpu && level) {
- cpu_exit(cpu);
+ if ((smp_cpus > 1) && cpu_supports_cps_smp(cpu_model)) {
+ create_cps(s, cpu_model, cbus_irq, i8259_irq);
+ } else {
+ create_cpu_without_cps(cpu_model, cbus_irq, i8259_irq);
}
}
{
ram_addr_t ram_size = machine->ram_size;
ram_addr_t ram_low_size;
- const char *cpu_model = machine->cpu_model;
const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename;
int64_t kernel_entry, bootloader_run_addr;
PCIBus *pci_bus;
ISABus *isa_bus;
- MIPSCPU *cpu;
- CPUMIPSState *env;
qemu_irq *isa_irq;
- qemu_irq *cpu_exit_irq;
+ qemu_irq cbus_irq, i8259_irq;
int piix4_devfn;
I2CBus *smbus;
int i;
if (!serial_hds[i]) {
char label[32];
snprintf(label, sizeof(label), "serial%d", i);
- serial_hds[i] = qemu_chr_new(label, "null", NULL);
+ serial_hds[i] = qemu_chr_new(label, "null");
}
}
- /* init CPUs */
- if (cpu_model == NULL) {
-#ifdef TARGET_MIPS64
- cpu_model = "20Kc";
-#else
- cpu_model = "24Kf";
-#endif
- }
-
- for (i = 0; i < smp_cpus; i++) {
- cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
- env = &cpu->env;
-
- /* Init internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
- qemu_register_reset(main_cpu_reset, cpu);
- }
- cpu = MIPS_CPU(first_cpu);
- env = &cpu->env;
+ /* create CPU */
+ create_cpu(s, machine->cpu_model, &cbus_irq, &i8259_irq);
/* allocate RAM */
if (ram_size > (2048u << 20)) {
#endif
/* FPGA */
/* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
- malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]);
+ malta_fpga_init(system_memory, FPGA_ADDRESS, cbus_irq, serial_hds[2]);
/* Load firmware in flash / BIOS. */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
loaderparams.initrd_filename = initrd_filename;
kernel_entry = load_kernel();
- write_bootloader(env, memory_region_get_ram_ptr(bios),
+ write_bootloader(memory_region_get_ram_ptr(bios),
bootloader_run_addr, kernel_entry);
if (kvm_enabled()) {
/* Write the bootloader code @ the end of RAM, 1MB reserved */
- write_bootloader(env, memory_region_get_ram_ptr(ram_low_preio) +
+ write_bootloader(memory_region_get_ram_ptr(ram_low_preio) +
ram_low_size,
bootloader_run_addr, kernel_entry);
}
* regions are not executable.
*/
memory_region_init_ram(bios_copy, NULL, "bios.1fc", BIOS_SIZE,
- &error_abort);
+ &error_fatal);
if (!rom_copy(memory_region_get_ram_ptr(bios_copy),
FLASH_ADDRESS, BIOS_SIZE)) {
memcpy(memory_region_get_ram_ptr(bios_copy),
/* Board ID = 0x420 (Malta Board with CoreLV) */
stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420);
- /* Init internal devices */
- cpu_mips_irq_init_cpu(env);
- cpu_mips_clock_init(env);
-
/*
* We have a circular dependency problem: pci_bus depends on isa_irq,
* isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
/* Interrupt controller */
/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
- s->i8259 = i8259_init(isa_bus, env->irq[2]);
+ s->i8259 = i8259_init(isa_bus, i8259_irq);
isa_bus_irqs(isa_bus, s->i8259);
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size);
g_free(smbus_eeprom_buf);
pit = pit_init(isa_bus, 0x40, 0, NULL);
- cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
- DMA_init(0, cpu_exit_irq);
+ DMA_init(isa_bus, 0);
/* Super I/O */
isa_create_simple(isa_bus, "i8042");
rtc_init(isa_bus, 2000, NULL);
- serial_hds_isa_init(isa_bus, 2);
+ serial_hds_isa_init(isa_bus, 0, 2);
parallel_hds_isa_init(isa_bus, 1);
for(i = 0; i < MAX_FD; i++) {
.class_init = mips_malta_class_init,
};
-static QEMUMachine mips_malta_machine = {
- .name = "malta",
- .desc = "MIPS Malta Core LV",
- .init = mips_malta_init,
- .max_cpus = 16,
- .is_default = 1,
-};
-
-static void mips_malta_register_types(void)
+static void mips_malta_machine_init(MachineClass *mc)
{
- type_register_static(&mips_malta_device);
+ mc->desc = "MIPS Malta Core LV";
+ mc->init = mips_malta_init;
+ mc->block_default_type = IF_IDE;
+ mc->max_cpus = 16;
+ mc->is_default = 1;
}
-static void mips_malta_machine_init(void)
+DEFINE_MACHINE("malta", mips_malta_machine_init)
+
+static void mips_malta_register_types(void)
{
- qemu_register_machine(&mips_malta_machine);
+ type_register_static(&mips_malta_device);
}
type_init(mips_malta_register_types)
-machine_init(mips_malta_machine_init);