mirror of
https://github.com/qemu/qemu.git
synced 2025-01-23 14:03:25 +08:00
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:
commit
3b88670664
@ -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
135
hw/mpc8544_guts.c
Normal 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);
|
@ -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");
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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.
@ -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.
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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++)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user