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
This commit is contained in:
Blue Swirl 2011-07-01 21:12:50 +00:00
commit 3b88670664
18 changed files with 493 additions and 207 deletions

View File

@ -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

135
hw/mpc8544_guts.c Normal file
View File

@ -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);

View File

@ -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");

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
target_phys_addr_t size;
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;
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);

View File

@ -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 */

View File

@ -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

Binary file not shown.

View File

@ -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 {
};
};

Binary file not shown.

View File

@ -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

View File

@ -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);
}
static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
target_ulong address, int rw,
int access_type)
target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
{
ppcemb_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)
{
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);

View File

@ -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++)

View File

@ -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->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->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;
if (!(tlbncfg & TLBnCFG_IPROT)) {
/* no IPROT supported by TLB */
tlb->mas1 &= ~MAS1_IPROT;
}
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 (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;
}
}
}

View File

@ -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);

View File

@ -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;
}