diff options
author | Blue Swirl <blauwirbel@gmail.com> | 2011-07-01 21:12:50 +0000 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2011-07-01 21:12:50 +0000 |
commit | 3b88670664f7902000b83149e7fa1875ad5c6239 (patch) | |
tree | 680e0ef80f570aed7e6c0686d7c7c7786364aa93 | |
parent | ec1884298c96a8ce723880adb9e8ffe5e71fcf37 (diff) | |
parent | 1c53accceeb01246aea0ec361e1efd15cac6db0f (diff) | |
download | qemu-3b88670664f7902000b83149e7fa1875ad5c6239.zip qemu-3b88670664f7902000b83149e7fa1875ad5c6239.tar.gz qemu-3b88670664f7902000b83149e7fa1875ad5c6239.tar.bz2 |
Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf
* 'ppc-next' of git://repo.or.cz/qemu/agraf:
PPC: move TLBs to their own arrays
PPC: 440: Use 440 style MMU as default, so Qemu knows the MMU type
PPC: E500: Use MAS registers instead of internal TLB representation
PPC: Only set lower 32bits with mtmsr
PPC: update openbios firmware
PPC: mpc8544ds: Add hypervisor node
PPC: calculate kernel,initrd,cmdline locations dynamically
target-ppc: Handle memory-forced I/O controller access
PPC: E500: Implement reboot controller
-rw-r--r-- | Makefile.target | 2 | ||||
-rw-r--r-- | hw/mpc8544_guts.c | 135 | ||||
-rw-r--r-- | hw/ppc440.c | 5 | ||||
-rw-r--r-- | hw/ppc_mac.h | 3 | ||||
-rw-r--r-- | hw/ppc_newworld.c | 15 | ||||
-rw-r--r-- | hw/ppc_oldworld.c | 15 | ||||
-rw-r--r-- | hw/ppce500_mpc8544ds.c | 46 | ||||
-rw-r--r-- | hw/virtex_ml507.c | 4 | ||||
-rw-r--r-- | pc-bios/README | 6 | ||||
-rw-r--r-- | pc-bios/mpc8544ds.dtb | bin | 12288 -> 2277 bytes | |||
-rw-r--r-- | pc-bios/mpc8544ds.dts | 9 | ||||
-rw-r--r-- | pc-bios/openbios-ppc | bin | 729876 -> 750392 bytes | |||
-rw-r--r-- | target-ppc/cpu.h | 47 | ||||
-rw-r--r-- | target-ppc/helper.c | 193 | ||||
-rw-r--r-- | target-ppc/machine.c | 16 | ||||
-rw-r--r-- | target-ppc/op_helper.c | 160 | ||||
-rw-r--r-- | target-ppc/translate.c | 17 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 27 |
18 files changed, 493 insertions, 207 deletions
diff --git a/Makefile.target b/Makefile.target index 38afdb8..a53a2ff 100644 --- a/Makefile.target +++ b/Makefile.target @@ -260,7 +260,7 @@ endif obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-ppc-y += ppc440.o ppc440_bamboo.o # PowerPC E500 boards -obj-ppc-y += ppce500_mpc8544ds.o +obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o # PowerPC 440 Xilinx ML507 reference board. obj-ppc-y += virtex_ml507.o obj-ppc-$(CONFIG_KVM) += kvm_ppc.o diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c new file mode 100644 index 0000000..c685f3e --- /dev/null +++ b/hw/mpc8544_guts.c @@ -0,0 +1,135 @@ +/* + * QEMU PowerPC MPC8544 global util pseudo-device + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Alexander Graf, <alex@csgraf.de> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ***************************************************************** + * + * The documentation for this device is noted in the MPC8544 documentation, + * file name "MPC8544ERM.pdf". You can easily find it on the web. + * + */ + +#include "hw.h" +#include "sysemu.h" +#include "sysbus.h" + +#define MPC8544_GUTS_MMIO_SIZE 0x1000 +#define MPC8544_GUTS_RSTCR_RESET 0x02 + +#define MPC8544_GUTS_ADDR_PORPLLSR 0x00 +#define MPC8544_GUTS_ADDR_PORBMSR 0x04 +#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08 +#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C +#define MPC8544_GUTS_ADDR_PORDBGMSR 0x10 +#define MPC8544_GUTS_ADDR_PORDEVSR2 0x14 +#define MPC8544_GUTS_ADDR_GPPORCR 0x20 +#define MPC8544_GUTS_ADDR_GPIOCR 0x30 +#define MPC8544_GUTS_ADDR_GPOUTDR 0x40 +#define MPC8544_GUTS_ADDR_GPINDR 0x50 +#define MPC8544_GUTS_ADDR_PMUXCR 0x60 +#define MPC8544_GUTS_ADDR_DEVDISR 0x70 +#define MPC8544_GUTS_ADDR_POWMGTCSR 0x80 +#define MPC8544_GUTS_ADDR_MCPSUMR 0x90 +#define MPC8544_GUTS_ADDR_RSTRSCR 0x94 +#define MPC8544_GUTS_ADDR_PVR 0xA0 +#define MPC8544_GUTS_ADDR_SVR 0xA4 +#define MPC8544_GUTS_ADDR_RSTCR 0xB0 +#define MPC8544_GUTS_ADDR_IOVSELSR 0xC0 +#define MPC8544_GUTS_ADDR_DDRCSR 0xB20 +#define MPC8544_GUTS_ADDR_DDRCDR 0xB24 +#define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28 +#define MPC8544_GUTS_ADDR_CLKOCR 0xE00 +#define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04 +#define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10 +#define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18 + +struct GutsState { + SysBusDevice busdev; +}; + +typedef struct GutsState GutsState; + +static uint32_t mpc8544_guts_read32(void *opaque, target_phys_addr_t addr) +{ + uint32_t value = 0; + CPUState *env = cpu_single_env; + + addr &= MPC8544_GUTS_MMIO_SIZE - 1; + switch (addr) { + case MPC8544_GUTS_ADDR_PVR: + value = env->spr[SPR_PVR]; + break; + case MPC8544_GUTS_ADDR_SVR: + value = env->spr[SPR_E500_SVR]; + break; + default: + fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr); + break; + } + + return value; +} + +static CPUReadMemoryFunc * const mpc8544_guts_read[] = { + NULL, + NULL, + &mpc8544_guts_read32, +}; + +static void mpc8544_guts_write32(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + addr &= MPC8544_GUTS_MMIO_SIZE - 1; + + switch (addr) { + case MPC8544_GUTS_ADDR_RSTCR: + if (value & MPC8544_GUTS_RSTCR_RESET) { + qemu_system_reset_request(); + } + break; + default: + fprintf(stderr, "guts: Unknown register write: %x = %x\n", + (int)addr, value); + break; + } +} + +static CPUWriteMemoryFunc * const mpc8544_guts_write[] = { + NULL, + NULL, + &mpc8544_guts_write32, +}; + +static int mpc8544_guts_initfn(SysBusDevice *dev) +{ + GutsState *s; + int iomem; + + s = FROM_SYSBUS(GutsState, sysbus_from_qdev(dev)); + + iomem = cpu_register_io_memory(mpc8544_guts_read, mpc8544_guts_write, s, + DEVICE_BIG_ENDIAN); + sysbus_init_mmio(dev, MPC8544_GUTS_MMIO_SIZE, iomem); + + return 0; +} + +static SysBusDeviceInfo mpc8544_guts_info = { + .init = mpc8544_guts_initfn, + .qdev.name = "mpc8544-guts", + .qdev.size = sizeof(GutsState), +}; + +static void mpc8544_guts_register(void) +{ + sysbus_register_withprop(&mpc8544_guts_info); +} +device_init(mpc8544_guts_register); diff --git a/hw/ppc440.c b/hw/ppc440.c index 1ed001a..90abc91 100644 --- a/hw/ppc440.c +++ b/hw/ppc440.c @@ -45,8 +45,9 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip, qemu_irq *irqs; qemu_irq *pci_irqs; - if (cpu_model == NULL) - cpu_model = "405"; // XXX: should be 440EP + if (cpu_model == NULL) { + cpu_model = "440-Xilinx"; // XXX: should be 440EP + } env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to initialize CPU!\n"); diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index ea87593..68dade7 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -35,8 +35,7 @@ #define PROM_ADDR 0xfff00000 #define KERNEL_LOAD_ADDR 0x01000000 -#define CMDLINE_ADDR 0x027ff000 -#define INITRD_LOAD_ADDR 0x02800000 +#define KERNEL_GAP 0x00100000 #define ESCC_CLOCK 3686400 diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 86f1cfb..5bce709 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -120,6 +120,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } +static target_phys_addr_t round_page(target_phys_addr_t addr) +{ + return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; +} + /* PowerPC Mac99 hardware initialisation */ static void ppc_core99_init (ram_addr_t ram_size, const char *boot_device, @@ -134,7 +139,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int unin_memory; int linux_boot, i; ram_addr_t ram_offset, bios_offset; - uint32_t kernel_base, initrd_base; + target_phys_addr_t kernel_base, initrd_base, cmdline_base = 0; long kernel_size, initrd_size; PCIBus *pci_bus; MacIONVRAMState *nvr; @@ -220,7 +225,7 @@ static void ppc_core99_init (ram_addr_t ram_size, } /* load initrd */ if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; + initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP); initrd_size = load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { @@ -228,9 +233,11 @@ static void ppc_core99_init (ram_addr_t ram_size, initrd_filename); exit(1); } + cmdline_base = round_page(initrd_base + initrd_size); } else { initrd_base = 0; initrd_size = 0; + cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP); } ppc_boot_device = 'm'; } else { @@ -373,8 +380,8 @@ static void ppc_core99_init (ram_addr_t ram_size, fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base); + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); } diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 75a3127..20cd8e1 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -59,6 +59,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; } +static target_phys_addr_t round_page(target_phys_addr_t addr) +{ + return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; +} + static void ppc_heathrow_init (ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -71,7 +76,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, qemu_irq *pic, **heathrow_irqs; int linux_boot, i; ram_addr_t ram_offset, bios_offset; - uint32_t kernel_base, initrd_base; + uint32_t kernel_base, initrd_base, cmdline_base = 0; int32_t kernel_size, initrd_size; PCIBus *pci_bus; MacIONVRAMState *nvr; @@ -157,7 +162,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, } /* load initrd */ if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; + initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP); initrd_size = load_image_targphys(initrd_filename, initrd_base, ram_size - initrd_base); if (initrd_size < 0) { @@ -165,9 +170,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size, initrd_filename); exit(1); } + cmdline_base = round_page(initrd_base + initrd_size); } else { initrd_base = 0; initrd_size = 0; + cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP); } ppc_boot_device = 'm'; } else { @@ -278,8 +285,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size, fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); - pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base); + pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); } diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index 6b57fbf..b739ce2 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -50,6 +50,7 @@ #define MPC8544_PCI_REGS_SIZE 0x1000 #define MPC8544_PCI_IO 0xE1000000 #define MPC8544_PCI_IOLEN 0x10000 +#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000) struct boot_info { @@ -81,11 +82,12 @@ out: } #endif -static int mpc8544_load_device_tree(target_phys_addr_t addr, - uint32_t ramsize, - target_phys_addr_t initrd_base, - target_phys_addr_t initrd_size, - const char *kernel_cmdline) +static int mpc8544_load_device_tree(CPUState *env, + target_phys_addr_t addr, + uint32_t ramsize, + target_phys_addr_t initrd_base, + target_phys_addr_t initrd_size, + const char *kernel_cmdline) { int ret = -1; #ifdef CONFIG_FDT @@ -93,6 +95,7 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr, char *filename; int fdt_size; void *fdt; + uint8_t hypercall[16]; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); if (!filename) { @@ -156,6 +159,13 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr, mpc8544_copy_soc_cell(fdt, buf, "clock-frequency"); mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency"); + + /* indicate KVM hypercall interface */ + qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible", + "linux,kvm"); + kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); + qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", + hypercall, sizeof(hypercall)); } else { const uint32_t freq = 400000000; @@ -175,18 +185,23 @@ out: } /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ +static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) +{ + return (ffs(size >> 10) - 1) >> 1; +} + static void mmubooke_create_initial_mapping(CPUState *env, target_ulong va, target_phys_addr_t pa) { - ppcemb_tlb_t *tlb = booke206_get_tlbe(env, 1, 0, 0); - - tlb->attr = 0; - tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); - tlb->size = 256 * 1024 * 1024; - tlb->EPN = va & TARGET_PAGE_MASK; - tlb->RPN = pa & TARGET_PAGE_MASK; - tlb->PID = 0; + ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); + target_phys_addr_t size; + + size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT); + tlb->mas1 = MAS1_VALID | size; + tlb->mas2 = va & TARGET_PAGE_MASK; + tlb->mas7_3 = pa & TARGET_PAGE_MASK; + tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; } static void mpc8544ds_cpu_reset(void *opaque) @@ -270,6 +285,9 @@ static void mpc8544ds_init(ram_addr_t ram_size, serial_hds[0], 1, 1); } + /* General Utility device */ + sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL); + /* PCI */ dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE, mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]], @@ -326,7 +344,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); #endif dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; - if (mpc8544_load_device_tree(dt_base, ram_size, + if (mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base, initrd_size, kernel_cmdline) < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index fa60515..7bde8c7 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -60,7 +60,7 @@ static void mmubooke_create_initial_mapping(CPUState *env, target_ulong va, target_phys_addr_t pa) { - ppcemb_tlb_t *tlb = &env->tlb[0].tlbe; + ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; tlb->attr = 0; tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); @@ -69,7 +69,7 @@ static void mmubooke_create_initial_mapping(CPUState *env, tlb->RPN = pa & TARGET_PAGE_MASK; tlb->PID = 0; - tlb = &env->tlb[1].tlbe; + tlb = &env->tlb.tlbe[1]; tlb->attr = 0; tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); tlb->size = 1 << 31; /* up to 0xffffffff */ diff --git a/pc-bios/README b/pc-bios/README index fe221a9..40568f8 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -10,8 +10,10 @@ - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable firmware implementation. The goal is to implement a 100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware. - The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32 - and Sparc64 are built from OpenBIOS SVN revision 1018. + The included image for PowerPC (for 32 and 64 bit PPC CPUs), + + PowerPC is built from OpenBIOS SVN revision 1044 + Sparc32 and Sparc64 are built from OpenBIOS SVN revision 1018. - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb Binary files differindex 3299546..ae318b1 100644 --- a/pc-bios/mpc8544ds.dtb +++ b/pc-bios/mpc8544ds.dtb diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts index 872152d..a88b47c 100644 --- a/pc-bios/mpc8544ds.dts +++ b/pc-bios/mpc8544ds.dts @@ -82,6 +82,12 @@ compatible = "chrp,open-pic"; device_type = "open-pic"; }; + + global-utilities@e0000 { //global utilities block + compatible = "fsl,mpc8544-guts"; + reg = <0xe0000 0x1000>; + fsl,has-rstcr; + }; }; pci0: pci@e0008000 { @@ -119,4 +125,7 @@ chosen { linux,stdout-path = "/soc8544@e0000000/serial@4500"; }; + + hypervisor { + }; }; diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex ee6f5ae..6525a91 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6d60d14..84f8ff6 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -360,10 +360,24 @@ struct ppcemb_tlb_t { uint32_t attr; /* Storage attributes */ }; +typedef struct ppcmas_tlb_t { + uint32_t mas8; + uint32_t mas1; + uint64_t mas2; + uint64_t mas7_3; +} ppcmas_tlb_t; + union ppc_tlb_t { - ppc6xx_tlb_t tlb6; - ppcemb_tlb_t tlbe; + ppc6xx_tlb_t *tlb6; + ppcemb_tlb_t *tlbe; + ppcmas_tlb_t *tlbm; }; + +/* possible TLB variants */ +#define TLB_NONE 0 +#define TLB_6XX 1 +#define TLB_EMB 2 +#define TLB_MAS 3 #endif #define SDR_32_HTABORG 0xFFFF0000UL @@ -903,7 +917,8 @@ struct CPUPPCState { int last_way; /* Last used way used to allocate TLB in a LRU way */ int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ int nb_pids; /* Number of available PID registers */ - ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ + int tlb_type; /* Type of TLB we're dealing with */ + ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */ /* 403 dedicated access protection registers */ target_ulong pb[4]; #endif @@ -1075,9 +1090,13 @@ void store_40x_sler (CPUPPCState *env, uint32_t val); void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot); +target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb); int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb, target_phys_addr_t *raddrp, target_ulong address, uint32_t pid, int ext, int i); +int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddrp, target_ulong address, + uint32_t pid); void ppc_tlb_invalidate_all (CPUPPCState *env); void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); #if defined(TARGET_PPC64) @@ -1927,12 +1946,12 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls) } #if !defined(CONFIG_USER_ONLY) -static inline int booke206_tlbe_id(CPUState *env, ppcemb_tlb_t *tlbe) +static inline int booke206_tlbm_id(CPUState *env, ppcmas_tlb_t *tlbm) { - uintptr_t tlbel = (uintptr_t)tlbe; - uintptr_t tlbl = (uintptr_t)env->tlb; + uintptr_t tlbml = (uintptr_t)tlbm; + uintptr_t tlbl = (uintptr_t)env->tlb.tlbm; - return (tlbel - tlbl) / sizeof(env->tlb[0]); + return (tlbml - tlbl) / sizeof(env->tlb.tlbm[0]); } static inline int booke206_tlb_size(CPUState *env, int tlbn) @@ -1949,9 +1968,9 @@ static inline int booke206_tlb_ways(CPUState *env, int tlbn) return r; } -static inline int booke206_tlbe_to_tlbn(CPUState *env, ppcemb_tlb_t *tlbe) +static inline int booke206_tlbm_to_tlbn(CPUState *env, ppcmas_tlb_t *tlbm) { - int id = booke206_tlbe_id(env, tlbe); + int id = booke206_tlbm_id(env, tlbm); int end = 0; int i; @@ -1966,14 +1985,14 @@ static inline int booke206_tlbe_to_tlbn(CPUState *env, ppcemb_tlb_t *tlbe) return 0; } -static inline int booke206_tlbe_to_way(CPUState *env, ppcemb_tlb_t *tlb) +static inline int booke206_tlbm_to_way(CPUState *env, ppcmas_tlb_t *tlb) { - int tlbn = booke206_tlbe_to_tlbn(env, tlb); - int tlbid = booke206_tlbe_id(env, tlb); + int tlbn = booke206_tlbm_to_tlbn(env, tlb); + int tlbid = booke206_tlbm_id(env, tlb); return tlbid & (booke206_tlb_ways(env, tlbn) - 1); } -static inline ppcemb_tlb_t *booke206_get_tlbe(CPUState *env, const int tlbn, +static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn, target_ulong ea, int way) { int r; @@ -1992,7 +2011,7 @@ static inline ppcemb_tlb_t *booke206_get_tlbe(CPUState *env, const int tlbn, r += booke206_tlb_size(env, i); } - return &env->tlb[r].tlbe; + return &env->tlb.tlbm[r]; } #endif diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 395ea0e..176128a 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -322,7 +322,7 @@ static inline void ppc6xx_tlb_invalidate_all(CPUState *env) if (env->id_tlbs == 1) max *= 2; for (nr = 0; nr < max; nr++) { - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; pte_invalidate(&tlb->pte0); } tlb_flush(env, 1); @@ -339,7 +339,7 @@ static inline void __ppc6xx_tlb_invalidate_virt(CPUState *env, /* Invalidate ITLB + DTLB, all ways */ for (way = 0; way < env->nb_ways; way++) { nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) { LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr, env->nb_tlb, eaddr); @@ -366,7 +366,7 @@ void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code, int nr; nr = ppc6xx_tlb_getnum(env, EPN, way, is_code); - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1); /* Invalidate any pending reference in Qemu for this virtual address */ @@ -390,7 +390,7 @@ static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx, for (way = 0; way < env->nb_ways; way++) { nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == ACCESS_CODE ? 1 : 0); - tlb = &env->tlb[nr].tlb6; + tlb = &env->tlb.tlb6[nr]; /* This test "emulates" the PTE index match for hardware TLBs */ if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx @@ -433,7 +433,7 @@ static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx, LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n", ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); /* Update page flags */ - pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw); + pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw); } return ret; @@ -948,8 +948,24 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, ret = -3; } } else { + target_ulong sr; LOG_MMU("direct store...\n"); /* Direct-store segment : absolutely *BUGGY* for now */ + + /* Direct-store implies a 32-bit MMU. + * Check the Segment Register's bus unit ID (BUID). + */ + sr = env->sr[eaddr >> 28]; + if ((sr & 0x1FF00000) >> 20 == 0x07f) { + /* Memory-forced I/O controller interface access */ + /* If T=1 and BUID=x'07F', the 601 performs a memory access + * to SR[28-31] LA[4-31], bypassing all protection mechanisms. + */ + ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); + ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return 0; + } + switch (type) { case ACCESS_INT: /* Integer load/store : only access allowed */ @@ -1032,7 +1048,7 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid) /* Default return value is no match */ ret = -1; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { ret = i; break; @@ -1049,7 +1065,7 @@ static inline void ppc4xx_tlb_invalidate_all(CPUState *env) int i; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; tlb->prot &= ~PAGE_VALID; } tlb_flush(env, 1); @@ -1065,7 +1081,7 @@ static inline void ppc4xx_tlb_invalidate_virt(CPUState *env, int i; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) @@ -1090,7 +1106,7 @@ static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, raddr = (target_phys_addr_t)-1ULL; pr = msr_pr; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; if (ppcemb_tlb_check(env, tlb, &raddr, address, env->spr[SPR_40x_PID], 0, i) < 0) continue; @@ -1231,7 +1247,7 @@ static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, ret = -1; raddr = (target_phys_addr_t)-1ULL; for (i = 0; i < env->nb_tlb; i++) { - tlb = &env->tlb[i].tlbe; + tlb = &env->tlb.tlbe[i]; ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, access_type, i); if (!ret) { @@ -1256,14 +1272,14 @@ void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot) { int tlb_size; int i, j; - ppc_tlb_t *tlb = env->tlb; + ppcmas_tlb_t *tlb = env->tlb.tlbm; for (i = 0; i < BOOKE206_MAX_TLBN; i++) { if (flags & (1 << i)) { tlb_size = booke206_tlb_size(env, i); for (j = 0; j < tlb_size; j++) { - if (!check_iprot || !(tlb[j].tlbe.attr & MAS1_IPROT)) { - tlb[j].tlbe.prot = 0; + if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) { + tlb[j].mas1 &= ~MAS1_VALID; } } } @@ -1273,11 +1289,148 @@ void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot) tlb_flush(env, 1); } +target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb) +{ + uint32_t tlbncfg; + int tlbn = booke206_tlbm_to_tlbn(env, tlb); + target_phys_addr_t tlbm_size; + + tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn]; + + if (tlbncfg & TLBnCFG_AVAIL) { + tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT; + } else { + tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; + } + + return (1 << (tlbm_size << 1)) << 10; +} + +/* TLB check function for MAS based SoftTLBs */ +int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddrp, + target_ulong address, uint32_t pid) +{ + target_ulong mask; + uint32_t tlb_pid; + + /* Check valid flag */ + if (!(tlb->mas1 & MAS1_VALID)) { + return -1; + } + + mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); + LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%" + PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n", + __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3, + tlb->mas8); + + /* Check PID */ + tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT; + if (tlb_pid != 0 && tlb_pid != pid) { + return -1; + } + + /* Check effective address */ + if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) { + return -1; + } + *raddrp = (tlb->mas7_3 & mask) | (address & ~mask); + + return 0; +} + +static int mmubooke206_check_tlb(CPUState *env, ppcmas_tlb_t *tlb, + target_phys_addr_t *raddr, int *prot, + target_ulong address, int rw, + int access_type) +{ + int ret; + int _prot = 0; + + if (ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID]) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID1] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID1]) >= 0) { + goto found_tlb; + } + + if (env->spr[SPR_BOOKE_PID2] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID2]) >= 0) { + goto found_tlb; + } + + LOG_SWTLB("%s: TLB entry not found\n", __func__); + return -1; + +found_tlb: + + if (msr_pr != 0) { + if (tlb->mas7_3 & MAS3_UR) { + _prot |= PAGE_READ; + } + if (tlb->mas7_3 & MAS3_UW) { + _prot |= PAGE_WRITE; + } + if (tlb->mas7_3 & MAS3_UX) { + _prot |= PAGE_EXEC; + } + } else { + if (tlb->mas7_3 & MAS3_SR) { + _prot |= PAGE_READ; + } + if (tlb->mas7_3 & MAS3_SW) { + _prot |= PAGE_WRITE; + } + if (tlb->mas7_3 & MAS3_SX) { + _prot |= PAGE_EXEC; + } + } + + /* Check the address space and permissions */ + if (access_type == ACCESS_CODE) { + if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = _prot; + if (_prot & PAGE_EXEC) { + LOG_SWTLB("%s: good TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot); + ret = -3; + } else { + if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + LOG_SWTLB("%s: AS doesn't match\n", __func__); + return -1; + } + + *prot = _prot; + if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) { + LOG_SWTLB("%s: found TLB!\n", __func__); + return 0; + } + + LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot); + ret = -2; + } + + return ret; +} + static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx, - target_ulong address, int rw, - int access_type) + target_ulong address, int rw, + int access_type) { - ppcemb_tlb_t *tlb; + ppcmas_tlb_t *tlb; target_phys_addr_t raddr; int i, j, ret; @@ -1288,9 +1441,9 @@ static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx, int ways = booke206_tlb_ways(env, i); for (j = 0; j < ways; j++) { - tlb = booke206_get_tlbe(env, i, address, j); - ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, - access_type, j); + tlb = booke206_get_tlbm(env, i, address, j); + ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, + rw, access_type); if (ret != -1) { goto found_tlb; } @@ -1395,7 +1548,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, rw, access_type); } else if (env->mmu_model == POWERPC_MMU_BOOKE206) { ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type); + access_type); } else { /* No address translation. */ ret = check_physical(env, ctx, eaddr, rw); diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 0c1986e..1c40d43 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -52,12 +52,12 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_sbe32s(f, &env->last_way); qemu_put_sbe32s(f, &env->id_tlbs); qemu_put_sbe32s(f, &env->nb_pids); - if (env->tlb) { + if (env->tlb.tlb6) { // XXX assumes 6xx for (i = 0; i < env->nb_tlb; i++) { - qemu_put_betls(f, &env->tlb[i].tlb6.pte0); - qemu_put_betls(f, &env->tlb[i].tlb6.pte1); - qemu_put_betls(f, &env->tlb[i].tlb6.EPN); + qemu_put_betls(f, &env->tlb.tlb6[i].pte0); + qemu_put_betls(f, &env->tlb.tlb6[i].pte1); + qemu_put_betls(f, &env->tlb.tlb6[i].EPN); } } for (i = 0; i < 4; i++) @@ -140,12 +140,12 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &env->last_way); qemu_get_sbe32s(f, &env->id_tlbs); qemu_get_sbe32s(f, &env->nb_pids); - if (env->tlb) { + if (env->tlb.tlb6) { // XXX assumes 6xx for (i = 0; i < env->nb_tlb; i++) { - qemu_get_betls(f, &env->tlb[i].tlb6.pte0); - qemu_get_betls(f, &env->tlb[i].tlb6.pte1); - qemu_get_betls(f, &env->tlb[i].tlb6.EPN); + qemu_get_betls(f, &env->tlb.tlb6[i].pte0); + qemu_get_betls(f, &env->tlb.tlb6[i].pte1); + qemu_get_betls(f, &env->tlb.tlb6[i].EPN); } } for (i = 0; i < 4; i++) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 29f72e1..dde7595 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -3959,7 +3959,7 @@ target_ulong helper_4xx_tlbre_hi (target_ulong entry) int size; entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; ret = tlb->EPN; if (tlb->prot & PAGE_VALID) { ret |= PPC4XX_TLBHI_V; @@ -3979,7 +3979,7 @@ target_ulong helper_4xx_tlbre_lo (target_ulong entry) target_ulong ret; entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; ret = tlb->RPN; if (tlb->prot & PAGE_EXEC) { ret |= PPC4XX_TLBLO_EX; @@ -3998,7 +3998,7 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val) LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry, val); entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; /* Invalidate previous TLB (if it's valid) */ if (tlb->prot & PAGE_VALID) { end = tlb->EPN + tlb->size; @@ -4056,7 +4056,7 @@ void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val) LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry, val); entry &= PPC4XX_TLB_ENTRY_MASK; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK; tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK; tlb->prot = PAGE_READ; @@ -4091,7 +4091,7 @@ void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value) __func__, word, (int)entry, value); do_flush_tlbs = 0; entry &= 0x3F; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; switch (word) { default: /* Just here to please gcc */ @@ -4150,7 +4150,7 @@ target_ulong helper_440_tlbre (uint32_t word, target_ulong entry) int size; entry &= 0x3F; - tlb = &env->tlb[entry].tlbe; + tlb = &env->tlb.tlbe[entry]; switch (word) { default: /* Just here to please gcc */ @@ -4196,7 +4196,7 @@ target_ulong helper_440_tlbsx (target_ulong address) /* PowerPC BookE 2.06 TLB management */ -static ppcemb_tlb_t *booke206_cur_tlb(CPUState *env) +static ppcmas_tlb_t *booke206_cur_tlb(CPUState *env) { uint32_t tlbncfg = 0; int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT; @@ -4210,17 +4210,7 @@ static ppcemb_tlb_t *booke206_cur_tlb(CPUState *env) cpu_abort(env, "we don't support HES yet\n"); } - return booke206_get_tlbe(env, tlb, ea, esel); -} - -static inline target_phys_addr_t booke206_tlb_to_page_size(int size) -{ - return (1 << (size << 1)) << 10; -} - -static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) -{ - return (ffs(size >> 10) - 1) >> 1; + return booke206_get_tlbm(env, tlb, ea, esel); } void helper_booke_setpid(uint32_t pidn, target_ulong pid) @@ -4233,9 +4223,7 @@ void helper_booke_setpid(uint32_t pidn, target_ulong pid) void helper_booke206_tlbwe(void) { uint32_t tlbncfg, tlbn; - ppcemb_tlb_t *tlb; - target_phys_addr_t rpn; - int tlbe_size; + ppcmas_tlb_t *tlb; switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) { case MAS0_WQ_ALWAYS: @@ -4269,116 +4257,43 @@ void helper_booke206_tlbwe(void) if (msr_gs) { cpu_abort(env, "missing HV implementation\n"); - } else { - rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | - (env->spr[SPR_BOOKE_MAS3] & 0xfffff000); - } - tlb->RPN = rpn; - - tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT; - if (tlbncfg & TLBnCFG_AVAIL) { - tlbe_size = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) - >> MAS1_TSIZE_SHIFT; - } else { - tlbe_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT; } + tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) | + env->spr[SPR_BOOKE_MAS3]; + tlb->mas1 = env->spr[SPR_BOOKE_MAS1]; + /* XXX needs to change when supporting 64-bit e500 */ + tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff; - tlb->size = booke206_tlb_to_page_size(tlbe_size); - tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK); - tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W | - MAS2_I | MAS2_M | MAS2_G | MAS2_E) - << 1; - - if (tlbncfg & TLBnCFG_IPROT) { - tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT; - } - tlb->attr |= (env->spr[SPR_BOOKE_MAS3] & - ((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8); - if (env->spr[SPR_BOOKE_MAS1] & MAS1_TS) { - tlb->attr |= 1; - } - - tlb->prot = 0; - - if (env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) { - tlb->prot |= PAGE_VALID; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_UX) { - tlb->prot |= PAGE_EXEC; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_SX) { - tlb->prot |= PAGE_EXEC << 4; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_UW) { - tlb->prot |= PAGE_WRITE; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_SW) { - tlb->prot |= PAGE_WRITE << 4; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_UR) { - tlb->prot |= PAGE_READ; - } - if (env->spr[SPR_BOOKE_MAS3] & MAS3_SR) { - tlb->prot |= PAGE_READ << 4; + if (!(tlbncfg & TLBnCFG_IPROT)) { + /* no IPROT supported by TLB */ + tlb->mas1 &= ~MAS1_IPROT; } - if (tlb->size == TARGET_PAGE_SIZE) { - tlb_flush_page(env, tlb->EPN); + if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) { + tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK); } else { tlb_flush(env, 1); } } -static inline void booke206_tlb_to_mas(CPUState *env, ppcemb_tlb_t *tlb) +static inline void booke206_tlb_to_mas(CPUState *env, ppcmas_tlb_t *tlb) { - int tlbn = booke206_tlbe_to_tlbn(env, tlb); - int way = booke206_tlbe_to_way(env, tlb); + int tlbn = booke206_tlbm_to_tlbn(env, tlb); + int way = booke206_tlbm_to_way(env, tlb); env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT; env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT; - - env->spr[SPR_BOOKE_MAS1] = MAS1_VALID; - env->spr[SPR_BOOKE_MAS2] = 0; - - env->spr[SPR_BOOKE_MAS7] = (uint64_t)tlb->RPN >> 32; - env->spr[SPR_BOOKE_MAS3] = tlb->RPN; - env->spr[SPR_BOOKE_MAS1] |= tlb->PID << MAS1_TID_SHIFT; - env->spr[SPR_BOOKE_MAS1] |= booke206_page_size_to_tlb(tlb->size) - << MAS1_TSIZE_SHIFT; - env->spr[SPR_BOOKE_MAS1] |= tlb->attr & MAS1_IPROT; - if (tlb->attr & 1) { - env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; - } - - env->spr[SPR_BOOKE_MAS2] = tlb->EPN; - env->spr[SPR_BOOKE_MAS2] |= (tlb->attr >> 1) & - (MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E); - - if (tlb->prot & PAGE_EXEC) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_UX; - } - if (tlb->prot & (PAGE_EXEC << 4)) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_SX; - } - if (tlb->prot & PAGE_WRITE) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_UW; - } - if (tlb->prot & (PAGE_WRITE << 4)) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_SW; - } - if (tlb->prot & PAGE_READ) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_UR; - } - if (tlb->prot & (PAGE_READ << 4)) { - env->spr[SPR_BOOKE_MAS3] |= MAS3_SR; - } - env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT; + + env->spr[SPR_BOOKE_MAS1] = tlb->mas1; + env->spr[SPR_BOOKE_MAS2] = tlb->mas2; + env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3; + env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32; } void helper_booke206_tlbre(void) { - ppcemb_tlb_t *tlb = NULL; + ppcmas_tlb_t *tlb = NULL; tlb = booke206_cur_tlb(env); booke206_tlb_to_mas(env, tlb); @@ -4386,7 +4301,7 @@ void helper_booke206_tlbre(void) void helper_booke206_tlbsx(target_ulong address) { - ppcemb_tlb_t *tlb = NULL; + ppcmas_tlb_t *tlb = NULL; int i, j; target_phys_addr_t raddr; uint32_t spid, sas; @@ -4398,13 +4313,13 @@ void helper_booke206_tlbsx(target_ulong address) int ways = booke206_tlb_ways(env, i); for (j = 0; j < ways; j++) { - tlb = booke206_get_tlbe(env, i, address, j); + tlb = booke206_get_tlbm(env, i, address, j); - if (ppcemb_tlb_check(env, tlb, &raddr, address, spid, 0, j)) { + if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) { continue; } - if (sas != (tlb->attr & MAS6_SAS)) { + if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { continue; } @@ -4439,13 +4354,14 @@ static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn, { int i; int ways = booke206_tlb_ways(env, tlbn); + target_ulong mask; for (i = 0; i < ways; i++) { - ppcemb_tlb_t *tlb = booke206_get_tlbe(env, tlbn, ea, i); - target_phys_addr_t masked_ea = ea & ~(tlb->size - 1); - if ((tlb->EPN == (masked_ea >> MAS2_EPN_SHIFT)) && - !(tlb->attr & MAS1_IPROT)) { - tlb->prot = 0; + ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i); + mask = ~(booke206_tlb_to_page_size(env, tlb) - 1); + if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) && + !(tlb->mas1 & MAS1_IPROT)) { + tlb->mas1 &= ~MAS1_VALID; } } } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0a03b44..fd7c208 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3877,24 +3877,19 @@ static void gen_mtmsr(DisasContext *ctx) tcg_gen_or_tl(cpu_msr, cpu_msr, t0); tcg_temp_free(t0); } else { + TCGv msr = tcg_temp_new(); + /* XXX: we need to update nip before the store * if we enter power saving mode, we will exit the loop * directly from ppc_store_msr */ gen_update_nip(ctx, ctx->nip); #if defined(TARGET_PPC64) - if (!ctx->sf_mode) { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_msr, 0xFFFFFFFF00000000ULL); - tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]); - tcg_gen_or_tl(t0, t0, t1); - tcg_temp_free(t1); - gen_helper_store_msr(t0); - tcg_temp_free(t0); - } else + tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32); +#else + tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]); #endif - gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]); + gen_helper_store_msr(msr); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index fc50ae3..f542b8e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -844,6 +844,7 @@ static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) env->nb_tlb = nb_tlbs; env->nb_ways = nb_ways; env->id_tlbs = 1; + env->tlb_type = TLB_6XX; spr_register(env, SPR_DMISS, "DMISS", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, @@ -1337,6 +1338,7 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) env->nb_tlb = nb_tlbs; env->nb_ways = nb_ways; env->id_tlbs = 1; + env->tlb_type = TLB_6XX; /* XXX : not implemented */ spr_register(env, SPR_PTEHI, "PTEHI", SPR_NOACCESS, SPR_NOACCESS, @@ -3282,6 +3284,7 @@ static void init_proc_401x2 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3352,6 +3355,7 @@ static void init_proc_IOP480 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3431,6 +3435,7 @@ static void init_proc_403GCX (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3479,6 +3484,7 @@ static void init_proc_405 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_4xx_softmmu(env); env->dcache_line_size = 32; @@ -3561,6 +3567,7 @@ static void init_proc_440EP (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3624,6 +3631,7 @@ static void init_proc_440GP (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3687,6 +3695,7 @@ static void init_proc_440x4 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3767,6 +3776,7 @@ static void init_proc_440x5 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3854,6 +3864,7 @@ static void init_proc_460 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -3944,6 +3955,7 @@ static void init_proc_460F (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_BookE(env); env->dcache_line_size = 32; @@ -4251,6 +4263,7 @@ static void init_proc_e200 (CPUPPCState *env) env->nb_tlb = 64; env->nb_ways = 1; env->id_tlbs = 0; + env->tlb_type = TLB_EMB; #endif init_excp_e200(env); env->dcache_line_size = 32; @@ -4464,6 +4477,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) #if !defined(CONFIG_USER_ONLY) env->nb_tlb = 0; + env->tlb_type = TLB_MAS; for (i = 0; i < BOOKE206_MAX_TLBN; i++) { env->nb_tlb += booke206_tlb_size(env, i); } @@ -9186,6 +9200,7 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) env->nb_BATs = 0; env->nb_tlb = 0; env->nb_ways = 0; + env->tlb_type = TLB_NONE; #endif /* Register SPR common to all PowerPC implementations */ gen_spr_generic(env); @@ -9310,7 +9325,17 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) int nb_tlb = env->nb_tlb; if (env->id_tlbs != 0) nb_tlb *= 2; - env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t)); + switch (env->tlb_type) { + case TLB_6XX: + env->tlb.tlb6 = qemu_mallocz(nb_tlb * sizeof(ppc6xx_tlb_t)); + break; + case TLB_EMB: + env->tlb.tlbe = qemu_mallocz(nb_tlb * sizeof(ppcemb_tlb_t)); + break; + case TLB_MAS: + env->tlb.tlbm = qemu_mallocz(nb_tlb * sizeof(ppcmas_tlb_t)); + break; + } /* Pre-compute some useful values */ env->tlb_per_way = env->nb_tlb / env->nb_ways; } |