/*
- * QEMU Sun4u System Emulator
+ * QEMU Sun4u/Sun4v System Emulator
*
* Copyright (c) 2005 Fabrice Bellard
*
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "vl.h"
-#include "m48t59.h"
+#include "hw.h"
+#include "pci.h"
+#include "pc.h"
+#include "nvram.h"
+#include "fdc.h"
+#include "net.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "firmware_abi.h"
+#include "fw_cfg.h"
+
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...) \
+ do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
#define KERNEL_LOAD_ADDR 0x00404000
#define CMDLINE_ADDR 0x003ff000
#define INITRD_LOAD_ADDR 0x00300000
-#define PROM_SIZE_MAX (512 * 1024)
-#define PROM_ADDR 0x1fff0000000ULL
+#define PROM_SIZE_MAX (4 * 1024 * 1024)
#define PROM_VADDR 0x000ffd00000ULL
#define APB_SPECIAL_BASE 0x1fe00000000ULL
#define APB_MEM_BASE 0x1ff00000000ULL
#define VGA_BASE (APB_MEM_BASE + 0x400000ULL)
#define PROM_FILENAME "openbios-sparc64"
#define NVRAM_SIZE 0x2000
+#define MAX_IDE_BUS 2
+#define BIOS_CFG_IOPORT 0x510
-/* TSC handling */
+#define MAX_PILS 16
-uint64_t cpu_get_tsc()
-{
- return qemu_get_clock(vm_clock);
-}
+#define TICK_INT_DIS 0x8000000000000000ULL
+#define TICK_MAX 0x7fffffffffffffffULL
+
+struct hwdef {
+ const char * const default_cpu_model;
+ uint16_t machine_id;
+ uint64_t prom_addr;
+ uint64_t console_serial_base;
+};
int DMA_get_channel_mode (int nchan)
{
void DMA_hold_DREQ (int nchan) {}
void DMA_release_DREQ (int nchan) {}
void DMA_schedule(int nchan) {}
-void DMA_run (void) {}
void DMA_init (int high_page_enable) {}
void DMA_register_channel (int nchan,
DMA_transfer_handler transfer_handler,
{
}
-/* NVRAM helpers */
-void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
+static int fw_cfg_boot_set(void *opaque, const char *boot_device)
{
- m48t59_write(nvram, addr, value);
-}
-
-uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
-{
- return m48t59_read(nvram, addr);
-}
-
-void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
-{
- m48t59_write(nvram, addr, value >> 8);
- m48t59_write(nvram, addr + 1, value & 0xFF);
+ fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+ return 0;
}
-uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
+static int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
+ const char *arch,
+ ram_addr_t RAM_size,
+ const char *boot_devices,
+ uint32_t kernel_image, uint32_t kernel_size,
+ const char *cmdline,
+ uint32_t initrd_image, uint32_t initrd_size,
+ uint32_t NVRAM_image,
+ int width, int height, int depth,
+ const uint8_t *macaddr)
{
- uint16_t tmp;
+ unsigned int i;
+ uint32_t start, end;
+ uint8_t image[0x1ff0];
+ struct OpenBIOS_nvpart_v1 *part_header;
- tmp = m48t59_read(nvram, addr) << 8;
- tmp |= m48t59_read(nvram, addr + 1);
+ memset(image, '\0', sizeof(image));
- return tmp;
-}
+ start = 0;
-void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
-{
- m48t59_write(nvram, addr, value >> 24);
- m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
- m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
- m48t59_write(nvram, addr + 3, value & 0xFF);
-}
+ // OpenBIOS nvram variables
+ // Variable partition
+ part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+ part_header->signature = OPENBIOS_PART_SYSTEM;
+ pstrcpy(part_header->name, sizeof(part_header->name), "system");
-uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
-{
- uint32_t tmp;
+ end = start + sizeof(struct OpenBIOS_nvpart_v1);
+ for (i = 0; i < nb_prom_envs; i++)
+ end = OpenBIOS_set_var(image, end, prom_envs[i]);
- tmp = m48t59_read(nvram, addr) << 24;
- tmp |= m48t59_read(nvram, addr + 1) << 16;
- tmp |= m48t59_read(nvram, addr + 2) << 8;
- tmp |= m48t59_read(nvram, addr + 3);
+ // End marker
+ image[end++] = '\0';
- return tmp;
-}
+ end = start + ((end - start + 15) & ~15);
+ OpenBIOS_finish_partition(part_header, end - start);
-void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
- const unsigned char *str, uint32_t max)
-{
- int i;
+ // free partition
+ start = end;
+ part_header = (struct OpenBIOS_nvpart_v1 *)&image[start];
+ part_header->signature = OPENBIOS_PART_FREE;
+ pstrcpy(part_header->name, sizeof(part_header->name), "free");
- for (i = 0; i < max && str[i] != '\0'; i++) {
- m48t59_write(nvram, addr + i, str[i]);
- }
- m48t59_write(nvram, addr + max - 1, '\0');
-}
+ end = 0x1fd0;
+ OpenBIOS_finish_partition(part_header, end - start);
-int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
-{
- int i;
+ Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80);
- memset(dst, 0, max);
- for (i = 0; i < max; i++) {
- dst[i] = NVRAM_get_byte(nvram, addr + i);
- if (dst[i] == '\0')
- break;
- }
+ for (i = 0; i < sizeof(image); i++)
+ m48t59_write(nvram, i, image[i]);
- return i;
+ return 0;
}
-static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
+void pic_info(Monitor *mon)
{
- uint16_t tmp;
- uint16_t pd, pd1, pd2;
-
- tmp = prev >> 8;
- pd = prev ^ value;
- pd1 = pd & 0x000F;
- pd2 = ((pd >> 4) & 0x000F) ^ pd1;
- tmp ^= (pd1 << 3) | (pd1 << 8);
- tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
-
- return tmp;
}
-uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
+void irq_info(Monitor *mon)
{
- uint32_t i;
- uint16_t crc = 0xFFFF;
- int odd;
-
- odd = count & 1;
- count &= ~1;
- for (i = 0; i != count; i++) {
- crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
- }
- if (odd) {
- crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
- }
-
- return crc;
}
-static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr,
- const unsigned char *str)
+void cpu_check_irqs(CPUState *env)
{
- uint32_t len;
+ uint32_t pil = env->pil_in | (env->softint & ~SOFTINT_TIMER) |
+ ((env->softint & SOFTINT_TIMER) << 14);
- len = strlen(str) + 1;
- NVRAM_set_string(nvram, addr, str, len);
+ if (pil && (env->interrupt_index == 0 ||
+ (env->interrupt_index & ~15) == TT_EXTINT)) {
+ unsigned int i;
- return addr + len;
-}
+ for (i = 15; i > 0; i--) {
+ if (pil & (1 << i)) {
+ int old_interrupt = env->interrupt_index;
-static void nvram_finish_partition (m48t59_t *nvram, uint32_t start,
- uint32_t end)
-{
- unsigned int i, sum;
-
- // Length divided by 16
- m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff);
- m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff);
- // Checksum
- sum = m48t59_read(nvram, start);
- for (i = 0; i < 14; i++) {
- sum += m48t59_read(nvram, start + 2 + i);
- sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
+ env->interrupt_index = TT_EXTINT | i;
+ if (old_interrupt != env->interrupt_index) {
+ DPRINTF("Set CPU IRQ %d\n", i);
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ break;
+ }
+ }
+ } else if (!pil && (env->interrupt_index & ~15) == TT_EXTINT) {
+ DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15);
+ env->interrupt_index = 0;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
- m48t59_write(nvram, start + 1, sum & 0xff);
}
-extern int nographic;
-
-int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
- const unsigned char *arch,
- uint32_t RAM_size, int boot_device,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth)
+static void cpu_set_irq(void *opaque, int irq, int level)
{
- uint16_t crc;
- unsigned int i;
- uint32_t start, end;
+ CPUState *env = opaque;
- /* Set parameters for Open Hack'Ware BIOS */
- NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
- NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
- NVRAM_set_word(nvram, 0x14, NVRAM_size);
- NVRAM_set_string(nvram, 0x20, arch, 16);
- NVRAM_set_byte(nvram, 0x2f, nographic & 0xff);
- NVRAM_set_lword(nvram, 0x30, RAM_size);
- NVRAM_set_byte(nvram, 0x34, boot_device);
- NVRAM_set_lword(nvram, 0x38, kernel_image);
- NVRAM_set_lword(nvram, 0x3C, kernel_size);
- if (cmdline) {
- /* XXX: put the cmdline in NVRAM too ? */
- strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
- NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
- NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
+ if (level) {
+ DPRINTF("Raise CPU IRQ %d\n", irq);
+ env->halted = 0;
+ env->pil_in |= 1 << irq;
+ cpu_check_irqs(env);
} else {
- NVRAM_set_lword(nvram, 0x40, 0);
- NVRAM_set_lword(nvram, 0x44, 0);
+ DPRINTF("Lower CPU IRQ %d\n", irq);
+ env->pil_in &= ~(1 << irq);
+ cpu_check_irqs(env);
}
- NVRAM_set_lword(nvram, 0x48, initrd_image);
- NVRAM_set_lword(nvram, 0x4C, initrd_size);
- NVRAM_set_lword(nvram, 0x50, NVRAM_image);
-
- NVRAM_set_word(nvram, 0x54, width);
- NVRAM_set_word(nvram, 0x56, height);
- NVRAM_set_word(nvram, 0x58, depth);
- crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
- NVRAM_set_word(nvram, 0xFC, crc);
-
- // OpenBIOS nvram variables
- // Variable partition
- start = 256;
- m48t59_write(nvram, start, 0x70);
- NVRAM_set_string(nvram, start + 4, "system", 12);
-
- end = start + 16;
- for (i = 0; i < nb_prom_envs; i++)
- end = nvram_set_var(nvram, end, prom_envs[i]);
-
- m48t59_write(nvram, end++ , 0);
- end = start + ((end - start + 15) & ~15);
- nvram_finish_partition(nvram, start, end);
-
- // free partition
- start = end;
- m48t59_write(nvram, start, 0x7f);
- NVRAM_set_string(nvram, start + 4, "free", 12);
-
- end = 0x1fd0;
- nvram_finish_partition(nvram, start, end);
-
- return 0;
}
-void pic_info()
+void qemu_system_powerdown(void)
{
}
-void irq_info()
-{
-}
+typedef struct ResetData {
+ CPUState *env;
+ uint64_t reset_addr;
+} ResetData;
-void qemu_system_powerdown(void)
+static void main_cpu_reset(void *opaque)
{
+ ResetData *s = (ResetData *)opaque;
+ CPUState *env = s->env;
+
+ cpu_reset(env);
+ env->tick_cmpr = TICK_INT_DIS | 0;
+ ptimer_set_limit(env->tick, TICK_MAX, 1);
+ ptimer_run(env->tick, 1);
+ env->stick_cmpr = TICK_INT_DIS | 0;
+ ptimer_set_limit(env->stick, TICK_MAX, 1);
+ ptimer_run(env->stick, 1);
+ env->hstick_cmpr = TICK_INT_DIS | 0;
+ ptimer_set_limit(env->hstick, TICK_MAX, 1);
+ ptimer_run(env->hstick, 1);
+ env->gregs[1] = 0; // Memory start
+ env->gregs[2] = ram_size; // Memory size
+ env->gregs[3] = 0; // Machine description XXX
+ env->pc = s->reset_addr;
+ env->npc = env->pc + 4;
}
-static void main_cpu_reset(void *opaque)
+static void tick_irq(void *opaque)
{
CPUState *env = opaque;
- cpu_reset(env);
- ptimer_set_limit(env->tick, 0x7fffffffffffffffULL, 1);
- ptimer_run(env->tick, 0);
- ptimer_set_limit(env->stick, 0x7fffffffffffffffULL, 1);
- ptimer_run(env->stick, 0);
- ptimer_set_limit(env->hstick, 0x7fffffffffffffffULL, 1);
- ptimer_run(env->hstick, 0);
+ if (!(env->tick_cmpr & TICK_INT_DIS)) {
+ env->softint |= SOFTINT_TIMER;
+ cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ }
}
-void tick_irq(void *opaque)
+static void stick_irq(void *opaque)
{
CPUState *env = opaque;
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ if (!(env->stick_cmpr & TICK_INT_DIS)) {
+ env->softint |= SOFTINT_STIMER;
+ cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ }
}
-void stick_irq(void *opaque)
+static void hstick_irq(void *opaque)
{
CPUState *env = opaque;
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ if (!(env->hstick_cmpr & TICK_INT_DIS)) {
+ cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ }
}
-void hstick_irq(void *opaque)
+void cpu_tick_set_count(void *opaque, uint64_t count)
{
- CPUState *env = opaque;
+ ptimer_set_count(opaque, -count);
+}
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+uint64_t cpu_tick_get_count(void *opaque)
+{
+ return -ptimer_get_count(opaque);
}
-static void dummy_cpu_set_irq(void *opaque, int irq, int level)
+void cpu_tick_set_limit(void *opaque, uint64_t limit)
{
+ ptimer_set_limit(opaque, -limit, 0);
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static fdctrl_t *floppy_controller;
-/* Sun4u hardware initialisation */
-static void sun4u_init(int ram_size, int vga_ram_size, const char *boot_device,
- DisplayState *ds, const char **fd_filename, int snapshot,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename, const char *cpu_model)
+static void ebus_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ DPRINTF("Mapping region %d registers at %08x\n", region_num, addr);
+ switch (region_num) {
+ case 0:
+ isa_mmio_init(addr, 0x1000000);
+ break;
+ case 1:
+ isa_mmio_init(addr, 0x800000);
+ break;
+ }
+}
+
+/* EBUS (Eight bit bus) bridge */
+static void
+pci_ebus_init(PCIBus *bus, int devfn)
+{
+ PCIDevice *s;
+
+ s = pci_register_device(bus, "EBUS", sizeof(*s), devfn, NULL, NULL);
+ pci_config_set_vendor_id(s->config, PCI_VENDOR_ID_SUN);
+ pci_config_set_device_id(s->config, PCI_DEVICE_ID_SUN_EBUS);
+ s->config[0x04] = 0x06; // command = bus master, pci mem
+ s->config[0x05] = 0x00;
+ s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+ s->config[0x07] = 0x03; // status = medium devsel
+ s->config[0x08] = 0x01; // revision
+ s->config[0x09] = 0x00; // programming i/f
+ pci_config_set_class(s->config, PCI_CLASS_BRIDGE_OTHER);
+ s->config[0x0D] = 0x0a; // latency_timer
+ s->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
+
+ pci_register_io_region(s, 0, 0x1000000, PCI_ADDRESS_SPACE_MEM,
+ ebus_mmio_mapfunc);
+ pci_register_io_region(s, 1, 0x800000, PCI_ADDRESS_SPACE_MEM,
+ ebus_mmio_mapfunc);
+}
+
+static void sun4uv_init(ram_addr_t RAM_size,
+ const char *boot_devices,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model,
+ const struct hwdef *hwdef)
{
CPUState *env;
- char buf[1024];
+ char *filename;
m48t59_t *nvram;
int ret, linux_boot;
unsigned int i;
- long prom_offset, initrd_size, kernel_size;
- PCIBus *pci_bus;
- const sparc_def_t *def;
+ ram_addr_t ram_offset, prom_offset;
+ long initrd_size, kernel_size;
+ PCIBus *pci_bus, *pci_bus2, *pci_bus3;
QEMUBH *bh;
qemu_irq *irq;
+ int drive_index;
+ BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ BlockDriverState *fd[MAX_FD];
+ void *fw_cfg;
+ ResetData *reset_info;
linux_boot = (kernel_filename != NULL);
/* init CPUs */
- if (cpu_model == NULL)
- cpu_model = "TI UltraSparc II";
- sparc_find_by_name(cpu_model, &def);
- if (def == NULL) {
+ if (!cpu_model)
+ cpu_model = hwdef->default_cpu_model;
+
+ env = cpu_init(cpu_model);
+ if (!env) {
fprintf(stderr, "Unable to find Sparc CPU definition\n");
exit(1);
}
- env = cpu_init();
- cpu_sparc_register(env, def, 0);
bh = qemu_bh_new(tick_irq, env);
env->tick = ptimer_init(bh);
ptimer_set_period(env->tick, 1ULL);
bh = qemu_bh_new(hstick_irq, env);
env->hstick = ptimer_init(bh);
ptimer_set_period(env->hstick, 1ULL);
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
- qemu_register_reset(main_cpu_reset, env);
- main_cpu_reset(env);
+
+ reset_info = qemu_mallocz(sizeof(ResetData));
+ reset_info->env = env;
+ reset_info->reset_addr = hwdef->prom_addr + 0x40ULL;
+ qemu_register_reset(main_cpu_reset, 0, reset_info);
+ main_cpu_reset(reset_info);
+ // Override warm reset address with cold start address
+ env->pc = hwdef->prom_addr + 0x20ULL;
+ env->npc = env->pc + 4;
/* allocate RAM */
- cpu_register_physical_memory(0, ram_size, 0);
+ ram_offset = qemu_ram_alloc(RAM_size);
+ cpu_register_physical_memory(0, RAM_size, ram_offset);
- prom_offset = ram_size + vga_ram_size;
- cpu_register_physical_memory(PROM_ADDR,
- (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
+ prom_offset = qemu_ram_alloc(PROM_SIZE_MAX);
+ cpu_register_physical_memory(hwdef->prom_addr,
+ (PROM_SIZE_MAX + TARGET_PAGE_SIZE) &
+ TARGET_PAGE_MASK,
prom_offset | IO_MEM_ROM);
if (bios_name == NULL)
bios_name = PROM_FILENAME;
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- ret = load_elf(buf, PROM_ADDR - PROM_VADDR, NULL, NULL, NULL);
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (filename) {
+ ret = load_elf(filename, hwdef->prom_addr - PROM_VADDR,
+ NULL, NULL, NULL);
+ if (ret < 0) {
+ ret = load_image_targphys(filename, hwdef->prom_addr,
+ (PROM_SIZE_MAX + TARGET_PAGE_SIZE) &
+ TARGET_PAGE_MASK);
+ }
+ qemu_free(filename);
+ } else {
+ ret = -1;
+ }
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
- buf);
+ bios_name);
exit(1);
}
/* XXX: put correct offset */
kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL);
if (kernel_size < 0)
- kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+ kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
+ ram_size - KERNEL_LOAD_ADDR);
if (kernel_size < 0)
- kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+ kernel_size = load_image_targphys(kernel_filename,
+ KERNEL_LOAD_ADDR,
+ ram_size - KERNEL_LOAD_ADDR);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
/* load initrd */
if (initrd_filename) {
- initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
+ initrd_size = load_image_targphys(initrd_filename,
+ INITRD_LOAD_ADDR,
+ ram_size - INITRD_LOAD_ADDR);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
}
if (initrd_size > 0) {
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
- if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
- == 0x48647253) { // HdrS
- stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
- stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
+ if (ldl_phys(KERNEL_LOAD_ADDR + i) == 0x48647253) { // HdrS
+ stl_phys(KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
+ stl_phys(KERNEL_LOAD_ADDR + i + 20, initrd_size);
break;
}
}
}
}
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL);
+ pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL, &pci_bus2,
+ &pci_bus3);
isa_mem_base = VGA_BASE;
- pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size);
+ pci_vga_init(pci_bus, 0, 0);
+
+ // XXX Should be pci_bus3
+ pci_ebus_init(pci_bus, -1);
- for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+ i = 0;
+ if (hwdef->console_serial_base) {
+ serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200,
+ serial_hds[i], 1);
+ i++;
+ }
+ for(; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
- serial_init(serial_io[i], NULL/*serial_irq[i]*/, serial_hds[i]);
+ serial_init(serial_io[i], NULL/*serial_irq[i]*/, 115200,
+ serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
- parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/, parallel_hds[i]);
+ parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/,
+ parallel_hds[i]);
}
}
- for(i = 0; i < nb_nics; i++) {
- if (!nd_table[i].model)
- nd_table[i].model = "ne2k_pci";
- pci_nic_init(pci_bus, &nd_table[i], -1);
+ for(i = 0; i < nb_nics; i++)
+ pci_nic_init(pci_bus, &nd_table[i], -1, "ne2k_pci");
+
+ irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
+ 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++) {
+ drive_index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS,
+ i % MAX_IDE_DEVS);
+ if (drive_index != -1)
+ hd[i] = drives_table[drive_index].bdrv;
+ else
+ hd[i] = NULL;
}
- irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32);
- // XXX pci_cmd646_ide_init(pci_bus, bs_table, 1);
- pci_piix3_ide_init(pci_bus, bs_table, -1, irq);
+ pci_cmd646_ide_init(pci_bus, hd, 1);
+
/* FIXME: wire up interrupts. */
i8042_init(NULL/*1*/, NULL/*12*/, 0x60);
- floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table);
+ for(i = 0; i < MAX_FD; i++) {
+ drive_index = drive_get_index(IF_FLOPPY, 0, i);
+ if (drive_index != -1)
+ fd[i] = drives_table[drive_index].bdrv;
+ else
+ fd[i] = NULL;
+ }
+ floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd);
nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59);
- sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device[0],
- KERNEL_LOAD_ADDR, kernel_size,
- kernel_cmdline,
- INITRD_LOAD_ADDR, initrd_size,
- /* XXX: need an option to load a NVRAM image */
- 0,
- graphic_width, graphic_height, graphic_depth);
+ sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices,
+ KERNEL_LOAD_ADDR, kernel_size,
+ kernel_cmdline,
+ INITRD_LOAD_ADDR, initrd_size,
+ /* XXX: need an option to load a NVRAM image */
+ 0,
+ graphic_width, graphic_height, graphic_depth,
+ (uint8_t *)&nd_table[0].macaddr);
+
+ fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
+ fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
+ if (kernel_cmdline) {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
+ pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+ } else {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+ }
+ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]);
+ qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+enum {
+ sun4u_id = 0,
+ sun4v_id = 64,
+ niagara_id,
+};
+static const struct hwdef hwdefs[] = {
+ /* Sun4u generic PC-like machine */
+ {
+ .default_cpu_model = "TI UltraSparc II",
+ .machine_id = sun4u_id,
+ .prom_addr = 0x1fff0000000ULL,
+ .console_serial_base = 0,
+ },
+ /* Sun4v generic PC-like machine */
+ {
+ .default_cpu_model = "Sun UltraSparc T1",
+ .machine_id = sun4v_id,
+ .prom_addr = 0x1fff0000000ULL,
+ .console_serial_base = 0,
+ },
+ /* Sun4v generic Niagara machine */
+ {
+ .default_cpu_model = "Sun UltraSparc T1",
+ .machine_id = niagara_id,
+ .prom_addr = 0xfff0000000ULL,
+ .console_serial_base = 0xfff0c2c000ULL,
+ },
+};
+
+/* Sun4u hardware initialisation */
+static void sun4u_init(ram_addr_t RAM_size,
+ const char *boot_devices,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ sun4uv_init(RAM_size, boot_devices, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]);
}
-QEMUMachine sun4u_machine = {
- "sun4u",
- "Sun4u platform",
- sun4u_init,
+/* Sun4v hardware initialisation */
+static void sun4v_init(ram_addr_t RAM_size,
+ const char *boot_devices,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ sun4uv_init(RAM_size, boot_devices, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]);
+}
+
+/* Niagara hardware initialisation */
+static void niagara_init(ram_addr_t RAM_size,
+ const char *boot_devices,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ sun4uv_init(RAM_size, boot_devices, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]);
+}
+
+static QEMUMachine sun4u_machine = {
+ .name = "sun4u",
+ .desc = "Sun4u platform",
+ .init = sun4u_init,
+ .max_cpus = 1, // XXX for now
+ .is_default = 1,
+};
+
+static QEMUMachine sun4v_machine = {
+ .name = "sun4v",
+ .desc = "Sun4v platform",
+ .init = sun4v_init,
+ .max_cpus = 1, // XXX for now
+};
+
+static QEMUMachine niagara_machine = {
+ .name = "Niagara",
+ .desc = "Sun4v platform, Niagara",
+ .init = niagara_init,
+ .max_cpus = 1, // XXX for now
};
+
+static void sun4u_machine_init(void)
+{
+ qemu_register_machine(&sun4u_machine);
+ qemu_register_machine(&sun4v_machine);
+ qemu_register_machine(&niagara_machine);
+}
+
+machine_init(sun4u_machine_init);