RTCState *rtc_init(int base, int irq) { RTCState *s; time_t ti; struct tm *tm; int val; s = qemu_mallocz(sizeof(RTCState)); if (!s) return NULL; /* PC cmos mappings */ #define REG_IBM_CENTURY_BYTE 0x32 #define REG_IBM_PS2_CENTURY_BYTE 0x37 time(&ti); tm = gmtime(&ti); /* XXX localtime and update from guest? */ val = to_bcd(s, (tm->tm_year / 100) + 19); rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); register_ioport_write(base, 2, 1, cmos_ioport_write, s); register_ioport_read(base, 2, 1, cmos_ioport_read, s); register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); return s; }
static void rtc_set_date_from_host(RTCState *s) { struct tm tm; int val; /* set the CMOS date */ qemu_get_timedate(&tm, 0); rtc_set_date(s, &tm); val = to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); }
static void rtc_set_date_from_host(ISADevice *dev) { RTCState *s = DO_UPCAST(RTCState, dev, dev); struct tm tm; int val; /* set the CMOS date */ qemu_get_timedate(&tm, 0); rtc_set_date(dev, &tm); val = rtc_to_bcd(s, (tm.tm_year / 100) + 19); rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val); rtc_set_memory(dev, REG_IBM_PS2_CENTURY_BYTE, val); }
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) * BIOS will read it and start S3 resume at POST Entry */ static void pc_cmos_set_s3_resume(void *opaque, int irq, int level) { ISADevice *s = opaque; if (level) { rtc_set_memory(s, 0xF, 0xFE); } }
static void pc_cmos_init_late(void *opaque) { pc_cmos_init_late_arg *arg = opaque; ISADevice *s = arg->rtc_state; int val; BlockDriverState *hd_table[4]; int i; ide_get_bs(hd_table, arg->idebus0); ide_get_bs(hd_table + 2, arg->idebus1); rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0)); if (hd_table[0]) cmos_init_hd(0x19, 0x1b, hd_table[0], s); if (hd_table[1]) cmos_init_hd(0x1a, 0x24, hd_table[1], s); val = 0; for (i = 0; i < 4; i++) { if (hd_table[i]) { int cylinders, heads, sectors, translation; /* NOTE: bdrv_get_geometry_hint() returns the physical geometry. It is always such that: 1 <= sects <= 63, 1 <= heads <= 16, 1 <= cylinders <= 16383. The BIOS geometry can be different if a translation is done. */ translation = bdrv_get_translation_hint(hd_table[i]); if (translation == BIOS_ATA_TRANSLATION_AUTO) { bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors); if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { /* No translation. */ translation = 0; } else { /* LBA translation. */ translation = 1; } } else { translation--; } val |= translation << (i * 2); } } rtc_set_memory(s, 0x39, val); qemu_unregister_reset(pc_cmos_init_late, opaque); }
static void rtc_notify_cpu_added(Notifier *notifier, void *data) { RTCCPUHotplugArg *arg = container_of(notifier, RTCCPUHotplugArg, cpu_added_notifier); ISADevice *s = arg->rtc_state; /* increment the number of CPUs */ rtc_set_memory(s, 0x5f, rtc_get_memory(s, 0x5f) + 1); }
static void cmos_init_hd(ISADevice *s, int type_ofs, int info_ofs, int16_t cylinders, int8_t heads, int8_t sectors) { rtc_set_memory(s, type_ofs, 47); rtc_set_memory(s, info_ofs, cylinders); rtc_set_memory(s, info_ofs + 1, cylinders >> 8); rtc_set_memory(s, info_ofs + 2, heads); rtc_set_memory(s, info_ofs + 3, 0xff); rtc_set_memory(s, info_ofs + 4, 0xff); rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); rtc_set_memory(s, info_ofs + 6, cylinders); rtc_set_memory(s, info_ofs + 7, cylinders >> 8); rtc_set_memory(s, info_ofs + 8, sectors); }
static void pc_cmos_init_late(void *opaque) { pc_cmos_init_late_arg *arg = opaque; ISADevice *s = arg->rtc_state; int16_t cylinders; int8_t heads, sectors; int val; int i, trans; val = 0; if (ide_get_geometry(arg->idebus[0], 0, &cylinders, &heads, §ors) >= 0) { cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors); val |= 0xf0; } if (ide_get_geometry(arg->idebus[0], 1, &cylinders, &heads, §ors) >= 0) { cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors); val |= 0x0f; } rtc_set_memory(s, 0x12, val); val = 0; for (i = 0; i < 4; i++) { /* NOTE: ide_get_geometry() returns the physical geometry. It is always such that: 1 <= sects <= 63, 1 <= heads <= 16, 1 <= cylinders <= 16383. The BIOS geometry can be different if a translation is done. */ if (ide_get_geometry(arg->idebus[i / 2], i % 2, &cylinders, &heads, §ors) >= 0) { trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1; assert((trans & ~3) == 0); val |= trans << (i * 2); } } rtc_set_memory(s, 0x39, val); qemu_unregister_reset(pc_cmos_init_late, opaque); }
static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk) { #define PC_MAX_BOOT_DEVICES 3 int nbds, bds[3] = { 0, }; int i; nbds = strlen(boot_device); if (nbds > PC_MAX_BOOT_DEVICES) { error_report("Too many boot devices for PC"); return(1); } for (i = 0; i < nbds; i++) { bds[i] = boot_device2nibble(boot_device[i]); if (bds[i] == 0) { error_report("Invalid boot device for PC: '%c'", boot_device[i]); return(1); } } rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]); rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1)); return(0); }
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd, ISADevice *s) { int cylinders, heads, sectors; bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors); rtc_set_memory(s, type_ofs, 47); rtc_set_memory(s, info_ofs, cylinders); rtc_set_memory(s, info_ofs + 1, cylinders >> 8); rtc_set_memory(s, info_ofs + 2, heads); rtc_set_memory(s, info_ofs + 3, 0xff); rtc_set_memory(s, info_ofs + 4, 0xff); rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); rtc_set_memory(s, info_ofs + 6, cylinders); rtc_set_memory(s, info_ofs + 7, cylinders >> 8); rtc_set_memory(s, info_ofs + 8, sectors); }
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) BIOS will read it and start S3 resume at POST Entry */ static void rtc_notify_suspend(Notifier *notifier, void *data) { RTCState *s = container_of(notifier, RTCState, suspend_notifier); rtc_set_memory(ISA_DEVICE(s), 0xF, 0xFE); }
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, BusState *idebus0, BusState *idebus1, FDCtrl *floppy_controller, ISADevice *s) { int val; int fd0, fd1, nb; static pc_cmos_init_late_arg arg; /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ val = 640; /* base memory in K */ rtc_set_memory(s, 0x15, val); rtc_set_memory(s, 0x16, val >> 8); val = (ram_size / 1024) - 1024; if (val > 65535) val = 65535; rtc_set_memory(s, 0x17, val); rtc_set_memory(s, 0x18, val >> 8); rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); if (above_4g_mem_size) { rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16); rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24); rtc_set_memory(s, 0x5d, (uint64_t)above_4g_mem_size >> 32); } if (ram_size > (16 * 1024 * 1024)) val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); else val = 0; if (val > 65535) val = 65535; rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); /* set the number of CPU */ rtc_set_memory(s, 0x5f, smp_cpus - 1); /* set boot devices, and disable floppy signature check if requested */ if (set_boot_dev(s, boot_device, fd_bootchk)) { exit(1); } /* floppy type */ fd0 = fdctrl_get_drive_type(floppy_controller, 0); fd1 = fdctrl_get_drive_type(floppy_controller, 1); val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1); rtc_set_memory(s, 0x10, val); val = 0; nb = 0; if (fd0 < 3) nb++; if (fd1 < 3) nb++; switch (nb) { case 0: break; case 1: val |= 0x01; /* 1 drive, ready for boot */ break; case 2: val |= 0x41; /* 2 drives, ready for boot */ break; } val |= 0x02; /* FPU is there */ val |= 0x04; /* PS/2 mouse installed */ rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); /* hard drives */ arg.rtc_state = s; arg.idebus0 = idebus0; arg.idebus1 = idebus1; qemu_register_reset(pc_cmos_init_late, &arg); }
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, ISADevice *floppy, BusState *idebus0, BusState *idebus1, ISADevice *s) { int val, nb, i; FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE }; static pc_cmos_init_late_arg arg; static RTCCPUHotplugArg cpu_hotplug_cb; /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ /* base memory (first MiB) */ val = MIN(ram_size / 1024, 640); rtc_set_memory(s, 0x15, val); rtc_set_memory(s, 0x16, val >> 8); /* extememorynded memory (next 64MiB) */ if (ram_size > 1024 * 1024) { val = (ram_size - 1024 * 1024) / 1024; } else { val = 0; } if (val > 65535) val = 65535; rtc_set_memory(s, 0x17, val); rtc_set_memory(s, 0x18, val >> 8); rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); /* memory between 16MiB and 4GiB */ if (ram_size > 16 * 1024 * 1024) { val = (ram_size - 16 * 1024 * 1024) / 65536; } else { val = 0; } if (val > 65535) val = 65535; rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); /* memory above 4GiB */ val = above_4g_mem_size / 65536; rtc_set_memory(s, 0x5b, val); rtc_set_memory(s, 0x5c, val >> 8); rtc_set_memory(s, 0x5d, val >> 16); printf("qemu riscvpcat: CMOS- memory init successfully.\n"); /* set the number of CPU */ rtc_set_memory(s, 0x5f, smp_cpus - 1); /* init CPU hotplug notifier */ cpu_hotplug_cb.rtc_state = s; cpu_hotplug_cb.cpu_added_notifier.notify = rtc_notify_cpu_added; qemu_register_cpu_added_notifier(&cpu_hotplug_cb.cpu_added_notifier); printf("qemu riscvpcat: CMOS- cpu init successfully.\n"); //if (set_boot_dev(s, boot_device)) { // exit(1); //} //printf("qemu riscvpcat: CMOS- boot device init successfully.\n"); /* floppy type */ if (floppy) { for (i = 0; i < 2; i++) { // fd_type[i] = isa_fdc_get_drive_type(floppy, i); } } val = (cmos_get_fd_drive_type(fd_type[0]) << 4) | cmos_get_fd_drive_type(fd_type[1]); rtc_set_memory(s, 0x10, val); val = 0; nb = 0; if (fd_type[0] < FDRIVE_DRV_NONE) { nb++; } if (fd_type[1] < FDRIVE_DRV_NONE) { nb++; } switch (nb) { case 0: break; case 1: val |= 0x01; /* 1 drive, ready for boot */ break; case 2: val |= 0x41; /* 2 drives, ready for boot */ break; } val |= 0x02; /* FPU is there */ val |= 0x04; /* PS/2 mouse installed */ rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); printf("qemu riscvpcat: floppy init successfully.\n"); return; // // (AC) Below causes exception. check it later... // /* hard drives */ arg.rtc_state = s; arg.idebus[0] = idebus0; arg.idebus[1] = idebus1; qemu_register_reset(pc_cmos_init_late, &arg); printf("qemu riscvpcat: CMOS- hard drives init successfully.\n"); }
void xbox_init_common(MachineState *machine, const uint8_t *eeprom, PCIBus **pci_bus_out, ISABus **isa_bus_out) { PCMachineState *pcms = PC_MACHINE(machine); // PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); MemoryRegion *system_memory = get_system_memory(); // MemoryRegion *system_io = get_system_io(); int i; PCIBus *pci_bus; ISABus *isa_bus; qemu_irq *i8259; // qemu_irq smi_irq; // XBOX_TODO: SMM support? GSIState *gsi_state; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; BusState *idebus[MAX_IDE_BUS]; ISADevice *rtc_state; // ISADevice *pit; MemoryRegion *ram_memory; MemoryRegion *pci_memory; MemoryRegion *rom_memory; I2CBus *smbus; PCIBus *agp_bus; pc_cpus_init(pcms); pci_memory = g_new(MemoryRegion, 1); memory_region_init(pci_memory, NULL, "pci", UINT64_MAX); rom_memory = pci_memory; // pc_guest_info_init(pcms); /* allocate ram and load rom/bios */ xbox_memory_init(pcms, system_memory, rom_memory, &ram_memory); gsi_state = g_malloc0(sizeof(*gsi_state)); pcms->gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); xbox_pci_init(pcms->gsi, get_system_memory(), get_system_io(), pci_memory, ram_memory, &pci_bus, &isa_bus, &smbus, &agp_bus); pcms->bus = pci_bus; isa_bus_irqs(isa_bus, pcms->gsi); i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq()); for (i = 0; i < ISA_NUM_IRQS; i++) { gsi_state->i8259_irq[i] = i8259[i]; } g_free(i8259); pc_register_ferr_irq(pcms->gsi[13]); /* init basic PC hardware */ pcms->pit = 1; // XBOX_FIXME: What's the right way to do this? rtc_state = mc146818_rtc_init(isa_bus, 2000, NULL); // qemu_register_boot_set(pc_boot_set, rtc_state); ISADevice *pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); pcspk_init(isa_bus, pit); ide_drive_get(hd, ARRAY_SIZE(hd)); PCIDevice *ide_dev = pci_piix3_ide_init(pci_bus, hd, PCI_DEVFN(9, 0)); idebus[0] = qdev_get_child_bus(&ide_dev->qdev, "ide.0"); idebus[1] = qdev_get_child_bus(&ide_dev->qdev, "ide.1"); // xbox bios wants this bit pattern set to mark the data as valid uint8_t bits = 0x55; for (i = 0x10; i < 0x70; i++) { rtc_set_memory(rtc_state, i, bits); bits = ~bits; } bits = 0x55; for (i = 0x80; i < 0x100; i++) { rtc_set_memory(rtc_state, i, bits); bits = ~bits; } /* smbus devices */ uint8_t *eeprom_buf = g_malloc0(256); memcpy(eeprom_buf, eeprom, 256); smbus_eeprom_init_one(smbus, 0x54, eeprom_buf); smbus_xbox_smc_init(smbus, 0x10); smbus_cx25871_init(smbus, 0x45); smbus_adm1032_init(smbus, 0x4c); /* USB */ PCIDevice *usb1 = pci_create(pci_bus, PCI_DEVFN(3, 0), "pci-ohci"); qdev_prop_set_uint32(&usb1->qdev, "num-ports", 4); qdev_init_nofail(&usb1->qdev); PCIDevice *usb0 = pci_create(pci_bus, PCI_DEVFN(2, 0), "pci-ohci"); qdev_prop_set_uint32(&usb0->qdev, "num-ports", 4); qdev_init_nofail(&usb0->qdev); /* Ethernet! */ PCIDevice *nvnet = pci_create(pci_bus, PCI_DEVFN(4, 0), "nvnet"); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; qemu_check_nic_model(nd, "nvnet"); qdev_set_nic_properties(&nvnet->qdev, nd); qdev_init_nofail(&nvnet->qdev); } /* APU! */ mcpx_apu_init(pci_bus, PCI_DEVFN(5, 0), ram_memory); /* ACI! */ pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "mcpx-aci"); /* GPU! */ nv2a_init(agp_bus, PCI_DEVFN(0, 0), ram_memory); if (pci_bus_out) { *pci_bus_out = pci_bus; } if (isa_bus_out) { *isa_bus_out = isa_bus; } }