diff options
| -rwxr-xr-x | configure | 9 | ||||
| -rw-r--r-- | hw/net/spapr_llan.c | 2 | ||||
| -rw-r--r-- | hw/ppc/e500.c | 31 | ||||
| -rw-r--r-- | hw/ppc/prep.c | 36 | ||||
| -rw-r--r-- | hw/ppc/spapr_iommu.c | 14 | ||||
| -rw-r--r-- | hw/s390x/ipl.c | 38 | ||||
| -rw-r--r-- | hw/timer/imx_timer.c | 262 | ||||
| -rw-r--r-- | pc-bios/README | 4 | ||||
| -rw-r--r-- | pc-bios/s390-ccw.img | bin | 9432 -> 9432 bytes | |||
| -rw-r--r-- | pc-bios/s390-ccw/main.c | 24 | ||||
| -rw-r--r-- | pc-bios/s390-ccw/start.S | 2 | ||||
| -rw-r--r-- | pc-bios/slof.bin | bin | 880832 -> 909720 bytes | |||
| m--------- | roms/SLOF | 0 | ||||
| -rw-r--r-- | target-ppc/cpu.h | 3 | ||||
| -rw-r--r-- | target-ppc/mmu_helper.c | 4 | ||||
| -rw-r--r-- | target-ppc/translate.c | 32 | ||||
| -rw-r--r-- | target-ppc/translate_init.c | 4 |
17 files changed, 346 insertions, 119 deletions
diff --git a/configure b/configure index e818e8b357..9439f1c727 100755 --- a/configure +++ b/configure @@ -1685,6 +1685,14 @@ if ! has $libtool; then libtool= fi +# MacOSX ships with a libtool which isn't the GNU one; weed this +# out by checking whether libtool supports the --version switch +if test -n "$libtool"; then + if ! "$libtool" --version >/dev/null 2>&1; then + libtool= + fi +fi + ########################################## # Sparse probe if test "$sparse" != "no" ; then @@ -4510,6 +4518,7 @@ for bios_file in \ $source_path/pc-bios/*.aml \ $source_path/pc-bios/*.rom \ $source_path/pc-bios/*.dtb \ + $source_path/pc-bios/*.img \ $source_path/pc-bios/openbios-* \ $source_path/pc-bios/palcode-* do diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 3150add3c1..03a09f2047 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -336,6 +336,8 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu, spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue)); dev->isopen = 1; + qemu_flush_queued_packets(qemu_get_queue(dev->nic)); + return H_SUCCESS; } diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index c1bdb6be98..c9ae51211e 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -37,6 +37,7 @@ #include "qemu/host-utils.h" #include "hw/pci-host/ppce500.h" +#define EPAPR_MAGIC (0x45504150) #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define UIMAGE_LOAD_BASE 0 #define DTC_LOAD_PAD 0x1800000 @@ -393,11 +394,10 @@ static inline hwaddr booke206_page_size_to_tlb(uint64_t size) return 63 - clz64(size >> 10); } -static void mmubooke_create_initial_mapping(CPUPPCState *env) +static int booke206_initial_map_tsize(CPUPPCState *env) { struct boot_info *bi = env->load_info; - ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); - hwaddr size, dt_end; + hwaddr dt_end; int ps; /* Our initial TLB entry needs to cover everything from 0 to @@ -408,6 +408,24 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env) /* e500v2 can only do even TLB size bits */ ps++; } + return ps; +} + +static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) +{ + int tsize; + + tsize = booke206_initial_map_tsize(env); + return (1ULL << 10 << tsize); +} + +static void mmubooke_create_initial_mapping(CPUPPCState *env) +{ + ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); + hwaddr size; + int ps; + + ps = booke206_initial_map_tsize(env); size = (ps << MAS1_TSIZE_SHIFT); tlb->mas1 = MAS1_VALID | size; tlb->mas2 = 0; @@ -444,6 +462,12 @@ static void ppce500_cpu_reset(void *opaque) cs->halted = 0; env->gpr[1] = (16<<20) - 8; env->gpr[3] = bi->dt_base; + env->gpr[4] = 0; + env->gpr[5] = 0; + env->gpr[6] = EPAPR_MAGIC; + env->gpr[7] = mmubooke_initial_mapsize(env); + env->gpr[8] = 0; + env->gpr[9] = 0; env->nip = bi->entry; mmubooke_create_initial_mapping(env); } @@ -523,6 +547,7 @@ void ppce500_init(PPCE500Params *params) /* Fixup Memory size on a alignment boundary */ ram_size &= ~(RAM_SIZES_ALIGN - 1); + params->ram_size = ram_size; /* Register Memory */ memory_region_init_ram(ram, "mpc8544ds.ram", ram_size); diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 59c7da3af7..be8a50ec4a 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -40,7 +40,9 @@ #include "hw/isa/pc87312.h" #include "sysemu/blockdev.h" #include "sysemu/arch_init.h" +#include "sysemu/qtest.h" #include "exec/address-spaces.h" +#include "elf.h" //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO @@ -267,7 +269,7 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) switch (addr) { case 0x0092: /* Special port 92 */ - retval = 0x00; + retval = sysctrl->endian << 1; break; case 0x0800: /* Motorola CPU configuration register */ @@ -427,6 +429,9 @@ static void ppc_prep_reset(void *opaque) PowerPCCPU *cpu = opaque; cpu_reset(CPU(cpu)); + + /* Reset address */ + cpu->env.nip = 0xfffffffc; } /* PowerPC PREP hardware initialisation */ @@ -502,18 +507,29 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) bios_name = BIOS_FILENAME; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { - bios_size = get_image_size(filename); + bios_size = load_elf(filename, NULL, NULL, NULL, + NULL, NULL, 1, ELF_MACHINE, 0); + if (bios_size < 0) { + bios_size = get_image_size(filename); + if (bios_size > 0 && bios_size <= BIOS_SIZE) { + hwaddr bios_addr; + bios_size = (bios_size + 0xfff) & ~0xfff; + bios_addr = (uint32_t)(-bios_size); + bios_size = load_image_targphys(filename, bios_addr, bios_size); + } + if (bios_size > BIOS_SIZE) { + fprintf(stderr, "qemu: PReP bios '%s' is too large (0x%x)\n", + bios_name, bios_size); + exit(1); + } + } } else { bios_size = -1; } - if (bios_size > 0 && bios_size <= BIOS_SIZE) { - hwaddr bios_addr; - bios_size = (bios_size + 0xfff) & ~0xfff; - bios_addr = (uint32_t)(-bios_size); - bios_size = load_image_targphys(filename, bios_addr, bios_size); - } - if (bios_size < 0 || bios_size > BIOS_SIZE) { - hw_error("qemu: could not load PPC PREP bios '%s'\n", bios_name); + if (bios_size < 0 && !qtest_enabled()) { + fprintf(stderr, "qemu: could not load PPC PReP bios '%s'\n", + bios_name); + exit(1); } if (filename) { g_free(filename); diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index d2782cfb39..e1fe94115f 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -55,6 +55,12 @@ static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) { sPAPRTCETable *tcet; + if (liobn & 0xFFFFFFFF00000000ULL) { + hcall_dprintf("Request for out-of-bounds LIOBN 0x" TARGET_FMT_lx "\n", + liobn); + return NULL; + } + QLIST_FOREACH(tcet, &spapr_tce_tables, list) { if (tcet->liobn == liobn) { return tcet; @@ -199,7 +205,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, sPAPRTCE *tcep; if (ioba >= tcet->window_size) { - hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x" + hcall_dprintf("spapr_vio_put_tce on out-of-bounds IOBA 0x" TARGET_FMT_lx "\n", ioba); return H_PARAMETER; } @@ -218,12 +224,6 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong tce = args[2]; sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); - if (liobn & 0xFFFFFFFF00000000ULL) { - hcall_dprintf("spapr_vio_put_tce on out-of-boundsw LIOBN " - TARGET_FMT_lx "\n", liobn); - return H_PARAMETER; - } - ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1); if (tcet) { diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index ace5ff50d1..0aeb003c9d 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -16,6 +16,8 @@ #include "elf.h" #include "hw/loader.h" #include "hw/sysbus.h" +#include "hw/s390x/virtio-ccw.h" +#include "hw/s390x/css.h" #define KERN_IMAGE_START 0x010000UL #define KERN_PARM_AREA 0x010480UL @@ -57,16 +59,6 @@ typedef struct S390IPLState { } S390IPLState; -static void s390_ipl_cpu(uint64_t pswaddr) -{ - S390CPU *cpu = S390_CPU(qemu_get_cpu(0)); - CPUS390XState *env = &cpu->env; - - env->psw.addr = pswaddr; - env->psw.mask = IPL_PSW_MASK; - s390_add_running_cpu(cpu); -} - static int s390_ipl_init(SysBusDevice *dev) { S390IPLState *ipl = S390_IPL(dev); @@ -82,6 +74,10 @@ static int s390_ipl_init(SysBusDevice *dev) } bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (bios_filename == NULL) { + hw_error("could not find stage1 bootloader\n"); + } + bios_size = load_elf(bios_filename, NULL, NULL, &ipl->start_addr, NULL, NULL, 1, ELF_MACHINE, 0); if (bios_size == -1UL) { @@ -151,8 +147,28 @@ static Property s390_ipl_properties[] = { static void s390_ipl_reset(DeviceState *dev) { S390IPLState *ipl = S390_IPL(dev); + S390CPU *cpu = S390_CPU(qemu_get_cpu(0)); + CPUS390XState *env = &cpu->env; - s390_ipl_cpu(ipl->start_addr); + env->psw.addr = ipl->start_addr; + env->psw.mask = IPL_PSW_MASK; + + if (!ipl->kernel) { + /* booting firmware, tell what device to boot from */ + DeviceState *dev_st = get_boot_device(0); + VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast( + OBJECT(&(dev_st->parent_obj)), "virtio-blk-ccw"); + + if (ccw_dev) { + env->regs[7] = ccw_dev->sch->cssid << 24 | + ccw_dev->sch->ssid << 16 | + ccw_dev->sch->devno; + } else { + env->regs[7] = -1; + } + } + + s390_add_running_cpu(cpu); } static void s390_ipl_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/imx_timer.c b/hw/timer/imx_timer.c index 03197e3f54..7693bb7364 100644 --- a/hw/timer/imx_timer.c +++ b/hw/timer/imx_timer.c @@ -95,6 +95,10 @@ typedef struct { uint32_t sr; uint32_t ir; uint32_t ocr1; + uint32_t ocr2; + uint32_t ocr3; + uint32_t icr1; + uint32_t icr2; uint32_t cnt; uint32_t waiting_rov; @@ -103,15 +107,19 @@ typedef struct { static const VMStateDescription vmstate_imx_timerg = { .name = "imx-timerg", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(cr, IMXTimerGState), VMSTATE_UINT32(pr, IMXTimerGState), VMSTATE_UINT32(sr, IMXTimerGState), VMSTATE_UINT32(ir, IMXTimerGState), VMSTATE_UINT32(ocr1, IMXTimerGState), + VMSTATE_UINT32(ocr2, IMXTimerGState), + VMSTATE_UINT32(ocr3, IMXTimerGState), + VMSTATE_UINT32(icr1, IMXTimerGState), + VMSTATE_UINT32(icr2, IMXTimerGState), VMSTATE_UINT32(cnt, IMXTimerGState), VMSTATE_UINT32(waiting_rov, IMXTimerGState), VMSTATE_PTIMER(timer, IMXTimerGState), @@ -156,7 +164,6 @@ static void imx_timerg_update(IMXTimerGState *s) s->ir & GPT_SR_ROV ? "ROV" : "", s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled"); - qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags); } @@ -221,6 +228,21 @@ static uint64_t imx_timerg_read(void *opaque, hwaddr offset, DPRINTF(" ocr1 = %x\n", s->ocr1); return s->ocr1; + case 5: /* Output Compare Register 2 */ + DPRINTF(" ocr2 = %x\n", s->ocr2); + return s->ocr2; + + case 6: /* Output Compare Register 3 */ + DPRINTF(" ocr3 = %x\n", s->ocr3); + return s->ocr3; + + case 7: /* input Capture Register 1 */ + DPRINTF(" icr1 = %x\n", s->icr1); + return s->icr1; + + case 8: /* input Capture Register 2 */ + DPRINTF(" icr2 = %x\n", s->icr2); + return s->icr2; case 9: /* cnt */ imx_timerg_update_counts(s); @@ -230,6 +252,7 @@ static uint64_t imx_timerg_read(void *opaque, hwaddr offset, IPRINTF("imx_timerg_read: Bad offset %x\n", (int)offset >> 2); + return 0; } @@ -240,14 +263,20 @@ static void imx_timerg_reset(DeviceState *dev) /* * Soft reset doesn't touch some bits; hard reset clears them */ - s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN); + s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| + GPT_CR_WAITEN|GPT_CR_DBGEN); s->sr = 0; s->pr = 0; s->ir = 0; s->cnt = 0; s->ocr1 = TIMER_MAX; + s->ocr2 = TIMER_MAX; + s->ocr3 = TIMER_MAX; + s->icr1 = 0; + s->icr2 = 0; ptimer_stop(s->timer); ptimer_set_limit(s->timer, TIMER_MAX, 1); + ptimer_set_count(s->timer, TIMER_MAX); imx_timerg_set_freq(s); } @@ -323,6 +352,8 @@ static void imx_timerg_write(void *opaque, hwaddr offset, s->ocr1 = value; return; + case 5: /* OCR2 -- output compare register */ + case 6: /* OCR3 -- output compare register */ default: IPRINTF("imx_timerg_write: Bad offset %x\n", (int)offset >> 2); @@ -411,7 +442,7 @@ static int imx_timerg_init(SysBusDevice *dev) #define CR_SWR (1 << 16) #define CR_IOVW (1 << 17) #define CR_DBGEN (1 << 18) -#define CR_EPIT (1 << 19) +#define CR_WAITEN (1 << 19) #define CR_DOZEN (1 << 20) #define CR_STOPEN (1 << 21) #define CR_CLKSRC_SHIFT (24) @@ -423,24 +454,26 @@ static int imx_timerg_init(SysBusDevice *dev) * These are typical. */ static const IMXClk imx_timerp_clocks[] = { - 0, /* disabled */ - IPG, /* ipg_clk, ~532MHz */ - IPG, /* ipg_clk_highfreq */ - CLK_32k, /* ipg_clk_32k -- ~32kHz */ + 0, /* 00 disabled */ + IPG, /* 01 ipg_clk, ~532MHz */ + IPG, /* 10 ipg_clk_highfreq */ + CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */ }; typedef struct { SysBusDevice busdev; - ptimer_state *timer; + ptimer_state *timer_reload; + ptimer_state *timer_cmp; MemoryRegion iomem; DeviceState *ccm; uint32_t cr; + uint32_t sr; uint32_t lr; uint32_t cmp; + uint32_t cnt; uint32_t freq; - int int_level; qemu_irq irq; } IMXTimerPState; @@ -449,23 +482,63 @@ typedef struct { */ static void imx_timerp_update(IMXTimerPState *s) { - if (s->int_level && (s->cr & CR_OCIEN)) { + if (s->sr && (s->cr & CR_OCIEN)) { qemu_irq_raise(s->irq); } else { qemu_irq_lower(s->irq); } } +static void set_timerp_freq(IMXTimerPState *s) +{ + int clksrc; + unsigned prescaler; + uint32_t freq; + + clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT; + prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK); + freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler; + + s->freq = freq; + DPRINTF("Setting ptimer frequency to %u\n", freq); + + if (freq) { + ptimer_set_freq(s->timer_reload, freq); + ptimer_set_freq(s->timer_cmp, freq); + } +} + static void imx_timerp_reset(DeviceState *dev) { IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev); - s->cr = 0; + /* + * Soft reset doesn't touch some bits; hard reset clears them + */ + s->cr &= ~(CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); + s->sr = 0; s->lr = TIMER_MAX; - s->int_level = 0; s->cmp = 0; - ptimer_stop(s->timer); - ptimer_set_count(s->timer, TIMER_MAX); + s->cnt = 0; + /* stop both timers */ + ptimer_stop(s->timer_cmp); + ptimer_stop(s->timer_reload); + /* compute new frequency */ + set_timerp_freq(s); + /* init both timers to TIMER_MAX */ + ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1); + ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); + if (s->freq && (s->cr & CR_EN)) { + /* if the timer is still enabled, restart it */ + ptimer_run(s->timer_reload, 1); + } +} + +static uint32_t imx_timerp_update_counts(IMXTimerPState *s) +{ + s->cnt = ptimer_get_count(s->timer_reload); + + return s->cnt; } static uint64_t imx_timerp_read(void *opaque, hwaddr offset, @@ -480,8 +553,8 @@ static uint64_t imx_timerp_read(void *opaque, hwaddr offset, return s->cr; case 1: /* Status Register */ - DPRINTF("int_level %x\n", s->int_level); - return s->int_level; + DPRINTF("sr %x\n", s->sr); + return s->sr; case 2: /* LR - ticks*/ DPRINTF("lr %x\n", s->lr); @@ -492,28 +565,29 @@ static uint64_t imx_timerp_read(void *opaque, hwaddr offset, return s->cmp; case 4: /* CNT */ - return ptimer_get_count(s->timer); + imx_timerp_update_counts(s); + DPRINTF(" cnt = %x\n", s->cnt); + return s->cnt; } + IPRINTF("imx_timerp_read: Bad offset %x\n", (int)offset >> 2); return 0; } -static void set_timerp_freq(IMXTimerPState *s) +static void imx_reload_compare_timer(IMXTimerPState *s) { - int clksrc; - unsigned prescaler; - uint32_t freq; - - clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT; - prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK); - freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler; - - s->freq = freq; - DPRINTF("Setting ptimer frequency to %u\n", freq); - - if (freq) { - ptimer_set_freq(s->timer, freq); + if ((s->cr & CR_OCIEN) && s->cmp) { + /* if the compare feature is on */ + uint32_t tmp = imx_timerp_update_counts(s); + if (tmp > s->cmp) { + /* reinit the cmp timer if required */ + ptimer_set_count(s->timer_cmp, tmp - s->cmp); + if ((s->cr & CR_EN)) { + /* Restart the cmp timer if required */ + ptimer_run(s->timer_cmp, 0); + } + } } } @@ -526,40 +600,62 @@ static void imx_timerp_write(void *opaque, hwaddr offset, switch (offset >> 2) { case 0: /* CR */ - if (value & CR_SWR) { + s->cr = value & 0x03ffffff; + if (s->cr & CR_SWR) { + /* handle the reset */ imx_timerp_reset(&s->busdev.qdev); - value &= ~CR_SWR; + } else { + set_timerp_freq(s); } - s->cr = value & 0x03ffffff; - set_timerp_freq(s); if (s->freq && (s->cr & CR_EN)) { - if (!(s->cr & CR_ENMOD)) { - ptimer_set_count(s->timer, s->lr); + if (s->cr & CR_ENMOD) { + if (s->cr & CR_RLD) { + ptimer_set_limit(s->timer_reload, s->lr, 1); + } else { + ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); + } } - ptimer_run(s->timer, 0); + + imx_reload_compare_timer(s); + + ptimer_run(s->timer_reload, 1); } else { - ptimer_stop(s->timer); + /* stop both timers */ + ptimer_stop(s->timer_reload); + ptimer_stop(s->timer_cmp); } break; case 1: /* SR - ACK*/ - s->int_level = 0; - imx_timerp_update(s); + /* writing 1 to OCIF clear the OCIF bit */ + if (value & 0x01) { + s->sr = 0; + imx_timerp_update(s); + } break; case 2: /* LR - set ticks */ s->lr = value; - ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW)); + + if (s->cr & CR_RLD) { + /* Also set the limit if the LRD bit is set */ + /* If IOVW bit is set then set the timer value */ + ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); + } else if (s->cr & CR_IOVW) { + /* If IOVW bit is set then set the timer value */ + ptimer_set_count(s->timer_reload, s->lr); + } + + imx_reload_compare_timer(s); + break; case 3: /* CMP */ s->cmp = value; - if (value) { - IPRINTF( - "Values for EPIT comparison other than zero not supported\n" - ); - } + + imx_reload_compare_timer(s); + break; default: @@ -568,16 +664,50 @@ static void imx_timerp_write(void *opaque, hwaddr offset, } } -static void imx_timerp_tick(void *opaque) +static void imx_timerp_reload(void *opaque) { IMXTimerPState *s = (IMXTimerPState *)opaque; - DPRINTF("imxp tick\n"); - if (!(s->cr & CR_RLD)) { - ptimer_set_count(s->timer, TIMER_MAX); + DPRINTF("imxp reload\n"); + + if (!(s->cr & CR_EN)) { + return; + } + + if (s->cr & CR_RLD) { + ptimer_set_limit(s->timer_reload, s->lr, 1); + } else { + ptimer_set_limit(s->timer_reload, TIMER_MAX, 1); + } + + if (s->cr & CR_OCIEN) { + /* if compare register is 0 then we handle the interrupt here */ + if (s->cmp == 0) { + s->sr = 1; + imx_timerp_update(s); + } else if (s->cmp <= s->lr) { + /* We should launch the compare register */ + ptimer_set_count(s->timer_cmp, s->lr - s->cmp); + ptimer_run(s->timer_cmp, 0); + } else { + IPRINTF("imxp reload: s->lr < s->cmp\n"); + } + } +} + +static void imx_timerp_cmp(void *opaque) +{ + IMXTimerPState *s = (IMXTimerPState *)opaque; + + DPRINTF("imxp compare\n"); + + ptimer_stop(s->timer_cmp); + + /* compare register is not 0 */ + if (s->cmp) { + s->sr = 1; + imx_timerp_update(s); } - s->int_level = 1; - imx_timerp_update(s); } void imx_timerp_create(const hwaddr addr, @@ -600,16 +730,18 @@ static const MemoryRegionOps imx_timerp_ops = { static const VMStateDescription vmstate_imx_timerp = { .name = "imx-timerp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(cr, IMXTimerPState), + VMSTATE_UINT32(sr, IMXTimerPState), VMSTATE_UINT32(lr, IMXTimerPState), VMSTATE_UINT32(cmp, IMXTimerPState), + VMSTATE_UINT32(cnt, IMXTimerPState), VMSTATE_UINT32(freq, IMXTimerPState), - VMSTATE_INT32(int_level, IMXTimerPState), - VMSTATE_PTIMER(timer, IMXTimerPState), + VMSTATE_PTIMER(timer_reload, IMXTimerPState), + VMSTATE_PTIMER(timer_cmp, IMXTimerPState), VMSTATE_END_OF_LIST() } }; @@ -620,15 +752,17 @@ static int imx_timerp_init(SysBusDevice *dev) QEMUBH *bh; DPRINTF("imx_timerp_init\n"); - sysbus_init_irq(dev, &s->irq); memory_region_init_io(&s->iomem, &imx_timerp_ops, s, "imxp-timer", 0x00001000); sysbus_init_mmio(dev, &s->iomem); - bh = qemu_bh_new(imx_timerp_tick, s); - s->timer = ptimer_init(bh); + bh = qemu_bh_new(imx_timerp_reload, s); + s->timer_reload = ptimer_init(bh); + + bh = qemu_bh_new(imx_timerp_cmp, s); + s->timer_cmp = ptimer_init(bh); return 0; } diff --git a/pc-bios/README b/pc-bios/README index 7b4dfed6cf..030d92a049 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -16,8 +16,8 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at - https://github.com/dgibson/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20121018. + https://github.com/aik/SLOF, and the image currently in qemu is + built from git tag qemu-slof-20130430. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 149cf70140..1b2a11e728 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img Binary files differdiff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index fd40fa582a..1665c57225 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -12,6 +12,7 @@ struct subchannel_id blk_schid; char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE))); +uint64_t boot_value; void virtio_panic(const char *string) { @@ -20,15 +21,22 @@ void virtio_panic(const char *string) while (1) { } } -static void virtio_setup(void) +static void virtio_setup(uint64_t dev_info) { struct schib schib; int i; int r; bool found = false; - + bool check_devno = false; + uint16_t dev_no = -1; blk_schid.one = 1; + if (dev_info != -1) { + check_devno = true; + dev_no = dev_info & 0xffff; + debug_print_int("device no. ", dev_no); + } + for (i = 0; i < 0x10000; i++) { blk_schid.sch_no = i; r = stsch_err(blk_schid, &schib); @@ -36,9 +44,11 @@ static void virtio_setup(void) break; } if (schib.pmcw.dnv) { - if (virtio_is_blk(blk_schid)) { - found = true; - break; + if (!check_devno || (schib.pmcw.dev == dev_no)) { + if (virtio_is_blk(blk_schid)) { + found = true; + break; + } } } } @@ -53,7 +63,9 @@ static void virtio_setup(void) int main(void) { sclp_setup(); - virtio_setup(); + debug_print_int("boot reg[7] ", boot_value); + virtio_setup(boot_value); + if (zipl_load() < 0) sclp_print("Failed to load OS from hard disk\n"); disabled_wait(); diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S index 09deee7fc0..5d5df0d616 100644 --- a/pc-bios/s390-ccw/start.S +++ b/pc-bios/s390-ccw/start.S @@ -14,6 +14,8 @@ _start: larl %r15, stack + 0x8000 /* Set up stack */ +larl %r6, boot_value +stg %r7, 0(%r6) /* save the boot_value before any function calls */ j main /* And call C */ /* diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index 3410f4fff4..092e58a46e 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin Binary files differdiff --git a/roms/SLOF b/roms/SLOF -Subproject 0ad10f26c94a86a0c9c3970e53f9a9f6a744055 +Subproject 8cfdfc43f4c4c8c8dfa4b7cf16f7c19c84eee81 diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 7cacb56bc5..aa1d013c31 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -119,6 +119,9 @@ enum powerpc_mmu_t { /* Architecture 2.06 variant */ POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | POWERPC_MMU_AMR | 0x00000003, + /* Architecture 2.06 "degraded" (no 1T segments) */ + POWERPC_MMU_2_06a = POWERPC_MMU_64 | POWERPC_MMU_AMR + | 0x00000003, /* Architecture 2.06 "degraded" (no 1T segments or AMR) */ POWERPC_MMU_2_06d = POWERPC_MMU_64 | 0x00000003, #endif /* defined(TARGET_PPC64) */ diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index acf01331f1..68d5415e54 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -1188,6 +1188,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env) #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: case POWERPC_MMU_2_06d: dump_slb(f, cpu_fprintf, env); break; @@ -1324,6 +1325,7 @@ hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr) #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: case POWERPC_MMU_2_06d: return ppc_hash64_get_phys_page_debug(env, addr); #endif @@ -1815,6 +1817,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env) #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: case POWERPC_MMU_2_06d: #endif /* defined(TARGET_PPC64) */ tlb_flush(env, 1); @@ -1884,6 +1887,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr) #if defined(TARGET_PPC64) case POWERPC_MMU_64B: case POWERPC_MMU_2_06: + case POWERPC_MMU_2_06a: case POWERPC_MMU_2_06d: /* tlbie invalidate TLBs for all segments */ /* XXX: given the fact that there are too many segments to invalidate, diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1a84653983..0886f4d699 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4005,19 +4005,19 @@ static inline void gen_op_mfspr(DisasContext *ctx) * allowing userland application to read the PVR */ if (sprn != SPR_PVR) { - qemu_log("Trying to read privileged spr %d %03x at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->nip); - printf("Trying to read privileged spr %d %03x at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->nip); + qemu_log("Trying to read privileged spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); + printf("Trying to read privileged spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); } gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { /* Not defined */ - qemu_log("Trying to read invalid spr %d %03x at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->nip); - printf("Trying to read invalid spr %d %03x at " TARGET_FMT_lx "\n", - sprn, sprn, ctx->nip); + qemu_log("Trying to read invalid spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); + printf("Trying to read invalid spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR); } } @@ -4150,18 +4150,18 @@ static void gen_mtspr(DisasContext *ctx) (*write_cb)(ctx, sprn, rS(ctx->opcode)); } else { /* Privilege exception */ - qemu_log("Trying to write privileged spr %d %03x at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->nip); - printf("Trying to write privileged spr %d %03x at " TARGET_FMT_lx - "\n", sprn, sprn, ctx->nip); + qemu_log("Trying to write privileged spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); + printf("Trying to write privileged spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { /* Not defined */ - qemu_log("Trying to write invalid spr %d %03x at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->nip); - printf("Trying to write invalid spr %d %03x at " TARGET_FMT_lx "\n", - sprn, sprn, ctx->nip); + qemu_log("Trying to write invalid spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); + printf("Trying to write invalid spr %d (0x%03x) at " + TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4); gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR); } } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6feb62abcd..021a31e209 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7010,6 +7010,10 @@ static void init_proc_POWER7 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic, 0x00000000); + spr_register(env, SPR_PPR, "PPR", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); #if !defined(CONFIG_USER_ONLY) env->slb_nr = 32; #endif |