* [Qemu-devel] [PATCH 1/2] PPC: Mac: Move tbfreq into local variable @ 2014-07-13 20:36 Alexander Graf 2014-07-13 20:36 ` [Qemu-devel] [PATCH 2/2] PPC: Cuda: Use cuda timer to expose tbfreq to guest Alexander Graf 0 siblings, 1 reply; 4+ messages in thread From: Alexander Graf @ 2014-07-13 20:36 UTC (permalink / raw) To: qemu-ppc; +Cc: programmingkidx, mark.cave-ayland, qemu-devel We already expose the real CPU's tb frequency to the guest via fw_cfg. Soon we will need to also expose it to the MacIO, so let's move it to a variable that we can leverage every time we need the frequency. Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/ppc/mac_newworld.c | 13 ++++++++++--- hw/ppc/mac_oldworld.c | 12 +++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 32ee2f2..419d2b4 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -177,6 +177,7 @@ static void ppc_core99_init(MachineState *machine) DeviceState *dev; int *token = g_new(int, 1); hwaddr nvram_addr = 0xFFF04000; + uint64_t tbfreq; linux_boot = (kernel_filename != NULL); @@ -373,6 +374,14 @@ static void ppc_core99_init(MachineState *machine) pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io()); machine_arch = ARCH_MAC99; } + + /* Timebase Frequency */ + if (kvm_enabled()) { + tbfreq = kvmppc_get_tbfreq(); + } else { + tbfreq = TBFREQ; + } + /* init basic PC hardware */ escc_mem = escc_init(0, pic[0x25], pic[0x24], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); @@ -469,15 +478,13 @@ static void ppc_core99_init(MachineState *machine) #ifdef CONFIG_KVM uint8_t *hypercall; - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); hypercall = g_malloc(16); kvmppc_get_hypercall(env, hypercall, 16); fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); #endif - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ); } + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq); /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 4b5e905..8a6cec9 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -103,6 +103,7 @@ static void ppc_heathrow_init(MachineState *machine) uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; + uint64_t tbfreq; linux_boot = (kernel_filename != NULL); @@ -249,6 +250,13 @@ static void ppc_heathrow_init(MachineState *machine) } } + /* Timebase Frequency */ + if (kvm_enabled()) { + tbfreq = kvmppc_get_tbfreq(); + } else { + tbfreq = TBFREQ; + } + /* init basic PC hardware */ if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { hw_error("Only 6xx bus is supported on heathrow machine\n"); @@ -329,15 +337,13 @@ static void ppc_heathrow_init(MachineState *machine) #ifdef CONFIG_KVM uint8_t *hypercall; - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); hypercall = g_malloc(16); kvmppc_get_hypercall(env, hypercall, 16); fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); #endif - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ); } + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq); /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ); -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 2/2] PPC: Cuda: Use cuda timer to expose tbfreq to guest 2014-07-13 20:36 [Qemu-devel] [PATCH 1/2] PPC: Mac: Move tbfreq into local variable Alexander Graf @ 2014-07-13 20:36 ` Alexander Graf 2014-07-14 14:04 ` Mark Cave-Ayland 0 siblings, 1 reply; 4+ messages in thread From: Alexander Graf @ 2014-07-13 20:36 UTC (permalink / raw) To: qemu-ppc; +Cc: programmingkidx, mark.cave-ayland, qemu-devel Mac OS X calibrates a number of frequencies on bootup based on reading tb values on bootup and comparing them to via cuda timer values. The only variable we can really steer well (thanks to KVM) is the cuda frequency. So let's use that one to fake Mac OS X into believing the bus frequency is tbfreq * 4. That way Mac OS X will automatically calculate the correct timebase frequency. With this patch and the patch set I posted earlier I can successfully run Mac OS X 10.2, 10.3 and 10.4 guests with -M mac99 on TCG and KVM. Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Alexander Graf <agraf@suse.de> --- hw/misc/macio/cuda.c | 28 ++++++++++++++++++++++------ hw/misc/macio/macio.c | 10 ++++++++++ hw/ppc/mac.h | 2 ++ hw/ppc/mac_newworld.c | 1 + hw/ppc/mac_oldworld.c | 1 + 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index ff6051d..81e54b8 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -102,7 +102,6 @@ #define CUDA_TIMER_TICKLE 0x24 #define CUDA_COMBINED_FORMAT_IIC 0x25 -#define CUDA_TIMER_FREQ (4700000 / 6) #define CUDA_ADB_POLL_FREQ 50 /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ @@ -123,13 +122,22 @@ static void cuda_update_irq(CUDAState *s) } } +static uint64_t get_tb(uint64_t freq) +{ + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), + freq, get_ticks_per_sec()); +} + static unsigned int get_counter(CUDATimer *s) { int64_t d; unsigned int counter; + uint64_t tb_diff; + + /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup. */ + tb_diff = get_tb(s->frequency) - s->load_time; + d = (tb_diff * 0xBF401675E5DULL) / (s->frequency << 24); - d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->load_time, - CUDA_TIMER_FREQ, get_ticks_per_sec()); if (s->index == 0) { /* the timer goes down from latch to -1 (period of latch + 2) */ if (d <= (s->counter_value + 1)) { @@ -147,7 +155,7 @@ static unsigned int get_counter(CUDATimer *s) static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val); - ti->load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ti->load_time = get_tb(s->frequency); ti->counter_value = val; cuda_timer_update(s, ti, ti->load_time); } @@ -159,7 +167,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) /* current counter value */ d = muldiv64(current_time - s->load_time, - CUDA_TIMER_FREQ, get_ticks_per_sec()); + s->frequency, get_ticks_per_sec()); /* the timer goes down from latch to -1 (period of latch + 2) */ if (d <= (s->counter_value + 1)) { counter = (s->counter_value - d) & 0xffff; @@ -178,7 +186,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) } CUDA_DPRINTF("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", s->latch, d, next_time - d); - next_time = muldiv64(next_time, get_ticks_per_sec(), CUDA_TIMER_FREQ) + + next_time = muldiv64(next_time, get_ticks_per_sec(), s->frequency) + s->load_time; if (next_time <= current_time) next_time = current_time + 1; @@ -688,6 +696,8 @@ static void cuda_realizefn(DeviceState *dev, Error **errp) struct tm tm; s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s); + s->timers[0].frequency = s->frequency; + s->timers[1].frequency = s->frequency; qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; @@ -713,6 +723,11 @@ static void cuda_initfn(Object *obj) DEVICE(obj), "adb.0"); } +static Property cuda_properties[] = { + DEFINE_PROP_UINT64("frequency", CUDAState, frequency, 0), + DEFINE_PROP_END_OF_LIST() +}; + static void cuda_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -720,6 +735,7 @@ static void cuda_class_init(ObjectClass *oc, void *data) dc->realize = cuda_realizefn; dc->reset = cuda_reset; dc->vmsd = &vmstate_cuda; + dc->props = cuda_properties; } static const TypeInfo cuda_type_info = { diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 35eaa00..e0f1e88 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -42,6 +42,7 @@ typedef struct MacIOState void *dbdma; MemoryRegion *pic_mem; MemoryRegion *escc_mem; + uint64_t frequency; } MacIOState; #define OLDWORLD_MACIO(obj) \ @@ -351,12 +352,19 @@ static void macio_newworld_class_init(ObjectClass *oc, void *data) pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL; } +static Property macio_properties[] = { + DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0), + DEFINE_PROP_END_OF_LIST() +}; + static void macio_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->vendor_id = PCI_VENDOR_ID_APPLE; k->class_id = PCI_CLASS_OTHERS << 8; + dc->props = macio_properties; } static const TypeInfo macio_oldworld_type_info = { @@ -403,6 +411,8 @@ void macio_init(PCIDevice *d, macio_state->escc_mem = escc_mem; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ + qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "frequency", + macio_state->frequency); qdev_init_nofail(DEVICE(d)); } diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 23536f4..aff2b9a 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -57,6 +57,7 @@ typedef struct CUDATimer { uint16_t counter_value; int64_t load_time; int64_t next_irq_time; + uint64_t frequency; QEMUTimer *timer; } CUDATimer; @@ -97,6 +98,7 @@ typedef struct CUDAState { CUDATimer timers[2]; uint32_t tick_offset; + uint64_t frequency; uint8_t last_b; uint8_t last_acr; diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 419d2b4..1eac3db 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -395,6 +395,7 @@ static void ppc_core99_init(MachineState *machine) qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */ + qdev_prop_set_uint64(dev, "frequency", tbfreq); macio_init(macio, pic_mem, escc_bar); /* We only emulate 2 out of 3 IDE controllers for now */ diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 8a6cec9..2e1bdc5 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -285,6 +285,7 @@ static void ppc_heathrow_init(MachineState *machine) qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */ qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */ qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */ + qdev_prop_set_uint64(dev, "frequency", tbfreq); macio_init(macio, pic_mem, escc_bar); macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 2/2] PPC: Cuda: Use cuda timer to expose tbfreq to guest 2014-07-13 20:36 ` [Qemu-devel] [PATCH 2/2] PPC: Cuda: Use cuda timer to expose tbfreq to guest Alexander Graf @ 2014-07-14 14:04 ` Mark Cave-Ayland 2014-07-14 17:21 ` Alexander Graf 0 siblings, 1 reply; 4+ messages in thread From: Mark Cave-Ayland @ 2014-07-14 14:04 UTC (permalink / raw) To: Alexander Graf, qemu-ppc; +Cc: programmingkidx, qemu-devel On 13/07/14 21:36, Alexander Graf wrote: > Mac OS X calibrates a number of frequencies on bootup based on reading > tb values on bootup and comparing them to via cuda timer values. > > The only variable we can really steer well (thanks to KVM) is the cuda > frequency. So let's use that one to fake Mac OS X into believing the > bus frequency is tbfreq * 4. That way Mac OS X will automatically > calculate the correct timebase frequency. > > With this patch and the patch set I posted earlier I can successfully > run Mac OS X 10.2, 10.3 and 10.4 guests with -M mac99 on TCG and KVM. Fantastic! I thought you mentioned before that there was a problem with the way in which OS X used the MMU which meant it wouldn't be possible to run under KVM but I guess that has been fixed now? Also do any of these changes help any of the *BSDs to boot further? ATB, Mark. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 2/2] PPC: Cuda: Use cuda timer to expose tbfreq to guest 2014-07-14 14:04 ` Mark Cave-Ayland @ 2014-07-14 17:21 ` Alexander Graf 0 siblings, 0 replies; 4+ messages in thread From: Alexander Graf @ 2014-07-14 17:21 UTC (permalink / raw) To: Mark Cave-Ayland, qemu-ppc; +Cc: programmingkidx, qemu-devel On 14.07.14 16:04, Mark Cave-Ayland wrote: > On 13/07/14 21:36, Alexander Graf wrote: > >> Mac OS X calibrates a number of frequencies on bootup based on reading >> tb values on bootup and comparing them to via cuda timer values. >> >> The only variable we can really steer well (thanks to KVM) is the cuda >> frequency. So let's use that one to fake Mac OS X into believing the >> bus frequency is tbfreq * 4. That way Mac OS X will automatically >> calculate the correct timebase frequency. >> >> With this patch and the patch set I posted earlier I can successfully >> run Mac OS X 10.2, 10.3 and 10.4 guests with -M mac99 on TCG and KVM. > > Fantastic! I thought you mentioned before that there was a problem > with the way in which OS X used the MMU which meant it wouldn't be > possible to run under KVM but I guess that has been fixed now? Yes, a patch for that is on the KVM mailing list. I just relocate the instruction pointer "somewhere safe" when in split real mode. Very crude hack, but it works astonishingly well. > Also do any of these changes help any of the *BSDs to boot further? I don't know :). I've never tried to boot *BSD on PPC, so I have no idea where that's broken. Alex ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2014-07-14 17:22 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-07-13 20:36 [Qemu-devel] [PATCH 1/2] PPC: Mac: Move tbfreq into local variable Alexander Graf 2014-07-13 20:36 ` [Qemu-devel] [PATCH 2/2] PPC: Cuda: Use cuda timer to expose tbfreq to guest Alexander Graf 2014-07-14 14:04 ` Mark Cave-Ayland 2014-07-14 17:21 ` Alexander Graf
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).