diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/9p.h | 2 | ||||
-rw-r--r-- | hw/eepro100.c | 1 | ||||
-rw-r--r-- | hw/hpet.c | 580 | ||||
-rw-r--r-- | hw/hpet_emul.h | 46 | ||||
-rw-r--r-- | hw/hw.h | 11 | ||||
-rw-r--r-- | hw/mc146818rtc.c | 49 | ||||
-rw-r--r-- | hw/mc146818rtc.h | 4 | ||||
-rw-r--r-- | hw/mips_jazz.c | 2 | ||||
-rw-r--r-- | hw/mips_malta.c | 2 | ||||
-rw-r--r-- | hw/mips_r4k.c | 2 | ||||
-rw-r--r-- | hw/pc.c | 15 | ||||
-rw-r--r-- | hw/ppc_prep.c | 2 | ||||
-rw-r--r-- | hw/usb-ohci.c | 4 | ||||
-rw-r--r-- | hw/virtio-serial.h | 1 | ||||
-rw-r--r-- | hw/xenfb.c | 1 |
15 files changed, 418 insertions, 304 deletions
@@ -14,8 +14,6 @@ #ifndef QEMU_9P_H #define QEMU_9P_H -#include <stdbool.h> - typedef struct V9fsConf { /* tag name for the device */ diff --git a/hw/eepro100.c b/hw/eepro100.c index a74d834811..97afa2cd9f 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -41,7 +41,6 @@ * * Wake-on-LAN is not implemented. */ -#include <stdbool.h> /* bool */ #include <stddef.h> /* offsetof */ #include "hw.h" #include "pci.h" @@ -29,6 +29,8 @@ #include "console.h" #include "qemu-timer.h" #include "hpet_emul.h" +#include "sysbus.h" +#include "mc146818rtc.h" //#define HPET_DEBUG #ifdef HPET_DEBUG @@ -37,26 +39,58 @@ #define DPRINTF(...) #endif -static HPETState *hpet_statep; - -uint32_t hpet_in_legacy_mode(void) +#define HPET_MSI_SUPPORT 0 + +struct HPETState; +typedef struct HPETTimer { /* timers */ + uint8_t tn; /*timer number*/ + QEMUTimer *qemu_timer; + struct HPETState *state; + /* Memory-mapped, software visible timer registers */ + uint64_t config; /* configuration/cap */ + uint64_t cmp; /* comparator */ + uint64_t fsb; /* FSB route */ + /* Hidden register state */ + uint64_t period; /* Last value written to comparator */ + uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit + * mode. Next pop will be actual timer expiration. + */ +} HPETTimer; + +typedef struct HPETState { + SysBusDevice busdev; + uint64_t hpet_offset; + qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; + uint32_t flags; + uint8_t rtc_irq_level; + uint8_t num_timers; + HPETTimer timer[HPET_MAX_TIMERS]; + + /* Memory-mapped, software visible registers */ + uint64_t capability; /* capabilities */ + uint64_t config; /* configuration */ + uint64_t isr; /* interrupt status reg */ + uint64_t hpet_counter; /* main counter */ +} HPETState; + +static uint32_t hpet_in_legacy_mode(HPETState *s) { - if (hpet_statep) - return hpet_statep->config & HPET_CFG_LEGACY; - else - return 0; + return s->config & HPET_CFG_LEGACY; } static uint32_t timer_int_route(struct HPETTimer *timer) { - uint32_t route; - route = (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT; - return route; + return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT; } -static uint32_t hpet_enabled(void) +static uint32_t timer_fsb_route(HPETTimer *t) { - return hpet_statep->config & HPET_CFG_ENABLE; + return t->config & HPET_TN_FSB_ENABLE; +} + +static uint32_t hpet_enabled(HPETState *s) +{ + return s->config & HPET_CFG_ENABLE; } static uint32_t timer_is_periodic(HPETTimer *t) @@ -106,11 +140,9 @@ static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask) return ((old & mask) && !(new & mask)); } -static uint64_t hpet_get_ticks(void) +static uint64_t hpet_get_ticks(HPETState *s) { - uint64_t ticks; - ticks = ns_to_ticks(qemu_get_clock(vm_clock) + hpet_statep->hpet_offset); - return ticks; + return ns_to_ticks(qemu_get_clock(vm_clock) + s->hpet_offset); } /* @@ -121,12 +153,14 @@ static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current) if (t->config & HPET_TN_32BIT) { uint32_t diff, cmp; + cmp = (uint32_t)t->cmp; diff = cmp - (uint32_t)current; diff = (int32_t)diff > 0 ? diff : (uint32_t)0; return (uint64_t)diff; } else { uint64_t diff, cmp; + cmp = t->cmp; diff = cmp - current; diff = (int64_t)diff > 0 ? diff : (uint64_t)0; @@ -134,34 +168,54 @@ static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current) } } -static void update_irq(struct HPETTimer *timer) +static void update_irq(struct HPETTimer *timer, int set) { - qemu_irq irq; + uint64_t mask; + HPETState *s; int route; - if (timer->tn <= 1 && hpet_in_legacy_mode()) { + if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) { /* if LegacyReplacementRoute bit is set, HPET specification requires * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC, * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */ - if (timer->tn == 0) { - irq=timer->state->irqs[0]; - } else - irq=timer->state->irqs[8]; + route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ; } else { - route=timer_int_route(timer); - irq=timer->state->irqs[route]; + route = timer_int_route(timer); } - if (timer_enabled(timer) && hpet_enabled()) { - qemu_irq_pulse(irq); + s = timer->state; + mask = 1 << timer->tn; + if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) { + s->isr &= ~mask; + if (!timer_fsb_route(timer)) { + qemu_irq_lower(s->irqs[route]); + } + } else if (timer_fsb_route(timer)) { + stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff); + } else if (timer->config & HPET_TN_TYPE_LEVEL) { + s->isr |= mask; + qemu_irq_raise(s->irqs[route]); + } else { + s->isr &= ~mask; + qemu_irq_pulse(s->irqs[route]); } } static void hpet_pre_save(void *opaque) { HPETState *s = opaque; + /* save current counter value */ - s->hpet_counter = hpet_get_ticks(); + s->hpet_counter = hpet_get_ticks(s); +} + +static int hpet_pre_load(void *opaque) +{ + HPETState *s = opaque; + + /* version 1 only supports 3, later versions will load the actual value */ + s->num_timers = HPET_MIN_TIMERS; + return 0; } static int hpet_post_load(void *opaque, int version_id) @@ -170,6 +224,16 @@ static int hpet_post_load(void *opaque, int version_id) /* Recalculate the offset between the main counter and guest time */ s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock); + + /* Push number of timers into capability returned via HPET_ID */ + s->capability &= ~HPET_ID_NUM_TIM_MASK; + s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; + + /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */ + s->flags &= ~(1 << HPET_MSI_SUPPORT); + if (s->timer[0].config & HPET_TN_FSB_CAP) { + s->flags |= 1 << HPET_MSI_SUPPORT; + } return 0; } @@ -192,17 +256,19 @@ static const VMStateDescription vmstate_hpet_timer = { static const VMStateDescription vmstate_hpet = { .name = "hpet", - .version_id = 1, + .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, .pre_save = hpet_pre_save, + .pre_load = hpet_pre_load, .post_load = hpet_post_load, .fields = (VMStateField []) { VMSTATE_UINT64(config, HPETState), VMSTATE_UINT64(isr, HPETState), VMSTATE_UINT64(hpet_counter, HPETState), - VMSTATE_STRUCT_ARRAY(timer, HPETState, HPET_NUM_TIMERS, 0, - vmstate_hpet_timer, HPETTimer), + VMSTATE_UINT8_V(num_timers, HPETState, 2), + VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0, + vmstate_hpet_timer, HPETTimer), VMSTATE_END_OF_LIST() } }; @@ -212,39 +278,41 @@ static const VMStateDescription vmstate_hpet = { */ static void hpet_timer(void *opaque) { - HPETTimer *t = (HPETTimer*)opaque; + HPETTimer *t = opaque; uint64_t diff; uint64_t period = t->period; - uint64_t cur_tick = hpet_get_ticks(); + uint64_t cur_tick = hpet_get_ticks(t->state); if (timer_is_periodic(t) && period != 0) { if (t->config & HPET_TN_32BIT) { - while (hpet_time_after(cur_tick, t->cmp)) + while (hpet_time_after(cur_tick, t->cmp)) { t->cmp = (uint32_t)(t->cmp + t->period); - } else - while (hpet_time_after64(cur_tick, t->cmp)) + } + } else { + while (hpet_time_after64(cur_tick, t->cmp)) { t->cmp += period; - + } + } diff = hpet_calculate_diff(t, cur_tick); - qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) - + (int64_t)ticks_to_ns(diff)); + qemu_mod_timer(t->qemu_timer, + qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff)); } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { if (t->wrap_flag) { diff = hpet_calculate_diff(t, cur_tick); - qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) - + (int64_t)ticks_to_ns(diff)); + qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) + + (int64_t)ticks_to_ns(diff)); t->wrap_flag = 0; } } - update_irq(t); + update_irq(t, 1); } static void hpet_set_timer(HPETTimer *t) { uint64_t diff; uint32_t wrap_diff; /* how many ticks until we wrap? */ - uint64_t cur_tick = hpet_get_ticks(); + uint64_t cur_tick = hpet_get_ticks(t->state); /* whenever new timer is being set up, make sure wrap_flag is 0 */ t->wrap_flag = 0; @@ -260,13 +328,14 @@ static void hpet_set_timer(HPETTimer *t) t->wrap_flag = 1; } } - qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) - + (int64_t)ticks_to_ns(diff)); + qemu_mod_timer(t->qemu_timer, + qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff)); } static void hpet_del_timer(HPETTimer *t) { qemu_del_timer(t->qemu_timer); + update_irq(t, 0); } #ifdef HPET_DEBUG @@ -285,7 +354,7 @@ static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr) static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr) { - HPETState *s = (HPETState *)opaque; + HPETState *s = opaque; uint64_t cur_tick, index; DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr); @@ -293,57 +362,62 @@ static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr) /*address range of all TN regs*/ if (index >= 0x100 && index <= 0x3ff) { uint8_t timer_id = (addr - 0x100) / 0x20; - if (timer_id > HPET_NUM_TIMERS - 1) { - printf("qemu: timer id out of range\n"); + HPETTimer *timer = &s->timer[timer_id]; + + if (timer_id > s->num_timers) { + DPRINTF("qemu: timer id out of range\n"); return 0; } - HPETTimer *timer = &s->timer[timer_id]; switch ((addr - 0x100) % 0x20) { - case HPET_TN_CFG: - return timer->config; - case HPET_TN_CFG + 4: // Interrupt capabilities - return timer->config >> 32; - case HPET_TN_CMP: // comparator register - return timer->cmp; - case HPET_TN_CMP + 4: - return timer->cmp >> 32; - case HPET_TN_ROUTE: - return timer->fsb >> 32; - default: - DPRINTF("qemu: invalid hpet_ram_readl\n"); - break; + case HPET_TN_CFG: + return timer->config; + case HPET_TN_CFG + 4: // Interrupt capabilities + return timer->config >> 32; + case HPET_TN_CMP: // comparator register + return timer->cmp; + case HPET_TN_CMP + 4: + return timer->cmp >> 32; + case HPET_TN_ROUTE: + return timer->fsb; + case HPET_TN_ROUTE + 4: + return timer->fsb >> 32; + default: + DPRINTF("qemu: invalid hpet_ram_readl\n"); + break; } } else { switch (index) { - case HPET_ID: - return s->capability; - case HPET_PERIOD: - return s->capability >> 32; - case HPET_CFG: - return s->config; - case HPET_CFG + 4: - DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n"); - return 0; - case HPET_COUNTER: - if (hpet_enabled()) - cur_tick = hpet_get_ticks(); - else - cur_tick = s->hpet_counter; - DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick); - return cur_tick; - case HPET_COUNTER + 4: - if (hpet_enabled()) - cur_tick = hpet_get_ticks(); - else - cur_tick = s->hpet_counter; - DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick); - return cur_tick >> 32; - case HPET_STATUS: - return s->isr; - default: - DPRINTF("qemu: invalid hpet_ram_readl\n"); - break; + case HPET_ID: + return s->capability; + case HPET_PERIOD: + return s->capability >> 32; + case HPET_CFG: + return s->config; + case HPET_CFG + 4: + DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n"); + return 0; + case HPET_COUNTER: + if (hpet_enabled(s)) { + cur_tick = hpet_get_ticks(s); + } else { + cur_tick = s->hpet_counter; + } + DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick); + return cur_tick; + case HPET_COUNTER + 4: + if (hpet_enabled(s)) { + cur_tick = hpet_get_ticks(s); + } else { + cur_tick = s->hpet_counter; + } + DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick); + return cur_tick >> 32; + case HPET_STATUS: + return s->isr; + default: + DPRINTF("qemu: invalid hpet_ram_readl\n"); + break; } } return 0; @@ -369,7 +443,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t value) { int i; - HPETState *s = (HPETState *)opaque; + HPETState *s = opaque; uint64_t old_val, new_val, val, index; DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value); @@ -380,129 +454,151 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, /*address range of all TN regs*/ if (index >= 0x100 && index <= 0x3ff) { uint8_t timer_id = (addr - 0x100) / 0x20; - DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id); HPETTimer *timer = &s->timer[timer_id]; + DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id); + if (timer_id > s->num_timers) { + DPRINTF("qemu: timer id out of range\n"); + return; + } switch ((addr - 0x100) % 0x20) { - case HPET_TN_CFG: - DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n"); - val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); - timer->config = (timer->config & 0xffffffff00000000ULL) | val; - if (new_val & HPET_TN_32BIT) { - timer->cmp = (uint32_t)timer->cmp; - timer->period = (uint32_t)timer->period; - } - if (new_val & HPET_TIMER_TYPE_LEVEL) { - printf("qemu: level-triggered hpet not supported\n"); - exit (-1); - } - - break; - case HPET_TN_CFG + 4: // Interrupt capabilities - DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n"); - break; - case HPET_TN_CMP: // comparator register - DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n"); - if (timer->config & HPET_TN_32BIT) - new_val = (uint32_t)new_val; - if (!timer_is_periodic(timer) || - (timer->config & HPET_TN_SETVAL)) - timer->cmp = (timer->cmp & 0xffffffff00000000ULL) - | new_val; - if (timer_is_periodic(timer)) { - /* - * FIXME: Clamp period to reasonable min value? - * Clamp period to reasonable max value - */ - new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; - timer->period = (timer->period & 0xffffffff00000000ULL) - | new_val; + case HPET_TN_CFG: + DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n"); + if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) { + update_irq(timer, 0); + } + val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); + timer->config = (timer->config & 0xffffffff00000000ULL) | val; + if (new_val & HPET_TN_32BIT) { + timer->cmp = (uint32_t)timer->cmp; + timer->period = (uint32_t)timer->period; + } + if (activating_bit(old_val, new_val, HPET_TN_ENABLE)) { + hpet_set_timer(timer); + } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) { + hpet_del_timer(timer); + } + break; + case HPET_TN_CFG + 4: // Interrupt capabilities + DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n"); + break; + case HPET_TN_CMP: // comparator register + DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n"); + if (timer->config & HPET_TN_32BIT) { + new_val = (uint32_t)new_val; + } + if (!timer_is_periodic(timer) + || (timer->config & HPET_TN_SETVAL)) { + timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val; + } + if (timer_is_periodic(timer)) { + /* + * FIXME: Clamp period to reasonable min value? + * Clamp period to reasonable max value + */ + new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; + timer->period = + (timer->period & 0xffffffff00000000ULL) | new_val; + } + timer->config &= ~HPET_TN_SETVAL; + if (hpet_enabled(s)) { + hpet_set_timer(timer); + } + break; + case HPET_TN_CMP + 4: // comparator register high order + DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n"); + if (!timer_is_periodic(timer) + || (timer->config & HPET_TN_SETVAL)) { + timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32; + } else { + /* + * FIXME: Clamp period to reasonable min value? + * Clamp period to reasonable max value + */ + new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; + timer->period = + (timer->period & 0xffffffffULL) | new_val << 32; } timer->config &= ~HPET_TN_SETVAL; - if (hpet_enabled()) + if (hpet_enabled(s)) { hpet_set_timer(timer); - break; - case HPET_TN_CMP + 4: // comparator register high order - DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n"); - if (!timer_is_periodic(timer) || - (timer->config & HPET_TN_SETVAL)) - timer->cmp = (timer->cmp & 0xffffffffULL) - | new_val << 32; - else { - /* - * FIXME: Clamp period to reasonable min value? - * Clamp period to reasonable max value - */ - new_val &= (timer->config - & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; - timer->period = (timer->period & 0xffffffffULL) - | new_val << 32; } - timer->config &= ~HPET_TN_SETVAL; - if (hpet_enabled()) - hpet_set_timer(timer); - break; - case HPET_TN_ROUTE + 4: - DPRINTF("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n"); - break; - default: - DPRINTF("qemu: invalid hpet_ram_writel\n"); break; + case HPET_TN_ROUTE: + timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val; + break; + case HPET_TN_ROUTE + 4: + timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff); + break; + default: + DPRINTF("qemu: invalid hpet_ram_writel\n"); + break; } return; } else { switch (index) { - case HPET_ID: - return; - case HPET_CFG: - val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); - s->config = (s->config & 0xffffffff00000000ULL) | val; - if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { - /* Enable main counter and interrupt generation. */ - s->hpet_offset = ticks_to_ns(s->hpet_counter) - - qemu_get_clock(vm_clock); - for (i = 0; i < HPET_NUM_TIMERS; i++) - if ((&s->timer[i])->cmp != ~0ULL) - hpet_set_timer(&s->timer[i]); + case HPET_ID: + return; + case HPET_CFG: + val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); + s->config = (s->config & 0xffffffff00000000ULL) | val; + if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { + /* Enable main counter and interrupt generation. */ + s->hpet_offset = + ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock); + for (i = 0; i < s->num_timers; i++) { + if ((&s->timer[i])->cmp != ~0ULL) { + hpet_set_timer(&s->timer[i]); + } } - else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { - /* Halt main counter and disable interrupt generation. */ - s->hpet_counter = hpet_get_ticks(); - for (i = 0; i < HPET_NUM_TIMERS; i++) - hpet_del_timer(&s->timer[i]); + } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { + /* Halt main counter and disable interrupt generation. */ + s->hpet_counter = hpet_get_ticks(s); + for (i = 0; i < s->num_timers; i++) { + hpet_del_timer(&s->timer[i]); } - /* i8254 and RTC are disabled when HPET is in legacy mode */ - if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { - hpet_pit_disable(); - } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { - hpet_pit_enable(); + } + /* i8254 and RTC are disabled when HPET is in legacy mode */ + if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { + hpet_pit_disable(); + qemu_irq_lower(s->irqs[RTC_ISA_IRQ]); + } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { + hpet_pit_enable(); + qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level); + } + break; + case HPET_CFG + 4: + DPRINTF("qemu: invalid HPET_CFG+4 write \n"); + break; + case HPET_STATUS: + val = new_val & s->isr; + for (i = 0; i < s->num_timers; i++) { + if (val & (1 << i)) { + update_irq(&s->timer[i], 0); } - break; - case HPET_CFG + 4: - DPRINTF("qemu: invalid HPET_CFG+4 write \n"); - break; - case HPET_STATUS: - /* FIXME: need to handle level-triggered interrupts */ - break; - case HPET_COUNTER: - if (hpet_enabled()) - printf("qemu: Writing counter while HPET enabled!\n"); - s->hpet_counter = (s->hpet_counter & 0xffffffff00000000ULL) - | value; - DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n", - value, s->hpet_counter); - break; - case HPET_COUNTER + 4: - if (hpet_enabled()) - printf("qemu: Writing counter while HPET enabled!\n"); - s->hpet_counter = (s->hpet_counter & 0xffffffffULL) - | (((uint64_t)value) << 32); - DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n", - value, s->hpet_counter); - break; - default: - DPRINTF("qemu: invalid hpet_ram_writel\n"); - break; + } + break; + case HPET_COUNTER: + if (hpet_enabled(s)) { + DPRINTF("qemu: Writing counter while HPET enabled!\n"); + } + s->hpet_counter = + (s->hpet_counter & 0xffffffff00000000ULL) | value; + DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n", + value, s->hpet_counter); + break; + case HPET_COUNTER + 4: + if (hpet_enabled(s)) { + DPRINTF("qemu: Writing counter while HPET enabled!\n"); + } + s->hpet_counter = + (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32); + DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n", + value, s->hpet_counter); + break; + default: + DPRINTF("qemu: invalid hpet_ram_writel\n"); + break; } } } @@ -529,58 +625,104 @@ static CPUWriteMemoryFunc * const hpet_ram_write[] = { hpet_ram_writel, }; -static void hpet_reset(void *opaque) { - HPETState *s = opaque; +static void hpet_reset(DeviceState *d) +{ + HPETState *s = FROM_SYSBUS(HPETState, sysbus_from_qdev(d)); int i; static int count = 0; - for (i=0; i<HPET_NUM_TIMERS; i++) { + for (i = 0; i < s->num_timers; i++) { HPETTimer *timer = &s->timer[i]; + hpet_del_timer(timer); - timer->tn = i; timer->cmp = ~0ULL; - timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; + timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; + if (s->flags & (1 << HPET_MSI_SUPPORT)) { + timer->config |= HPET_TN_FSB_CAP; + } /* advertise availability of ioapic inti2 */ timer->config |= 0x00000004ULL << 32; - timer->state = s; timer->period = 0ULL; timer->wrap_flag = 0; } s->hpet_counter = 0ULL; s->hpet_offset = 0ULL; - /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */ - s->capability = 0x8086a201ULL; + /* 64-bit main counter; LegacyReplacementRoute. */ + s->capability = 0x8086a001ULL; + s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; s->capability |= ((HPET_CLK_PERIOD) << 32); s->config = 0ULL; - if (count > 0) + if (count > 0) { /* we don't enable pit when hpet_reset is first called (by hpet_init) * because hpet is taking over for pit here. On subsequent invocations, * hpet_reset is called due to system reset. At this point control must * be returned to pit until SW reenables hpet. */ hpet_pit_enable(); + } count = 1; } +static void hpet_handle_rtc_irq(void *opaque, int n, int level) +{ + HPETState *s = FROM_SYSBUS(HPETState, opaque); + + s->rtc_irq_level = level; + if (!hpet_in_legacy_mode(s)) { + qemu_set_irq(s->irqs[RTC_ISA_IRQ], level); + } +} -void hpet_init(qemu_irq *irq) { +static int hpet_init(SysBusDevice *dev) +{ + HPETState *s = FROM_SYSBUS(HPETState, dev); int i, iomemtype; - HPETState *s; + HPETTimer *timer; - DPRINTF ("hpet_init\n"); + for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) { + sysbus_init_irq(dev, &s->irqs[i]); + } - s = qemu_mallocz(sizeof(HPETState)); - hpet_statep = s; - s->irqs = irq; - for (i=0; i<HPET_NUM_TIMERS; i++) { - HPETTimer *timer = &s->timer[i]; + if (s->num_timers < HPET_MIN_TIMERS) { + s->num_timers = HPET_MIN_TIMERS; + } else if (s->num_timers > HPET_MAX_TIMERS) { + s->num_timers = HPET_MAX_TIMERS; + } + for (i = 0; i < HPET_MAX_TIMERS; i++) { + timer = &s->timer[i]; timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer); + timer->tn = i; + timer->state = s; } - vmstate_register(-1, &vmstate_hpet, s); - qemu_register_reset(hpet_reset, s); + + isa_reserve_irq(RTC_ISA_IRQ); + qdev_init_gpio_in(&dev->qdev, hpet_handle_rtc_irq, 1); + /* HPET Area */ iomemtype = cpu_register_io_memory(hpet_ram_read, hpet_ram_write, s); - cpu_register_physical_memory(HPET_BASE, 0x400, iomemtype); + sysbus_init_mmio(dev, 0x400, iomemtype); + return 0; } + +static SysBusDeviceInfo hpet_device_info = { + .qdev.name = "hpet", + .qdev.size = sizeof(HPETState), + .qdev.no_user = 1, + .qdev.vmsd = &vmstate_hpet, + .qdev.reset = hpet_reset, + .init = hpet_init, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), + DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void hpet_register_device(void) +{ + sysbus_register_withprop(&hpet_device_info); +} + +device_init(hpet_register_device) diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h index cfd95b4ad4..d7bc102c22 100644 --- a/hw/hpet_emul.h +++ b/hw/hpet_emul.h @@ -17,8 +17,10 @@ #define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/ #define FS_PER_NS 1000000 -#define HPET_NUM_TIMERS 3 -#define HPET_TIMER_TYPE_LEVEL 0x002 +#define HPET_MIN_TIMERS 3 +#define HPET_MAX_TIMERS 32 + +#define HPET_NUM_IRQ_ROUTES 32 #define HPET_CFG_ENABLE 0x001 #define HPET_CFG_LEGACY 0x002 @@ -33,7 +35,10 @@ #define HPET_TN_ROUTE 0x010 #define HPET_CFG_WRITE_MASK 0x3 +#define HPET_ID_NUM_TIM_SHIFT 8 +#define HPET_ID_NUM_TIM_MASK 0x1f00 +#define HPET_TN_TYPE_LEVEL 0x002 #define HPET_TN_ENABLE 0x004 #define HPET_TN_PERIODIC 0x008 #define HPET_TN_PERIODIC_CAP 0x010 @@ -41,42 +46,11 @@ #define HPET_TN_SETVAL 0x040 #define HPET_TN_32BIT 0x100 #define HPET_TN_INT_ROUTE_MASK 0x3e00 -#define HPET_TN_CFG_WRITE_MASK 0x3f4e +#define HPET_TN_FSB_ENABLE 0x4000 +#define HPET_TN_FSB_CAP 0x8000 +#define HPET_TN_CFG_WRITE_MASK 0x7f4e #define HPET_TN_INT_ROUTE_SHIFT 9 #define HPET_TN_INT_ROUTE_CAP_SHIFT 32 #define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U -struct HPETState; -typedef struct HPETTimer { /* timers */ - uint8_t tn; /*timer number*/ - QEMUTimer *qemu_timer; - struct HPETState *state; - /* Memory-mapped, software visible timer registers */ - uint64_t config; /* configuration/cap */ - uint64_t cmp; /* comparator */ - uint64_t fsb; /* FSB route, not supported now */ - /* Hidden register state */ - uint64_t period; /* Last value written to comparator */ - uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit - * mode. Next pop will be actual timer expiration. - */ -} HPETTimer; - -typedef struct HPETState { - uint64_t hpet_offset; - qemu_irq *irqs; - HPETTimer timer[HPET_NUM_TIMERS]; - - /* Memory-mapped, software visible registers */ - uint64_t capability; /* capabilities */ - uint64_t config; /* configuration */ - uint64_t isr; /* interrupt status reg */ - uint64_t hpet_counter; /* main counter */ -} HPETState; - -#if defined TARGET_I386 -extern uint32_t hpet_in_legacy_mode(void); -extern void hpet_init(qemu_irq *irq); -#endif - #endif @@ -8,7 +8,6 @@ #include "cpu-common.h" #endif -#include <stdbool.h> #include "ioport.h" #include "irq.h" @@ -474,6 +473,16 @@ extern const VMStateInfo vmstate_info_unused_buffer; .offset = vmstate_offset_array(_state, _field, _type, _num), \ } +#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \ + .version_id = (_version), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT|VMS_VARRAY_INT32, \ + .offset = offsetof(_state, _field), \ +} + #define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \ .name = (stringify(_field)), \ .version_id = (_version), \ diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index c3e6a70e3d..c3459bf605 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -27,7 +27,6 @@ #include "pc.h" #include "apic.h" #include "isa.h" -#include "hpet_emul.h" #include "mc146818rtc.h" //#define DEBUG_CMOS @@ -101,19 +100,6 @@ typedef struct RTCState { QEMUTimer *second_timer2; } RTCState; -static void rtc_irq_raise(qemu_irq irq) -{ - /* When HPET is operating in legacy mode, RTC interrupts are disabled - * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy - * mode is established while interrupt is raised. We want it to - * be lowered in any case - */ -#if defined TARGET_I386 - if (!hpet_in_legacy_mode()) -#endif - qemu_irq_raise(irq); -} - static void rtc_set_time(RTCState *s); static void rtc_copy_date(RTCState *s); @@ -139,7 +125,7 @@ static void rtc_coalesced_timer(void *opaque) apic_reset_irq_delivered(); s->cmos_data[RTC_REG_C] |= 0xc0; DPRINTF_C("cmos: injecting from timer\n"); - rtc_irq_raise(s->irq); + qemu_irq_raise(s->irq); if (apic_get_irq_delivered()) { s->irq_coalesced--; DPRINTF_C("cmos: coalesced irqs decreased to %d\n", @@ -155,19 +141,10 @@ static void rtc_timer_update(RTCState *s, int64_t current_time) { int period_code, period; int64_t cur_clock, next_irq_clock; - int enable_pie; period_code = s->cmos_data[RTC_REG_A] & 0x0f; -#if defined TARGET_I386 - /* disable periodic timer if hpet is in legacy mode, since interrupts are - * disabled anyway. - */ - enable_pie = !hpet_in_legacy_mode(); -#else - enable_pie = 1; -#endif if (period_code != 0 - && (((s->cmos_data[RTC_REG_B] & REG_B_PIE) && enable_pie) + && ((s->cmos_data[RTC_REG_B] & REG_B_PIE) || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) { if (period_code <= 2) period_code += 7; @@ -206,7 +183,7 @@ static void rtc_periodic_timer(void *opaque) if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) s->irq_reinject_on_ack_count = 0; apic_reset_irq_delivered(); - rtc_irq_raise(s->irq); + qemu_irq_raise(s->irq); if (!apic_get_irq_delivered()) { s->irq_coalesced++; rtc_coalesced_timer_update(s); @@ -215,7 +192,7 @@ static void rtc_periodic_timer(void *opaque) } } else #endif - rtc_irq_raise(s->irq); + qemu_irq_raise(s->irq); } if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) { /* Not square wave at all but we don't want 2048Hz interrupts! @@ -444,15 +421,15 @@ static void rtc_update_second2(void *opaque) s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) { s->cmos_data[RTC_REG_C] |= 0xa0; - rtc_irq_raise(s->irq); + qemu_irq_raise(s->irq); } } /* update ended interrupt */ s->cmos_data[RTC_REG_C] |= REG_C_UF; if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; - rtc_irq_raise(s->irq); + s->cmos_data[RTC_REG_C] |= REG_C_IRQF; + qemu_irq_raise(s->irq); } /* clear update in progress bit */ @@ -606,9 +583,6 @@ static int rtc_initfn(ISADevice *dev) { RTCState *s = DO_UPCAST(RTCState, dev, dev); int base = 0x70; - int isairq = 8; - - isa_init_irq(dev, &s->irq, isairq); s->cmos_data[RTC_REG_A] = 0x26; s->cmos_data[RTC_REG_B] = 0x02; @@ -638,13 +612,20 @@ static int rtc_initfn(ISADevice *dev) return 0; } -ISADevice *rtc_init(int base_year) +ISADevice *rtc_init(int base_year, qemu_irq intercept_irq) { ISADevice *dev; + RTCState *s; dev = isa_create("mc146818rtc"); + s = DO_UPCAST(RTCState, dev, dev); qdev_prop_set_int32(&dev->qdev, "base_year", base_year); qdev_init_nofail(&dev->qdev); + if (intercept_irq) { + s->irq = intercept_irq; + } else { + isa_init_irq(dev, &s->irq, RTC_ISA_IRQ); + } return dev; } diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h index 6f46a68e02..575968c041 100644 --- a/hw/mc146818rtc.h +++ b/hw/mc146818rtc.h @@ -3,7 +3,9 @@ #include "isa.h" -ISADevice *rtc_init(int base_year); +#define RTC_ISA_IRQ 8 + +ISADevice *rtc_init(int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); void rtc_set_date(ISADevice *dev, const struct tm *tm); diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index ead3a00c3d..22db7a2f7a 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -259,7 +259,7 @@ void mips_jazz_init (ram_addr_t ram_size, fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds); /* Real time clock */ - rtc_init(1980); + rtc_init(1980, NULL); s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL); cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index a8f9d152dd..23de7f0f30 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -959,7 +959,7 @@ void mips_malta_init (ram_addr_t ram_size, /* Super I/O */ isa_dev = isa_create_simple("i8042"); - rtc_state = rtc_init(2000); + rtc_state = rtc_init(2000, NULL); serial_isa_init(0, serial_hds[0]); serial_isa_init(1, serial_hds[1]); if (parallel_hds[0]) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index f1fcfcd2ed..5a96dea003 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -267,7 +267,7 @@ void mips_r4k_init (ram_addr_t ram_size, isa_bus_new(NULL); isa_bus_irqs(i8259); - rtc_state = rtc_init(2000); + rtc_state = rtc_init(2000, NULL); /* Register 64 KB of ISA IO space at 0x14000000 */ #ifdef TARGET_WORDS_BIGENDIAN @@ -35,6 +35,7 @@ #include "elf.h" #include "multiboot.h" #include "mc146818rtc.h" +#include "sysbus.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS @@ -942,6 +943,7 @@ void pc_basic_device_init(qemu_irq *isa_irq, int i; DriveInfo *fd[MAX_FD]; PITState *pit; + qemu_irq rtc_irq = NULL; qemu_irq *a20_line; ISADevice *i8042; qemu_irq *cpu_exit_irq; @@ -950,15 +952,20 @@ void pc_basic_device_init(qemu_irq *isa_irq, register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); - *rtc_state = rtc_init(2000); + if (!no_hpet) { + DeviceState *hpet = sysbus_create_simple("hpet", HPET_BASE, NULL); + + for (i = 0; i < 24; i++) { + sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]); + } + rtc_irq = qdev_get_gpio_in(hpet, 0); + } + *rtc_state = rtc_init(2000, rtc_irq); qemu_register_boot_set(pc_boot_set, *rtc_state); pit = pit_init(0x40, isa_reserve_irq(0)); pcspk_init(pit); - if (!no_hpet) { - hpet_init(isa_irq); - } for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 16c9950740..bb9e15ffd8 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -696,7 +696,7 @@ static void ppc_prep_init (ram_addr_t ram_size, pci_vga_init(pci_bus, 0, 0); // openpic = openpic_init(0x00000000, 0xF0000000, 1); // pit = pit_init(0x40, i8259[0]); - rtc_init(2000); + rtc_init(2000, NULL); if (serial_hds[0]) serial_isa_init(0, serial_hds[0]); diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 9f80e159ad..c60fd8deef 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1415,6 +1415,8 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr) OHCIState *ohci = ptr; uint32_t retval; + addr &= 0xff; + /* Only aligned reads are allowed on OHCI */ if (addr & 3) { fprintf(stderr, "usb-ohci: Mis-aligned read\n"); @@ -1538,6 +1540,8 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) { OHCIState *ohci = ptr; + addr &= 0xff; + #ifdef TARGET_WORDS_BIGENDIAN val = bswap32(val); #endif diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index a93b5458b2..ff08c40681 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -15,7 +15,6 @@ #ifndef _QEMU_VIRTIO_SERIAL_H #define _QEMU_VIRTIO_SERIAL_H -#include <stdbool.h> #include "qdev.h" #include "virtio.h" diff --git a/hw/xenfb.c b/hw/xenfb.c index 422cd53400..da5297b498 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -29,7 +29,6 @@ #include <sys/types.h> #include <fcntl.h> #include <unistd.h> -#include <stdbool.h> #include <sys/mman.h> #include <errno.h> #include <stdio.h> |