PPC: Cuda: Use cuda timer to expose tbfreq to guest
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>
This commit is contained in:
parent
caae6c9611
commit
b981289c49
@ -123,13 +123,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)
|
static unsigned int get_counter(CUDATimer *s)
|
||||||
{
|
{
|
||||||
int64_t d;
|
int64_t d;
|
||||||
unsigned int counter;
|
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) {
|
if (s->index == 0) {
|
||||||
/* the timer goes down from latch to -1 (period of latch + 2) */
|
/* the timer goes down from latch to -1 (period of latch + 2) */
|
||||||
if (d <= (s->counter_value + 1)) {
|
if (d <= (s->counter_value + 1)) {
|
||||||
@ -147,7 +156,7 @@ static unsigned int get_counter(CUDATimer *s)
|
|||||||
static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
|
static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
|
||||||
{
|
{
|
||||||
CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), 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;
|
ti->counter_value = val;
|
||||||
cuda_timer_update(s, ti, ti->load_time);
|
cuda_timer_update(s, ti, ti->load_time);
|
||||||
}
|
}
|
||||||
@ -688,6 +697,8 @@ static void cuda_realizefn(DeviceState *dev, Error **errp)
|
|||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s);
|
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);
|
qemu_get_timedate(&tm, 0);
|
||||||
s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
|
s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
|
||||||
@ -713,6 +724,11 @@ static void cuda_initfn(Object *obj)
|
|||||||
DEVICE(obj), "adb.0");
|
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)
|
static void cuda_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
@ -720,6 +736,7 @@ static void cuda_class_init(ObjectClass *oc, void *data)
|
|||||||
dc->realize = cuda_realizefn;
|
dc->realize = cuda_realizefn;
|
||||||
dc->reset = cuda_reset;
|
dc->reset = cuda_reset;
|
||||||
dc->vmsd = &vmstate_cuda;
|
dc->vmsd = &vmstate_cuda;
|
||||||
|
dc->props = cuda_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo cuda_type_info = {
|
static const TypeInfo cuda_type_info = {
|
||||||
|
@ -42,6 +42,7 @@ typedef struct MacIOState
|
|||||||
void *dbdma;
|
void *dbdma;
|
||||||
MemoryRegion *pic_mem;
|
MemoryRegion *pic_mem;
|
||||||
MemoryRegion *escc_mem;
|
MemoryRegion *escc_mem;
|
||||||
|
uint64_t frequency;
|
||||||
} MacIOState;
|
} MacIOState;
|
||||||
|
|
||||||
#define OLDWORLD_MACIO(obj) \
|
#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;
|
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)
|
static void macio_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->vendor_id = PCI_VENDOR_ID_APPLE;
|
k->vendor_id = PCI_VENDOR_ID_APPLE;
|
||||||
k->class_id = PCI_CLASS_OTHERS << 8;
|
k->class_id = PCI_CLASS_OTHERS << 8;
|
||||||
|
dc->props = macio_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo macio_oldworld_type_info = {
|
static const TypeInfo macio_oldworld_type_info = {
|
||||||
@ -403,6 +411,8 @@ void macio_init(PCIDevice *d,
|
|||||||
macio_state->escc_mem = escc_mem;
|
macio_state->escc_mem = escc_mem;
|
||||||
/* Note: this code is strongly inspirated from the corresponding code
|
/* Note: this code is strongly inspirated from the corresponding code
|
||||||
in PearPC */
|
in PearPC */
|
||||||
|
qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "frequency",
|
||||||
|
macio_state->frequency);
|
||||||
|
|
||||||
qdev_init_nofail(DEVICE(d));
|
qdev_init_nofail(DEVICE(d));
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ typedef struct CUDATimer {
|
|||||||
uint16_t counter_value;
|
uint16_t counter_value;
|
||||||
int64_t load_time;
|
int64_t load_time;
|
||||||
int64_t next_irq_time;
|
int64_t next_irq_time;
|
||||||
|
uint64_t frequency;
|
||||||
QEMUTimer *timer;
|
QEMUTimer *timer;
|
||||||
} CUDATimer;
|
} CUDATimer;
|
||||||
|
|
||||||
@ -97,6 +98,7 @@ typedef struct CUDAState {
|
|||||||
CUDATimer timers[2];
|
CUDATimer timers[2];
|
||||||
|
|
||||||
uint32_t tick_offset;
|
uint32_t tick_offset;
|
||||||
|
uint64_t frequency;
|
||||||
|
|
||||||
uint8_t last_b;
|
uint8_t last_b;
|
||||||
uint8_t last_acr;
|
uint8_t last_acr;
|
||||||
|
@ -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, 2, pic[0x02]); /* IDE DMA */
|
||||||
qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */
|
qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */
|
||||||
qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */
|
qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */
|
||||||
|
qdev_prop_set_uint64(dev, "frequency", tbfreq);
|
||||||
macio_init(macio, pic_mem, escc_bar);
|
macio_init(macio, pic_mem, escc_bar);
|
||||||
|
|
||||||
/* We only emulate 2 out of 3 IDE controllers for now */
|
/* We only emulate 2 out of 3 IDE controllers for now */
|
||||||
|
@ -286,6 +286,7 @@ static void ppc_heathrow_init(MachineState *machine)
|
|||||||
qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */
|
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, 3, pic[0x0E]); /* IDE-1 */
|
||||||
qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */
|
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_init(macio, pic_mem, escc_bar);
|
||||||
|
|
||||||
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
|
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
|
||||||
|
Loading…
Reference in New Issue
Block a user