提交 0f6bcf68 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/artyom/tags/pull-sun4v-20170118' into staging

add OpenSPARC T1 emulation

# gpg: Signature made Wed 18 Jan 2017 22:25:47 GMT
# gpg:                using RSA key 0x3360C3F7411A125F
# gpg: Good signature from "Artyom Tarasenko <atar4qemu@gmail.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 2AD8 6149 17F4 B2D7 05C0  BB12 3360 C3F7 411A 125F

* remotes/artyom/tags/pull-sun4v-20170118: (30 commits)
  target-sparc: fix up niagara machine
  target-sparc: move common cpu initialisation routines to sparc64.c
  target-sparc: implement sun4v RTC
  target-sparc: add ST_BLKINIT_ ASIs for UA2005+ CPUs
  target-sparc: store the UA2005 entries in sun4u format
  target-sparc: implement UA2005 ASI_MMU (0x21)
  target-sparc: add more registers to dump_mmu
  target-sparc: implement auto-demapping for UA2005 CPUs
  target-sparc: allow 256M sized pages
  target-sparc: simplify ultrasparc_tsb_pointer
  target-sparc: implement UA2005 TSB Pointers
  target-sparc: use SparcV9MMU type for sparc64 I/D-MMUs
  target-sparc: replace the last tlb entry when no free entries left
  target-sparc: ignore writes to UA2005 CPU mondo queue register
  target-sparc: allow priveleged ASIs in hyperprivileged mode
  target-sparc: use direct address translation in hyperprivileged mode
  target-sparc: fix immediate UA2005 traps
  target-sparc: implement UA2005 rdhpstate and wrhpstate instructions
  target-sparc: implement UA2005 GL register
  target-sparc: implement UA2005 hypervisor traps
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -725,6 +725,13 @@ S: Maintained ...@@ -725,6 +725,13 @@ S: Maintained
F: hw/sparc64/sun4u.c F: hw/sparc64/sun4u.c
F: pc-bios/openbios-sparc64 F: pc-bios/openbios-sparc64
Sun4v
M: Artyom Tarasenko <atar4qemu@gmail.com>
S: Maintained
F: hw/sparc64/sun4v.c
F: hw/timer/sun4v-rtc.c
F: include/hw/timer/sun4v-rtc.h
Leon3 Leon3
M: Fabien Chouteau <chouteau@adacore.com> M: Fabien Chouteau <chouteau@adacore.com>
S: Maintained S: Maintained
......
...@@ -13,3 +13,5 @@ CONFIG_IDE_CMD646=y ...@@ -13,3 +13,5 @@ CONFIG_IDE_CMD646=y
CONFIG_PCI_APB=y CONFIG_PCI_APB=y
CONFIG_MC146818RTC=y CONFIG_MC146818RTC=y
CONFIG_ISA_TESTDEV=y CONFIG_ISA_TESTDEV=y
CONFIG_EMPTY_SLOT=y
CONFIG_SUN4V_RTC=y
obj-y += sparc64.o
obj-y += sun4u.o obj-y += sun4u.o
obj-y += niagara.o
\ No newline at end of file
/*
* QEMU Sun4v/Niagara System Emulator
*
* Copyright (c) 2016 Artyom Tarasenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/boards.h"
#include "hw/char/serial.h"
#include "hw/empty_slot.h"
#include "hw/loader.h"
#include "hw/sparc/sparc64.h"
#include "hw/timer/sun4v-rtc.h"
#include "exec/address-spaces.h"
#include "sysemu/block-backend.h"
typedef struct NiagaraBoardState {
MemoryRegion hv_ram;
MemoryRegion partition_ram;
MemoryRegion nvram;
MemoryRegion md_rom;
MemoryRegion hv_rom;
MemoryRegion vdisk_ram;
MemoryRegion prom;
} NiagaraBoardState;
#define NIAGARA_HV_RAM_BASE 0x100000ULL
#define NIAGARA_HV_RAM_SIZE 0x3f00000ULL /* 63 MiB */
#define NIAGARA_PARTITION_RAM_BASE 0x80000000ULL
#define NIAGARA_UART_BASE 0x1f10000000ULL
#define NIAGARA_NVRAM_BASE 0x1f11000000ULL
#define NIAGARA_NVRAM_SIZE 0x2000
#define NIAGARA_MD_ROM_BASE 0x1f12000000ULL
#define NIAGARA_MD_ROM_SIZE 0x2000
#define NIAGARA_HV_ROM_BASE 0x1f12080000ULL
#define NIAGARA_HV_ROM_SIZE 0x2000
#define NIAGARA_IOBBASE 0x9800000000ULL
#define NIAGARA_IOBSIZE 0x0100000000ULL
#define NIAGARA_VDISK_BASE 0x1f40000000ULL
#define NIAGARA_RTC_BASE 0xfff0c1fff8ULL
#define NIAGARA_UART_BASE 0x1f10000000ULL
/* Firmware layout
*
* |------------------|
* | openboot.bin |
* |------------------| PROM_ADDR + OBP_OFFSET
* | q.bin |
* |------------------| PROM_ADDR + Q_OFFSET
* | reset.bin |
* |------------------| PROM_ADDR
*/
#define NIAGARA_PROM_BASE 0xfff0000000ULL
#define NIAGARA_Q_OFFSET 0x10000ULL
#define NIAGARA_OBP_OFFSET 0x80000ULL
#define PROM_SIZE_MAX (4 * 1024 * 1024)
/* Niagara hardware initialisation */
static void niagara_init(MachineState *machine)
{
NiagaraBoardState *s = g_new(NiagaraBoardState, 1);
DriveInfo *dinfo = drive_get_next(IF_PFLASH);
MemoryRegion *sysmem = get_system_memory();
/* init CPUs */
sparc64_cpu_devinit(machine->cpu_model, "Sun UltraSparc T1",
NIAGARA_PROM_BASE);
/* set up devices */
memory_region_allocate_system_memory(&s->hv_ram, NULL, "sun4v-hv.ram",
NIAGARA_HV_RAM_SIZE);
memory_region_add_subregion(sysmem, NIAGARA_HV_RAM_BASE, &s->hv_ram);
memory_region_allocate_system_memory(&s->partition_ram, NULL,
"sun4v-partition.ram",
machine->ram_size);
memory_region_add_subregion(sysmem, NIAGARA_PARTITION_RAM_BASE,
&s->partition_ram);
memory_region_allocate_system_memory(&s->nvram, NULL,
"sun4v.nvram", NIAGARA_NVRAM_SIZE);
memory_region_add_subregion(sysmem, NIAGARA_NVRAM_BASE, &s->nvram);
memory_region_allocate_system_memory(&s->md_rom, NULL,
"sun4v-md.rom", NIAGARA_MD_ROM_SIZE);
memory_region_add_subregion(sysmem, NIAGARA_MD_ROM_BASE, &s->md_rom);
memory_region_allocate_system_memory(&s->hv_rom, NULL,
"sun4v-hv.rom", NIAGARA_HV_ROM_SIZE);
memory_region_add_subregion(sysmem, NIAGARA_HV_ROM_BASE, &s->hv_rom);
memory_region_allocate_system_memory(&s->prom, NULL,
"sun4v.prom", PROM_SIZE_MAX);
memory_region_add_subregion(sysmem, NIAGARA_PROM_BASE, &s->prom);
rom_add_file_fixed("nvram1", NIAGARA_NVRAM_BASE, -1);
rom_add_file_fixed("1up-md.bin", NIAGARA_MD_ROM_BASE, -1);
rom_add_file_fixed("1up-hv.bin", NIAGARA_HV_ROM_BASE, -1);
rom_add_file_fixed("reset.bin", NIAGARA_PROM_BASE, -1);
rom_add_file_fixed("q.bin", NIAGARA_PROM_BASE + NIAGARA_Q_OFFSET, -1);
rom_add_file_fixed("openboot.bin", NIAGARA_PROM_BASE + NIAGARA_OBP_OFFSET,
-1);
/* the virtual ramdisk is kind of initrd, but it resides
outside of the partition RAM */
if (dinfo) {
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
int size = blk_getlength(blk);
if (size > 0) {
memory_region_allocate_system_memory(&s->vdisk_ram, NULL,
"sun4v_vdisk.ram", size);
memory_region_add_subregion(get_system_memory(),
NIAGARA_VDISK_BASE, &s->vdisk_ram);
dinfo->is_default = 1;
rom_add_file_fixed(blk_bs(blk)->filename, NIAGARA_VDISK_BASE, -1);
} else {
fprintf(stderr, "qemu: could not load ram disk '%s'\n",
blk_bs(blk)->filename);
exit(1);
}
}
serial_mm_init(sysmem, NIAGARA_UART_BASE, 0, NULL, 115200,
serial_hds[0], DEVICE_BIG_ENDIAN);
empty_slot_init(NIAGARA_IOBBASE, NIAGARA_IOBSIZE);
sun4v_rtc_init(NIAGARA_RTC_BASE);
}
static void niagara_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Sun4v platform, Niagara";
mc->init = niagara_init;
mc->max_cpus = 1; /* XXX for now */
mc->default_boot_order = "c";
}
static const TypeInfo niagara_type = {
.name = MACHINE_TYPE_NAME("niagara"),
.parent = TYPE_MACHINE,
.class_init = niagara_class_init,
};
static void niagara_register_types(void)
{
type_register_static(&niagara_type);
}
type_init(niagara_register_types)
/*
* QEMU Sun4u/Sun4v System Emulator common routines
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "hw/char/serial.h"
#include "hw/sparc/sparc64.h"
#include "qemu/timer.h"
//#define DEBUG_IRQ
//#define DEBUG_TIMER
#ifdef DEBUG_IRQ
#define CPUIRQ_DPRINTF(fmt, ...) \
do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
#else
#define CPUIRQ_DPRINTF(fmt, ...)
#endif
#ifdef DEBUG_TIMER
#define TIMER_DPRINTF(fmt, ...) \
do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
#else
#define TIMER_DPRINTF(fmt, ...)
#endif
#define TICK_MAX 0x7fffffffffffffffULL
void cpu_check_irqs(CPUSPARCState *env)
{
CPUState *cs;
uint32_t pil = env->pil_in |
(env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
/* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
if (env->ivec_status & 0x20) {
return;
}
cs = CPU(sparc_env_get_cpu(env));
/* check if TM or SM in SOFTINT are set
setting these also causes interrupt 14 */
if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
pil |= 1 << 14;
}
/* The bit corresponding to psrpil is (1<< psrpil), the next bit
is (2 << psrpil). */
if (pil < (2 << env->psrpil)) {
if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
env->interrupt_index);
env->interrupt_index = 0;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
return;
}
if (cpu_interrupts_enabled(env)) {
unsigned int i;
for (i = 15; i > env->psrpil; i--) {
if (pil & (1 << i)) {
int old_interrupt = env->interrupt_index;
int new_interrupt = TT_EXTINT | i;
if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
&& ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
"current %x >= pending %x\n",
env->tl, cpu_tsptr(env)->tt, new_interrupt);
} else if (old_interrupt != new_interrupt) {
env->interrupt_index = new_interrupt;
CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
old_interrupt, new_interrupt);
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
}
break;
}
}
} else if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
"current interrupt %x\n",
pil, env->pil_in, env->softint, env->interrupt_index);
env->interrupt_index = 0;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
static void cpu_kick_irq(SPARCCPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUSPARCState *env = &cpu->env;
cs->halted = 0;
cpu_check_irqs(env);
qemu_cpu_kick(cs);
}
void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUState *cs;
if (level) {
if (!(env->ivec_status & 0x20)) {
CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
cs = CPU(cpu);
cs->halted = 0;
env->interrupt_index = TT_IVEC;
env->ivec_status |= 0x20;
env->ivec_data[0] = (0x1f << 6) | irq;
env->ivec_data[1] = 0;
env->ivec_data[2] = 0;
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
}
} else {
if (env->ivec_status & 0x20) {
CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
cs = CPU(cpu);
env->ivec_status &= ~0x20;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
}
typedef struct ResetData {
SPARCCPU *cpu;
uint64_t prom_addr;
} ResetData;
static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
QEMUBHFunc *cb, uint32_t frequency,
uint64_t disabled_mask, uint64_t npt_mask)
{
CPUTimer *timer = g_malloc0(sizeof(CPUTimer));
timer->name = name;
timer->frequency = frequency;
timer->disabled_mask = disabled_mask;
timer->npt_mask = npt_mask;
timer->disabled = 1;
timer->npt = 1;
timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu);
return timer;
}
static void cpu_timer_reset(CPUTimer *timer)
{
timer->disabled = 1;
timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
timer_del(timer->qtimer);
}
static void main_cpu_reset(void *opaque)
{
ResetData *s = (ResetData *)opaque;
CPUSPARCState *env = &s->cpu->env;
static unsigned int nr_resets;
cpu_reset(CPU(s->cpu));
cpu_timer_reset(env->tick);
cpu_timer_reset(env->stick);
cpu_timer_reset(env->hstick);
env->gregs[1] = 0; /* Memory start */
env->gregs[2] = ram_size; /* Memory size */
env->gregs[3] = 0; /* Machine description XXX */
if (nr_resets++ == 0) {
/* Power on reset */
env->pc = s->prom_addr + 0x20ULL;
} else {
env->pc = s->prom_addr + 0x40ULL;
}
env->npc = env->pc + 4;
}
static void tick_irq(void *opaque)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUTimer *timer = env->tick;
if (timer->disabled) {
CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
return;
} else {
CPUIRQ_DPRINTF("tick: fire\n");
}
env->softint |= SOFTINT_TIMER;
cpu_kick_irq(cpu);
}
static void stick_irq(void *opaque)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUTimer *timer = env->stick;
if (timer->disabled) {
CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
return;
} else {
CPUIRQ_DPRINTF("stick: fire\n");
}
env->softint |= SOFTINT_STIMER;
cpu_kick_irq(cpu);
}
static void hstick_irq(void *opaque)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUTimer *timer = env->hstick;
if (timer->disabled) {
CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
return;
} else {
CPUIRQ_DPRINTF("hstick: fire\n");
}
env->softint |= SOFTINT_STIMER;
cpu_kick_irq(cpu);
}
static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
{
return muldiv64(cpu_ticks, NANOSECONDS_PER_SECOND, frequency);
}
static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
{
return muldiv64(timer_ticks, frequency, NANOSECONDS_PER_SECOND);
}
void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
{
uint64_t real_count = count & ~timer->npt_mask;
uint64_t npt_bit = count & timer->npt_mask;
int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
cpu_to_timer_ticks(real_count, timer->frequency);
TIMER_DPRINTF("%s set_count count=0x%016lx (npt %s) p=%p\n",
timer->name, real_count,
timer->npt ? "disabled" : "enabled", timer);
timer->npt = npt_bit ? 1 : 0;
timer->clock_offset = vm_clock_offset;
}
uint64_t cpu_tick_get_count(CPUTimer *timer)
{
uint64_t real_count = timer_to_cpu_ticks(
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset,
timer->frequency);
TIMER_DPRINTF("%s get_count count=0x%016lx (npt %s) p=%p\n",
timer->name, real_count,
timer->npt ? "disabled" : "enabled", timer);
if (timer->npt) {
real_count |= timer->npt_mask;
}
return real_count;
}
void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
{
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t real_limit = limit & ~timer->disabled_mask;
timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
timer->clock_offset;
if (expires < now) {
expires = now + 1;
}
TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
"called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
timer->name, real_limit,
timer->disabled ? "disabled" : "enabled",
timer, limit,
timer_to_cpu_ticks(now - timer->clock_offset,
timer->frequency),
timer_to_cpu_ticks(expires - now, timer->frequency));
if (!real_limit) {
TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
timer->name);
timer_del(timer->qtimer);
} else if (timer->disabled) {
timer_del(timer->qtimer);
} else {
timer_mod(timer->qtimer, expires);
}
}
SPARCCPU *sparc64_cpu_devinit(const char *cpu_model,
const char *default_cpu_model, uint64_t prom_addr)
{
SPARCCPU *cpu;
CPUSPARCState *env;
ResetData *reset_info;
uint32_t tick_frequency = 100 * 1000000;
uint32_t stick_frequency = 100 * 1000000;
uint32_t hstick_frequency = 100 * 1000000;
if (cpu_model == NULL) {
cpu_model = default_cpu_model;
}
cpu = cpu_sparc_init(cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find Sparc CPU definition\n");
exit(1);
}
env = &cpu->env;
env->tick = cpu_timer_create("tick", cpu, tick_irq,
tick_frequency, TICK_INT_DIS,
TICK_NPT_MASK);
env->stick = cpu_timer_create("stick", cpu, stick_irq,
stick_frequency, TICK_INT_DIS,
TICK_NPT_MASK);
env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
hstick_frequency, TICK_INT_DIS,
TICK_NPT_MASK);
reset_info = g_malloc0(sizeof(ResetData));
reset_info->cpu = cpu;
reset_info->prom_addr = prom_addr;
qemu_register_reset(main_cpu_reset, reset_info);
return cpu;
}
...@@ -38,25 +38,15 @@ ...@@ -38,25 +38,15 @@
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/nvram/sun_nvram.h" #include "hw/nvram/sun_nvram.h"
#include "hw/nvram/chrp_nvram.h" #include "hw/nvram/chrp_nvram.h"
#include "hw/sparc/sparc64.h"
#include "hw/nvram/fw_cfg.h" #include "hw/nvram/fw_cfg.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/ide.h" #include "hw/ide.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "elf.h" #include "elf.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
//#define DEBUG_IRQ
//#define DEBUG_EBUS //#define DEBUG_EBUS
//#define DEBUG_TIMER
#ifdef DEBUG_IRQ
#define CPUIRQ_DPRINTF(fmt, ...) \
do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
#else
#define CPUIRQ_DPRINTF(fmt, ...)
#endif
#ifdef DEBUG_EBUS #ifdef DEBUG_EBUS
#define EBUS_DPRINTF(fmt, ...) \ #define EBUS_DPRINTF(fmt, ...) \
...@@ -65,13 +55,6 @@ ...@@ -65,13 +55,6 @@
#define EBUS_DPRINTF(fmt, ...) #define EBUS_DPRINTF(fmt, ...)
#endif #endif
#ifdef DEBUG_TIMER
#define TIMER_DPRINTF(fmt, ...) \
do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
#else
#define TIMER_DPRINTF(fmt, ...)
#endif
#define KERNEL_LOAD_ADDR 0x00404000 #define KERNEL_LOAD_ADDR 0x00404000
#define CMDLINE_ADDR 0x003ff000 #define CMDLINE_ADDR 0x003ff000
#define PROM_SIZE_MAX (4 * 1024 * 1024) #define PROM_SIZE_MAX (4 * 1024 * 1024)
...@@ -89,8 +72,6 @@ ...@@ -89,8 +72,6 @@
#define IVEC_MAX 0x40 #define IVEC_MAX 0x40
#define TICK_MAX 0x7fffffffffffffffULL
struct hwdef { struct hwdef {
const char * const default_cpu_model; const char * const default_cpu_model;
uint16_t machine_id; uint16_t machine_id;
...@@ -216,293 +197,11 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename, ...@@ -216,293 +197,11 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
return kernel_size; return kernel_size;
} }
void cpu_check_irqs(CPUSPARCState *env)
{
CPUState *cs;
uint32_t pil = env->pil_in |
(env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
/* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
if (env->ivec_status & 0x20) {
return;
}
cs = CPU(sparc_env_get_cpu(env));
/* check if TM or SM in SOFTINT are set
setting these also causes interrupt 14 */
if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
pil |= 1 << 14;
}
/* The bit corresponding to psrpil is (1<< psrpil), the next bit
is (2 << psrpil). */
if (pil < (2 << env->psrpil)){
if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n",
env->interrupt_index);
env->interrupt_index = 0;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
return;
}
if (cpu_interrupts_enabled(env)) {
unsigned int i;
for (i = 15; i > env->psrpil; i--) {
if (pil & (1 << i)) {
int old_interrupt = env->interrupt_index;
int new_interrupt = TT_EXTINT | i;
if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
&& ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d "
"current %x >= pending %x\n",
env->tl, cpu_tsptr(env)->tt, new_interrupt);
} else if (old_interrupt != new_interrupt) {
env->interrupt_index = new_interrupt;
CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i,
old_interrupt, new_interrupt);
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
}
break;
}
}
} else if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x "
"current interrupt %x\n",
pil, env->pil_in, env->softint, env->interrupt_index);
env->interrupt_index = 0;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
static void cpu_kick_irq(SPARCCPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUSPARCState *env = &cpu->env;
cs->halted = 0;
cpu_check_irqs(env);
qemu_cpu_kick(cs);
}
static void cpu_set_ivec_irq(void *opaque, int irq, int level)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUState *cs;
if (level) {
if (!(env->ivec_status & 0x20)) {
CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
cs = CPU(cpu);
cs->halted = 0;
env->interrupt_index = TT_IVEC;
env->ivec_status |= 0x20;
env->ivec_data[0] = (0x1f << 6) | irq;
env->ivec_data[1] = 0;
env->ivec_data[2] = 0;
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
}
} else {
if (env->ivec_status & 0x20) {
CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
cs = CPU(cpu);
env->ivec_status &= ~0x20;
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
}
typedef struct ResetData { typedef struct ResetData {
SPARCCPU *cpu; SPARCCPU *cpu;
uint64_t prom_addr; uint64_t prom_addr;
} ResetData; } ResetData;
static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
QEMUBHFunc *cb, uint32_t frequency,
uint64_t disabled_mask, uint64_t npt_mask)
{
CPUTimer *timer = g_malloc0(sizeof (CPUTimer));
timer->name = name;
timer->frequency = frequency;
timer->disabled_mask = disabled_mask;
timer->npt_mask = npt_mask;
timer->disabled = 1;
timer->npt = 1;
timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu);
return timer;
}
static void cpu_timer_reset(CPUTimer *timer)
{
timer->disabled = 1;
timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
timer_del(timer->qtimer);
}
static void main_cpu_reset(void *opaque)
{
ResetData *s = (ResetData *)opaque;
CPUSPARCState *env = &s->cpu->env;
static unsigned int nr_resets;
cpu_reset(CPU(s->cpu));
cpu_timer_reset(env->tick);
cpu_timer_reset(env->stick);
cpu_timer_reset(env->hstick);
env->gregs[1] = 0; // Memory start
env->gregs[2] = ram_size; // Memory size
env->gregs[3] = 0; // Machine description XXX
if (nr_resets++ == 0) {
/* Power on reset */
env->pc = s->prom_addr + 0x20ULL;
} else {
env->pc = s->prom_addr + 0x40ULL;
}
env->npc = env->pc + 4;
}
static void tick_irq(void *opaque)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUTimer* timer = env->tick;
if (timer->disabled) {
CPUIRQ_DPRINTF("tick_irq: softint disabled\n");
return;
} else {
CPUIRQ_DPRINTF("tick: fire\n");
}
env->softint |= SOFTINT_TIMER;
cpu_kick_irq(cpu);
}
static void stick_irq(void *opaque)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUTimer* timer = env->stick;
if (timer->disabled) {
CPUIRQ_DPRINTF("stick_irq: softint disabled\n");
return;
} else {
CPUIRQ_DPRINTF("stick: fire\n");
}
env->softint |= SOFTINT_STIMER;
cpu_kick_irq(cpu);
}
static void hstick_irq(void *opaque)
{
SPARCCPU *cpu = opaque;
CPUSPARCState *env = &cpu->env;
CPUTimer* timer = env->hstick;
if (timer->disabled) {
CPUIRQ_DPRINTF("hstick_irq: softint disabled\n");
return;
} else {
CPUIRQ_DPRINTF("hstick: fire\n");
}
env->softint |= SOFTINT_STIMER;
cpu_kick_irq(cpu);
}
static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
{
return muldiv64(cpu_ticks, NANOSECONDS_PER_SECOND, frequency);
}
static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
{
return muldiv64(timer_ticks, frequency, NANOSECONDS_PER_SECOND);
}
void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
{
uint64_t real_count = count & ~timer->npt_mask;
uint64_t npt_bit = count & timer->npt_mask;
int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
cpu_to_timer_ticks(real_count, timer->frequency);
TIMER_DPRINTF("%s set_count count=0x%016lx (npt %s) p=%p\n",
timer->name, real_count,
timer->npt ? "disabled" : "enabled", timer);
timer->npt = npt_bit ? 1 : 0;
timer->clock_offset = vm_clock_offset;
}
uint64_t cpu_tick_get_count(CPUTimer *timer)
{
uint64_t real_count = timer_to_cpu_ticks(
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset,
timer->frequency);
TIMER_DPRINTF("%s get_count count=0x%016lx (npt %s) p=%p\n",
timer->name, real_count,
timer->npt ? "disabled" : "enabled", timer);
if (timer->npt) {
real_count |= timer->npt_mask;
}
return real_count;
}
void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
{
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t real_limit = limit & ~timer->disabled_mask;
timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
timer->clock_offset;
if (expires < now) {
expires = now + 1;
}
TIMER_DPRINTF("%s set_limit limit=0x%016lx (%s) p=%p "
"called with limit=0x%016lx at 0x%016lx (delta=0x%016lx)\n",
timer->name, real_limit,
timer->disabled?"disabled":"enabled",
timer, limit,
timer_to_cpu_ticks(now - timer->clock_offset,
timer->frequency),
timer_to_cpu_ticks(expires - now, timer->frequency));
if (!real_limit) {
TIMER_DPRINTF("%s set_limit limit=ZERO - not starting timer\n",
timer->name);
timer_del(timer->qtimer);
} else if (timer->disabled) {
timer_del(timer->qtimer);
} else {
timer_mod(timer->qtimer, expires);
}
}
static void isa_irq_handler(void *opaque, int n, int level) static void isa_irq_handler(void *opaque, int n, int level)
{ {
static const int isa_irq_to_ivec[16] = { static const int isa_irq_to_ivec[16] = {
...@@ -723,46 +422,6 @@ static const TypeInfo ram_info = { ...@@ -723,46 +422,6 @@ static const TypeInfo ram_info = {
.class_init = ram_class_init, .class_init = ram_class_init,
}; };
static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
{
SPARCCPU *cpu;
CPUSPARCState *env;
ResetData *reset_info;
uint32_t tick_frequency = 100*1000000;
uint32_t stick_frequency = 100*1000000;
uint32_t hstick_frequency = 100*1000000;
if (cpu_model == NULL) {
cpu_model = hwdef->default_cpu_model;
}
cpu = cpu_sparc_init(cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find Sparc CPU definition\n");
exit(1);
}
env = &cpu->env;
env->tick = cpu_timer_create("tick", cpu, tick_irq,
tick_frequency, TICK_INT_DIS,
TICK_NPT_MASK);
env->stick = cpu_timer_create("stick", cpu, stick_irq,
stick_frequency, TICK_INT_DIS,
TICK_NPT_MASK);
env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
hstick_frequency, TICK_INT_DIS,
TICK_NPT_MASK);
reset_info = g_malloc0(sizeof(ResetData));
reset_info->cpu = cpu;
reset_info->prom_addr = hwdef->prom_addr;
qemu_register_reset(main_cpu_reset, reset_info);
return cpu;
}
static void sun4uv_init(MemoryRegion *address_space_mem, static void sun4uv_init(MemoryRegion *address_space_mem,
MachineState *machine, MachineState *machine,
const struct hwdef *hwdef) const struct hwdef *hwdef)
...@@ -781,14 +440,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem, ...@@ -781,14 +440,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
FWCfgState *fw_cfg; FWCfgState *fw_cfg;
/* init CPUs */ /* init CPUs */
cpu = cpu_devinit(machine->cpu_model, hwdef); cpu = sparc64_cpu_devinit(machine->cpu_model, hwdef->default_cpu_model,
hwdef->prom_addr);
/* set up devices */ /* set up devices */
ram_init(0, machine->ram_size); ram_init(0, machine->ram_size);
prom_init(hwdef->prom_addr, bios_name); prom_init(hwdef->prom_addr, bios_name);
ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, cpu, IVEC_MAX); ivec_irqs = qemu_allocate_irqs(sparc64_cpu_set_ivec_irq, cpu, IVEC_MAX);
pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2,
&pci_bus3, &pbm_irqs); &pci_bus3, &pbm_irqs);
pci_vga_init(pci_bus); pci_vga_init(pci_bus);
...@@ -882,7 +542,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem, ...@@ -882,7 +542,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
enum { enum {
sun4u_id = 0, sun4u_id = 0,
sun4v_id = 64, sun4v_id = 64,
niagara_id,
}; };
static const struct hwdef hwdefs[] = { static const struct hwdef hwdefs[] = {
...@@ -900,13 +559,6 @@ static const struct hwdef hwdefs[] = { ...@@ -900,13 +559,6 @@ static const struct hwdef hwdefs[] = {
.prom_addr = 0x1fff0000000ULL, .prom_addr = 0x1fff0000000ULL,
.console_serial_base = 0, .console_serial_base = 0,
}, },
/* Sun4v generic Niagara machine */
{
.default_cpu_model = "Sun UltraSparc T1",
.machine_id = niagara_id,
.prom_addr = 0xfff0000000ULL,
.console_serial_base = 0xfff0c2c000ULL,
},
}; };
/* Sun4u hardware initialisation */ /* Sun4u hardware initialisation */
...@@ -921,12 +573,6 @@ static void sun4v_init(MachineState *machine) ...@@ -921,12 +573,6 @@ static void sun4v_init(MachineState *machine)
sun4uv_init(get_system_memory(), machine, &hwdefs[1]); sun4uv_init(get_system_memory(), machine, &hwdefs[1]);
} }
/* Niagara hardware initialisation */
static void niagara_init(MachineState *machine)
{
sun4uv_init(get_system_memory(), machine, &hwdefs[2]);
}
static void sun4u_class_init(ObjectClass *oc, void *data) static void sun4u_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
...@@ -960,22 +606,6 @@ static const TypeInfo sun4v_type = { ...@@ -960,22 +606,6 @@ static const TypeInfo sun4v_type = {
.class_init = sun4v_class_init, .class_init = sun4v_class_init,
}; };
static void niagara_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Sun4v platform, Niagara";
mc->init = niagara_init;
mc->max_cpus = 1; /* XXX for now */
mc->default_boot_order = "c";
}
static const TypeInfo niagara_type = {
.name = MACHINE_TYPE_NAME("Niagara"),
.parent = TYPE_MACHINE,
.class_init = niagara_class_init,
};
static void sun4u_register_types(void) static void sun4u_register_types(void)
{ {
type_register_static(&ebus_info); type_register_static(&ebus_info);
...@@ -984,7 +614,6 @@ static void sun4u_register_types(void) ...@@ -984,7 +614,6 @@ static void sun4u_register_types(void)
type_register_static(&sun4u_type); type_register_static(&sun4u_type);
type_register_static(&sun4v_type); type_register_static(&sun4v_type);
type_register_static(&niagara_type);
} }
type_init(sun4u_register_types) type_init(sun4u_register_types)
...@@ -34,3 +34,5 @@ obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o ...@@ -34,3 +34,5 @@ obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
/*
* QEMU sun4v Real Time Clock device
*
* The sun4v_rtc device (sun4v tod clock)
*
* Copyright (c) 2016 Artyom Tarasenko
*
* This code is licensed under the GNU GPL v3 or (at your option) any later
* version.
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "hw/timer/sun4v-rtc.h"
//#define DEBUG_SUN4V_RTC
#ifdef DEBUG_SUN4V_RTC
#define DPRINTF(fmt, ...) \
do { printf("sun4v_rtc: " fmt , ## __VA_ARGS__); } while (0)
#else
#define DPRINTF(fmt, ...) do {} while (0)
#endif
#define TYPE_SUN4V_RTC "sun4v_rtc"
#define SUN4V_RTC(obj) OBJECT_CHECK(Sun4vRtc, (obj), TYPE_SUN4V_RTC)
typedef struct Sun4vRtc {
SysBusDevice parent_obj;
MemoryRegion iomem;
} Sun4vRtc;
static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr,
unsigned size)
{
uint64_t val = get_clock_realtime() / NANOSECONDS_PER_SECOND;
if (!(addr & 4ULL)) {
/* accessing the high 32 bits */
val >>= 32;
}
DPRINTF("read from " TARGET_FMT_plx " val %lx\n", addr, val);
return val;
}
static void sun4v_rtc_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr);
}
static const MemoryRegionOps sun4v_rtc_ops = {
.read = sun4v_rtc_read,
.write = sun4v_rtc_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
void sun4v_rtc_init(hwaddr addr)
{
DeviceState *dev;
SysBusDevice *s;
dev = qdev_create(NULL, TYPE_SUN4V_RTC);
s = SYS_BUS_DEVICE(dev);
qdev_init_nofail(dev);
sysbus_mmio_map(s, 0, addr);
}
static int sun4v_rtc_init1(SysBusDevice *dev)
{
Sun4vRtc *s = SUN4V_RTC(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &sun4v_rtc_ops, s,
"sun4v-rtc", 0x08ULL);
sysbus_init_mmio(dev, &s->iomem);
return 0;
}
static void sun4v_rtc_class_init(ObjectClass *klass, void *data)
{
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = sun4v_rtc_init1;
}
static const TypeInfo sun4v_rtc_info = {
.name = TYPE_SUN4V_RTC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Sun4vRtc),
.class_init = sun4v_rtc_class_init,
};
static void sun4v_rtc_register_types(void)
{
type_register_static(&sun4v_rtc_info);
}
type_init(sun4v_rtc_register_types)
SPARCCPU *sparc64_cpu_devinit(const char *cpu_model,
const char *dflt_cpu_model, uint64_t prom_addr);
void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level);
void sun4v_rtc_init(hwaddr addr);
...@@ -1166,7 +1166,7 @@ void cpu_loop (CPUSPARCState *env) ...@@ -1166,7 +1166,7 @@ void cpu_loop (CPUSPARCState *env)
/* XXX: check env->error_code */ /* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR; info.si_code = TARGET_SEGV_MAPERR;
if (trapnr == TT_DFAULT) if (trapnr == TT_DFAULT)
info._sifields._sigfault._addr = env->dmmuregs[4]; info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
else else
info._sifields._sigfault._addr = cpu_tsptr(env)->tpc; info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
......
...@@ -2138,7 +2138,17 @@ Use the executable @file{qemu-system-sparc64} to simulate a Sun4u ...@@ -2138,7 +2138,17 @@ Use the executable @file{qemu-system-sparc64} to simulate a Sun4u
(UltraSPARC PC-like machine), Sun4v (T1 PC-like machine), or generic (UltraSPARC PC-like machine), Sun4v (T1 PC-like machine), or generic
Niagara (T1) machine. The Sun4u emulator is mostly complete, being Niagara (T1) machine. The Sun4u emulator is mostly complete, being
able to run Linux, NetBSD and OpenBSD in headless (-nographic) mode. The able to run Linux, NetBSD and OpenBSD in headless (-nographic) mode. The
Sun4v and Niagara emulators are still a work in progress. Sun4v emulator is still a work in progress.
The Niagara T1 emulator makes use of firmware and OS binaries supplied in the S10image/ directory
of the OpenSPARC T1 project @url{http://download.oracle.com/technetwork/systems/opensparc/OpenSPARCT1_Arch.1.5.tar.bz2}
and is able to boot the disk.s10hw2 Solaris image.
@example
qemu-system-sparc64 -M niagara -L /path-to/S10image/ \
-nographic -m 256 \
-drive if=pflash,readonly=on,file=/S10image/disk.s10hw2
@end example
QEMU emulates the following peripherals: QEMU emulates the following peripherals:
...@@ -2173,7 +2183,7 @@ Set OpenBIOS variables in NVRAM, for example: ...@@ -2173,7 +2183,7 @@ Set OpenBIOS variables in NVRAM, for example:
qemu-system-sparc64 -prom-env 'auto-boot?=false' qemu-system-sparc64 -prom-env 'auto-boot?=false'
@end example @end example
@item -M [sun4u|sun4v|Niagara] @item -M [sun4u|sun4v|niagara]
Set the emulated machine type. The default is sun4u. Set the emulated machine type. The default is sun4u.
......
...@@ -211,6 +211,7 @@ ...@@ -211,6 +211,7 @@
#define ASI_AFSR 0x4c /* Async fault status register */ #define ASI_AFSR 0x4c /* Async fault status register */
#define ASI_AFAR 0x4d /* Async fault address register */ #define ASI_AFAR 0x4d /* Async fault address register */
#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */ #define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */
#define ASI_HYP_SCRATCHPAD 0x4f /* (4V) Hypervisor scratchpad */
#define ASI_IMMU 0x50 /* Insn-MMU main register space */ #define ASI_IMMU 0x50 /* Insn-MMU main register space */
#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */ #define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */
#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */ #define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */
......
...@@ -57,9 +57,13 @@ static void sparc_cpu_reset(CPUState *s) ...@@ -57,9 +57,13 @@ static void sparc_cpu_reset(CPUState *s)
env->psrps = 1; env->psrps = 1;
#endif #endif
#ifdef TARGET_SPARC64 #ifdef TARGET_SPARC64
env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG; env->pstate = PS_PRIV | PS_RED | PS_PEF;
if (!cpu_has_hypervisor(env)) {
env->pstate |= PS_AG;
}
env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0; env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
env->tl = env->maxtl; env->tl = env->maxtl;
env->gl = 2;
cpu_tsptr(env)->tt = TT_POWER_ON_RESET; cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
env->lsu = 0; env->lsu = 0;
#else #else
...@@ -744,14 +748,17 @@ void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, ...@@ -744,14 +748,17 @@ void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT); cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
cpu_fprintf(f, " xcc: "); cpu_fprintf(f, " xcc: ");
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4)); cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl, cpu_fprintf(f, ") asi: %02x tl: %d pil: %x gl: %d\n", env->asi, env->tl,
env->psrpil); env->psrpil, env->gl);
cpu_fprintf(f, "tbr: " TARGET_FMT_lx " hpstate: " TARGET_FMT_lx " htba: "
TARGET_FMT_lx "\n", env->tbr, env->hpstate, env->htba);
cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d " cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
"cleanwin: %d cwp: %d\n", "cleanwin: %d cwp: %d\n",
env->cansave, env->canrestore, env->otherwin, env->wstate, env->cansave, env->canrestore, env->otherwin, env->wstate,
env->cleanwin, env->nwindows - 1 - env->cwp); env->cleanwin, env->nwindows - 1 - env->cwp);
cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: " cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs); TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
#else #else
cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env)); cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env)); cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
......
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
#define TT_DATA_ACCESS 0x32 #define TT_DATA_ACCESS 0x32
#define TT_UNALIGNED 0x34 #define TT_UNALIGNED 0x34
#define TT_PRIV_ACT 0x37 #define TT_PRIV_ACT 0x37
#define TT_INSN_REAL_TRANSLATION_MISS 0x3e
#define TT_DATA_REAL_TRANSLATION_MISS 0x3f
#define TT_EXTINT 0x40 #define TT_EXTINT 0x40
#define TT_IVEC 0x60 #define TT_IVEC 0x60
#define TT_TMISS 0x64 #define TT_TMISS 0x64
...@@ -77,6 +79,7 @@ ...@@ -77,6 +79,7 @@
#define TT_FILL 0xc0 #define TT_FILL 0xc0
#define TT_WOTHER (1 << 5) #define TT_WOTHER (1 << 5)
#define TT_TRAP 0x100 #define TT_TRAP 0x100
#define TT_HTRAP 0x180
#endif #endif
#define PSR_NEG_SHIFT 23 #define PSR_NEG_SHIFT 23
...@@ -227,7 +230,7 @@ enum { ...@@ -227,7 +230,7 @@ enum {
#if !defined(TARGET_SPARC64) #if !defined(TARGET_SPARC64)
#define NB_MMU_MODES 3 #define NB_MMU_MODES 3
#else #else
#define NB_MMU_MODES 7 #define NB_MMU_MODES 6
typedef struct trap_state { typedef struct trap_state {
uint64_t tpc; uint64_t tpc;
uint64_t tnpc; uint64_t tnpc;
...@@ -302,21 +305,42 @@ enum { ...@@ -302,21 +305,42 @@ enum {
#define TTE_W_OK_BIT (1ULL << 1) #define TTE_W_OK_BIT (1ULL << 1)
#define TTE_GLOBAL_BIT (1ULL << 0) #define TTE_GLOBAL_BIT (1ULL << 0)
#define TTE_NFO_BIT_UA2005 (1ULL << 62)
#define TTE_USED_BIT_UA2005 (1ULL << 47)
#define TTE_LOCKED_BIT_UA2005 (1ULL << 61)
#define TTE_SIDEEFFECT_BIT_UA2005 (1ULL << 11)
#define TTE_PRIV_BIT_UA2005 (1ULL << 8)
#define TTE_W_OK_BIT_UA2005 (1ULL << 6)
#define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT) #define TTE_IS_VALID(tte) ((tte) & TTE_VALID_BIT)
#define TTE_IS_NFO(tte) ((tte) & TTE_NFO_BIT) #define TTE_IS_NFO(tte) ((tte) & TTE_NFO_BIT)
#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT) #define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT)
#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT) #define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_BIT)
#define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT) #define TTE_IS_SIDEEFFECT(tte) ((tte) & TTE_SIDEEFFECT_BIT)
#define TTE_IS_SIDEEFFECT_UA2005(tte) ((tte) & TTE_SIDEEFFECT_BIT_UA2005)
#define TTE_IS_PRIV(tte) ((tte) & TTE_PRIV_BIT) #define TTE_IS_PRIV(tte) ((tte) & TTE_PRIV_BIT)
#define TTE_IS_W_OK(tte) ((tte) & TTE_W_OK_BIT) #define TTE_IS_W_OK(tte) ((tte) & TTE_W_OK_BIT)
#define TTE_IS_NFO_UA2005(tte) ((tte) & TTE_NFO_BIT_UA2005)
#define TTE_IS_USED_UA2005(tte) ((tte) & TTE_USED_BIT_UA2005)
#define TTE_IS_LOCKED_UA2005(tte) ((tte) & TTE_LOCKED_BIT_UA2005)
#define TTE_IS_SIDEEFFECT_UA2005(tte) ((tte) & TTE_SIDEEFFECT_BIT_UA2005)
#define TTE_IS_PRIV_UA2005(tte) ((tte) & TTE_PRIV_BIT_UA2005)
#define TTE_IS_W_OK_UA2005(tte) ((tte) & TTE_W_OK_BIT_UA2005)
#define TTE_IS_GLOBAL(tte) ((tte) & TTE_GLOBAL_BIT) #define TTE_IS_GLOBAL(tte) ((tte) & TTE_GLOBAL_BIT)
#define TTE_SET_USED(tte) ((tte) |= TTE_USED_BIT) #define TTE_SET_USED(tte) ((tte) |= TTE_USED_BIT)
#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT) #define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
#define TTE_PGSIZE(tte) (((tte) >> 61) & 3ULL) #define TTE_PGSIZE(tte) (((tte) >> 61) & 3ULL)
#define TTE_PGSIZE_UA2005(tte) ((tte) & 7ULL)
#define TTE_PA(tte) ((tte) & 0x1ffffffe000ULL) #define TTE_PA(tte) ((tte) & 0x1ffffffe000ULL)
/* UltraSPARC T1 specific */
#define TLB_UST1_IS_REAL_BIT (1ULL << 9) /* Real translation entry */
#define TLB_UST1_IS_SUN4V_BIT (1ULL << 10) /* sun4u/sun4v TTE format switch */
#define SFSR_NF_BIT (1ULL << 24) /* JPS1 NoFault */ #define SFSR_NF_BIT (1ULL << 24) /* JPS1 NoFault */
#define SFSR_TM_BIT (1ULL << 15) /* JPS1 TLB Miss */ #define SFSR_TM_BIT (1ULL << 15) /* JPS1 TLB Miss */
#define SFSR_FT_VA_IMMU_BIT (1ULL << 13) /* USIIi VA out of range (IMMU) */ #define SFSR_FT_VA_IMMU_BIT (1ULL << 13) /* USIIi VA out of range (IMMU) */
...@@ -360,6 +384,9 @@ enum { ...@@ -360,6 +384,9 @@ enum {
#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */ #define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */ #define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */
#define CONVERT_BIT(X, SRC, DST) \
(SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
typedef struct SparcTLBEntry { typedef struct SparcTLBEntry {
uint64_t tag; uint64_t tag;
uint64_t tte; uint64_t tte;
...@@ -380,7 +407,24 @@ struct CPUTimer ...@@ -380,7 +407,24 @@ struct CPUTimer
typedef struct CPUTimer CPUTimer; typedef struct CPUTimer CPUTimer;
typedef struct CPUSPARCState CPUSPARCState; typedef struct CPUSPARCState CPUSPARCState;
#if defined(TARGET_SPARC64)
typedef union {
uint64_t mmuregs[16];
struct {
uint64_t tsb_tag_target;
uint64_t mmu_primary_context;
uint64_t mmu_secondary_context;
uint64_t sfsr;
uint64_t sfar;
uint64_t tsb;
uint64_t tag_access;
uint64_t virtual_watchpoint;
uint64_t physical_watchpoint;
uint64_t sun4v_ctx_config[2];
uint64_t sun4v_tsb_pointers[4];
};
} SparcV9MMU;
#endif
struct CPUSPARCState { struct CPUSPARCState {
target_ulong gregs[8]; /* general registers */ target_ulong gregs[8]; /* general registers */
target_ulong *regwptr; /* pointer to current register window */ target_ulong *regwptr; /* pointer to current register window */
...@@ -433,31 +477,8 @@ struct CPUSPARCState { ...@@ -433,31 +477,8 @@ struct CPUSPARCState {
uint64_t lsu; uint64_t lsu;
#define DMMU_E 0x8 #define DMMU_E 0x8
#define IMMU_E 0x4 #define IMMU_E 0x4
//typedef struct SparcMMU SparcV9MMU immu;
union { SparcV9MMU dmmu;
uint64_t immuregs[16];
struct {
uint64_t tsb_tag_target;
uint64_t unused_mmu_primary_context; // use DMMU
uint64_t unused_mmu_secondary_context; // use DMMU
uint64_t sfsr;
uint64_t sfar;
uint64_t tsb;
uint64_t tag_access;
} immu;
};
union {
uint64_t dmmuregs[16];
struct {
uint64_t tsb_tag_target;
uint64_t mmu_primary_context;
uint64_t mmu_secondary_context;
uint64_t sfsr;
uint64_t sfar;
uint64_t tsb;
uint64_t tag_access;
} dmmu;
};
SparcTLBEntry itlb[64]; SparcTLBEntry itlb[64];
SparcTLBEntry dtlb[64]; SparcTLBEntry dtlb[64];
uint32_t mmu_version; uint32_t mmu_version;
...@@ -487,6 +508,7 @@ struct CPUSPARCState { ...@@ -487,6 +508,7 @@ struct CPUSPARCState {
uint64_t bgregs[8]; /* backup for normal global registers */ uint64_t bgregs[8]; /* backup for normal global registers */
uint64_t igregs[8]; /* interrupt general registers */ uint64_t igregs[8]; /* interrupt general registers */
uint64_t mgregs[8]; /* mmu general registers */ uint64_t mgregs[8]; /* mmu general registers */
uint64_t glregs[8 * MAXTL_MAX];
uint64_t fprs; uint64_t fprs;
uint64_t tick_cmpr, stick_cmpr; uint64_t tick_cmpr, stick_cmpr;
CPUTimer *tick, *stick; CPUTimer *tick, *stick;
...@@ -496,6 +518,7 @@ struct CPUSPARCState { ...@@ -496,6 +518,7 @@ struct CPUSPARCState {
uint32_t gl; // UA2005 uint32_t gl; // UA2005
/* UA 2005 hyperprivileged registers */ /* UA 2005 hyperprivileged registers */
uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr; uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
uint64_t scratch[8];
CPUTimer *hstick; // UA 2005 CPUTimer *hstick; // UA 2005
/* Interrupt vector registers */ /* Interrupt vector registers */
uint64_t ivec_status; uint64_t ivec_status;
...@@ -586,6 +609,7 @@ void cpu_put_ccr(CPUSPARCState *env1, target_ulong val); ...@@ -586,6 +609,7 @@ void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
target_ulong cpu_get_cwp64(CPUSPARCState *env1); target_ulong cpu_get_cwp64(CPUSPARCState *env1);
void cpu_put_cwp64(CPUSPARCState *env1, int cwp); void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate); void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl);
#endif #endif
int cpu_cwp_inc(CPUSPARCState *env1, int cwp); int cpu_cwp_inc(CPUSPARCState *env1, int cwp);
int cpu_cwp_dec(CPUSPARCState *env1, int cwp); int cpu_cwp_dec(CPUSPARCState *env1, int cwp);
...@@ -645,8 +669,7 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); ...@@ -645,8 +669,7 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
#define MMU_KERNEL_IDX 2 #define MMU_KERNEL_IDX 2
#define MMU_KERNEL_SECONDARY_IDX 3 #define MMU_KERNEL_SECONDARY_IDX 3
#define MMU_NUCLEUS_IDX 4 #define MMU_NUCLEUS_IDX 4
#define MMU_HYPV_IDX 5 #define MMU_PHYS_IDX 5
#define MMU_PHYS_IDX 6
#else #else
#define MMU_USER_IDX 0 #define MMU_USER_IDX 0
#define MMU_KERNEL_IDX 1 #define MMU_KERNEL_IDX 1
...@@ -668,6 +691,11 @@ static inline int cpu_supervisor_mode(CPUSPARCState *env1) ...@@ -668,6 +691,11 @@ static inline int cpu_supervisor_mode(CPUSPARCState *env1)
{ {
return env1->pstate & PS_PRIV; return env1->pstate & PS_PRIV;
} }
#else
static inline int cpu_supervisor_mode(CPUSPARCState *env1)
{
return env1->psrs;
}
#endif #endif
static inline int cpu_mmu_index(CPUSPARCState *env, bool ifetch) static inline int cpu_mmu_index(CPUSPARCState *env, bool ifetch)
...@@ -686,10 +714,10 @@ static inline int cpu_mmu_index(CPUSPARCState *env, bool ifetch) ...@@ -686,10 +714,10 @@ static inline int cpu_mmu_index(CPUSPARCState *env, bool ifetch)
? (env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0 ? (env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0
: (env->lsu & DMMU_E) == 0) { : (env->lsu & DMMU_E) == 0) {
return MMU_PHYS_IDX; return MMU_PHYS_IDX;
} else if (cpu_hypervisor_mode(env)) {
return MMU_PHYS_IDX;
} else if (env->tl > 0) { } else if (env->tl > 0) {
return MMU_NUCLEUS_IDX; return MMU_NUCLEUS_IDX;
} else if (cpu_hypervisor_mode(env)) {
return MMU_HYPV_IDX;
} else if (cpu_supervisor_mode(env)) { } else if (cpu_supervisor_mode(env)) {
return MMU_KERNEL_IDX; return MMU_KERNEL_IDX;
} else { } else {
...@@ -704,8 +732,9 @@ static inline int cpu_interrupts_enabled(CPUSPARCState *env1) ...@@ -704,8 +732,9 @@ static inline int cpu_interrupts_enabled(CPUSPARCState *env1)
if (env1->psret != 0) if (env1->psret != 0)
return 1; return 1;
#else #else
if (env1->pstate & PS_IE) if ((env1->pstate & PS_IE) && !cpu_hypervisor_mode(env1)) {
return 1; return 1;
}
#endif #endif
return 0; return 0;
...@@ -734,6 +763,8 @@ trap_state* cpu_tsptr(CPUSPARCState* env); ...@@ -734,6 +763,8 @@ trap_state* cpu_tsptr(CPUSPARCState* env);
#define TB_FLAG_MMU_MASK 7 #define TB_FLAG_MMU_MASK 7
#define TB_FLAG_FPU_ENABLED (1 << 4) #define TB_FLAG_FPU_ENABLED (1 << 4)
#define TB_FLAG_AM_ENABLED (1 << 5) #define TB_FLAG_AM_ENABLED (1 << 5)
#define TB_FLAG_SUPER (1 << 6)
#define TB_FLAG_HYPER (1 << 7)
#define TB_FLAG_ASI_SHIFT 24 #define TB_FLAG_ASI_SHIFT 24
static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc, static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
...@@ -743,7 +774,17 @@ static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc, ...@@ -743,7 +774,17 @@ static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc,
*pc = env->pc; *pc = env->pc;
*cs_base = env->npc; *cs_base = env->npc;
flags = cpu_mmu_index(env, false); flags = cpu_mmu_index(env, false);
#ifndef CONFIG_USER_ONLY
if (cpu_supervisor_mode(env)) {
flags |= TB_FLAG_SUPER;
}
#endif
#ifdef TARGET_SPARC64 #ifdef TARGET_SPARC64
#ifndef CONFIG_USER_ONLY
if (cpu_hypervisor_mode(env)) {
flags |= TB_FLAG_HYPER;
}
#endif
if (env->pstate & PS_AM) { if (env->pstate & PS_AM) {
flags |= TB_FLAG_AM_ENABLED; flags |= TB_FLAG_AM_ENABLED;
} }
......
...@@ -5,6 +5,7 @@ DEF_HELPER_1(rdpsr, tl, env) ...@@ -5,6 +5,7 @@ DEF_HELPER_1(rdpsr, tl, env)
DEF_HELPER_1(power_down, void, env) DEF_HELPER_1(power_down, void, env)
#else #else
DEF_HELPER_FLAGS_2(wrpil, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(wrpil, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_2(wrgl, void, env, tl)
DEF_HELPER_2(wrpstate, void, env, tl) DEF_HELPER_2(wrpstate, void, env, tl)
DEF_HELPER_1(done, void, env) DEF_HELPER_1(done, void, env)
DEF_HELPER_1(retry, void, env) DEF_HELPER_1(retry, void, env)
......
...@@ -78,8 +78,10 @@ void sparc_cpu_do_interrupt(CPUState *cs) ...@@ -78,8 +78,10 @@ void sparc_cpu_do_interrupt(CPUState *cs)
static int count; static int count;
const char *name; const char *name;
if (intno < 0 || intno >= 0x180) { if (intno < 0 || intno >= 0x1ff) {
name = "Unknown"; name = "Unknown";
} else if (intno >= 0x180) {
name = "Hyperprivileged Trap Instruction";
} else if (intno >= 0x100) { } else if (intno >= 0x100) {
name = "Trap Instruction"; name = "Trap Instruction";
} else if (intno >= 0xc0) { } else if (intno >= 0xc0) {
...@@ -135,16 +137,42 @@ void sparc_cpu_do_interrupt(CPUState *cs) ...@@ -135,16 +137,42 @@ void sparc_cpu_do_interrupt(CPUState *cs)
tsptr->tnpc = env->npc; tsptr->tnpc = env->npc;
tsptr->tt = intno; tsptr->tt = intno;
if (cpu_has_hypervisor(env)) {
env->htstate[env->tl] = env->hpstate;
/* XXX OpenSPARC T1 - UltraSPARC T3 have MAXPTL=2
but this may change in the future */
if (env->tl > 2) {
env->hpstate |= HS_PRIV;
}
}
if (env->def->features & CPU_FEATURE_GL) {
tsptr->tstate |= (env->gl & 7ULL) << 40;
cpu_gl_switch_gregs(env, env->gl + 1);
env->gl++;
}
switch (intno) { switch (intno) {
case TT_IVEC: case TT_IVEC:
if (!cpu_has_hypervisor(env)) {
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG); cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
}
break; break;
case TT_TFAULT: case TT_TFAULT:
case TT_DFAULT: case TT_DFAULT:
case TT_TMISS ... TT_TMISS + 3: case TT_TMISS ... TT_TMISS + 3:
case TT_DMISS ... TT_DMISS + 3: case TT_DMISS ... TT_DMISS + 3:
case TT_DPROT ... TT_DPROT + 3: case TT_DPROT ... TT_DPROT + 3:
if (cpu_has_hypervisor(env)) {
env->hpstate |= HS_PRIV;
env->pstate = PS_PEF | PS_PRIV;
} else {
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG); cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
}
break;
case TT_INSN_REAL_TRANSLATION_MISS ... TT_DATA_REAL_TRANSLATION_MISS:
case TT_HTRAP ... TT_HTRAP + 127:
env->hpstate |= HS_PRIV;
break; break;
default: default:
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG); cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
...@@ -158,8 +186,13 @@ void sparc_cpu_do_interrupt(CPUState *cs) ...@@ -158,8 +186,13 @@ void sparc_cpu_do_interrupt(CPUState *cs)
} else if ((intno & 0x1c0) == TT_FILL) { } else if ((intno & 0x1c0) == TT_FILL) {
cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1)); cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
} }
if (cpu_hypervisor_mode(env)) {
env->pc = (env->htba & ~0x3fffULL) | (intno << 5);
} else {
env->pc = env->tbr & ~0x7fffULL; env->pc = env->tbr & ~0x7fffULL;
env->pc |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); env->pc |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
}
env->npc = env->pc + 4; env->npc = env->pc + 4;
cs->exception_index = -1; cs->exception_index = -1;
} }
......
此差异已折叠。
...@@ -148,8 +148,8 @@ const VMStateDescription vmstate_sparc_cpu = { ...@@ -148,8 +148,8 @@ const VMStateDescription vmstate_sparc_cpu = {
VMSTATE_UINT64_ARRAY(env.mmubpregs, SPARCCPU, 4), VMSTATE_UINT64_ARRAY(env.mmubpregs, SPARCCPU, 4),
#else #else
VMSTATE_UINT64(env.lsu, SPARCCPU), VMSTATE_UINT64(env.lsu, SPARCCPU),
VMSTATE_UINT64_ARRAY(env.immuregs, SPARCCPU, 16), VMSTATE_UINT64_ARRAY(env.immu.mmuregs, SPARCCPU, 16),
VMSTATE_UINT64_ARRAY(env.dmmuregs, SPARCCPU, 16), VMSTATE_UINT64_ARRAY(env.dmmu.mmuregs, SPARCCPU, 16),
VMSTATE_STRUCT_ARRAY(env.itlb, SPARCCPU, 64, 0, VMSTATE_STRUCT_ARRAY(env.itlb, SPARCCPU, 64, 0,
vmstate_tlb_entry, SparcTLBEntry), vmstate_tlb_entry, SparcTLBEntry),
VMSTATE_STRUCT_ARRAY(env.dtlb, SPARCCPU, 64, 0, VMSTATE_STRUCT_ARRAY(env.dtlb, SPARCCPU, 64, 0,
......
...@@ -456,23 +456,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, ...@@ -456,23 +456,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
uint64_t address, uint64_t context, uint64_t address, uint64_t context,
hwaddr *physical) hwaddr *physical)
{ {
uint64_t mask; uint64_t mask = -(8192ULL << 3 * TTE_PGSIZE(tlb->tte));
switch (TTE_PGSIZE(tlb->tte)) {
default:
case 0x0: /* 8k */
mask = 0xffffffffffffe000ULL;
break;
case 0x1: /* 64k */
mask = 0xffffffffffff0000ULL;
break;
case 0x2: /* 512k */
mask = 0xfffffffffff80000ULL;
break;
case 0x3: /* 4M */
mask = 0xffffffffffc00000ULL;
break;
}
/* valid, context match, virtual address match? */ /* valid, context match, virtual address match? */
if (TTE_IS_VALID(tlb->tte) && if (TTE_IS_VALID(tlb->tte) &&
...@@ -757,6 +741,8 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env) ...@@ -757,6 +741,8 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
PRId64 "\n", PRId64 "\n",
env->dmmu.mmu_primary_context, env->dmmu.mmu_primary_context,
env->dmmu.mmu_secondary_context); env->dmmu.mmu_secondary_context);
(*cpu_fprintf)(f, "DMMU Tag Access: %" PRIx64 ", TSB Tag Target: %" PRIx64
"\n", env->dmmu.tag_access, env->dmmu.tsb_tag_target);
if ((env->lsu & DMMU_E) == 0) { if ((env->lsu & DMMU_E) == 0) {
(*cpu_fprintf)(f, "DMMU disabled\n"); (*cpu_fprintf)(f, "DMMU disabled\n");
} else { } else {
......
...@@ -72,9 +72,16 @@ typedef struct DisasContext { ...@@ -72,9 +72,16 @@ typedef struct DisasContext {
target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
int is_br; int is_br;
int mem_idx; int mem_idx;
int fpu_enabled; bool fpu_enabled;
int address_mask_32bit; bool address_mask_32bit;
int singlestep; bool singlestep;
#ifndef CONFIG_USER_ONLY
bool supervisor;
#ifdef TARGET_SPARC64
bool hypervisor;
#endif
#endif
uint32_t cc_op; /* current CC operation */ uint32_t cc_op; /* current CC operation */
struct TranslationBlock *tb; struct TranslationBlock *tb;
sparc_def_t *def; sparc_def_t *def;
...@@ -283,10 +290,11 @@ static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs) ...@@ -283,10 +290,11 @@ static void gen_move_Q(DisasContext *dc, unsigned int rd, unsigned int rs)
#define hypervisor(dc) 0 #define hypervisor(dc) 0
#endif #endif
#else #else
#define supervisor(dc) (dc->mem_idx >= MMU_KERNEL_IDX)
#ifdef TARGET_SPARC64 #ifdef TARGET_SPARC64
#define hypervisor(dc) (dc->mem_idx == MMU_HYPV_IDX) #define hypervisor(dc) (dc->hypervisor)
#define supervisor(dc) (dc->supervisor | dc->hypervisor)
#else #else
#define supervisor(dc) (dc->supervisor)
#endif #endif
#endif #endif
...@@ -2134,7 +2142,11 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop) ...@@ -2134,7 +2142,11 @@ static DisasASI get_asi(DisasContext *dc, int insn, TCGMemOp memop)
case ASI_TWINX_NL: case ASI_TWINX_NL:
case ASI_NUCLEUS_QUAD_LDD: case ASI_NUCLEUS_QUAD_LDD:
case ASI_NUCLEUS_QUAD_LDD_L: case ASI_NUCLEUS_QUAD_LDD_L:
if (hypervisor(dc)) {
mem_idx = MMU_PHYS_IDX;
} else {
mem_idx = MMU_NUCLEUS_IDX; mem_idx = MMU_NUCLEUS_IDX;
}
break; break;
case ASI_AIUP: /* As if user primary */ case ASI_AIUP: /* As if user primary */
case ASI_AIUPL: /* As if user primary LE */ case ASI_AIUPL: /* As if user primary LE */
...@@ -2309,8 +2321,19 @@ static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr, ...@@ -2309,8 +2321,19 @@ static void gen_st_asi(DisasContext *dc, TCGv src, TCGv addr,
case GET_ASI_EXCP: case GET_ASI_EXCP:
break; break;
case GET_ASI_DTWINX: /* Reserved for stda. */ case GET_ASI_DTWINX: /* Reserved for stda. */
#ifndef TARGET_SPARC64
gen_exception(dc, TT_ILL_INSN); gen_exception(dc, TT_ILL_INSN);
break; break;
#else
if (!(dc->def->features & CPU_FEATURE_HYPV)) {
/* Pre OpenSPARC CPUs don't have these */
gen_exception(dc, TT_ILL_INSN);
return;
}
/* in OpenSPARC T1+ CPUs TWINX ASIs in store instructions
* are ST_BLKINIT_ ASIs */
/* fall through */
#endif
case GET_ASI_DIRECT: case GET_ASI_DIRECT:
gen_address_mask(dc, addr); gen_address_mask(dc, addr);
tcg_gen_qemu_st_tl(src, addr, da.mem_idx, da.memop); tcg_gen_qemu_st_tl(src, addr, da.mem_idx, da.memop);
...@@ -3286,7 +3309,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) ...@@ -3286,7 +3309,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
rs1 = GET_FIELD_SP(insn, 14, 18); rs1 = GET_FIELD_SP(insn, 14, 18);
if (IS_IMM) { if (IS_IMM) {
rs2 = GET_FIELD_SP(insn, 0, 6); rs2 = GET_FIELD_SP(insn, 0, 7);
if (rs1 == 0) { if (rs1 == 0) {
tcg_gen_movi_i32(trap, (rs2 & mask) + TT_TRAP); tcg_gen_movi_i32(trap, (rs2 & mask) + TT_TRAP);
/* Signal that the trap value is fully constant. */ /* Signal that the trap value is fully constant. */
...@@ -3421,6 +3444,17 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) ...@@ -3421,6 +3444,17 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
case 0x19: /* System tick compare */ case 0x19: /* System tick compare */
gen_store_gpr(dc, rd, cpu_stick_cmpr); gen_store_gpr(dc, rd, cpu_stick_cmpr);
break; break;
case 0x1a: /* UltraSPARC-T1 Strand status */
/* XXX HYPV check maybe not enough, UA2005 & UA2007 describe
* this ASR as impl. dep
*/
CHECK_IU_FEATURE(dc, HYPV);
{
TCGv t = gen_dest_gpr(dc, rd);
tcg_gen_movi_tl(t, 1UL);
gen_store_gpr(dc, rd, t);
}
break;
case 0x10: /* Performance Control */ case 0x10: /* Performance Control */
case 0x11: /* Performance Instrumentation Counter */ case 0x11: /* Performance Instrumentation Counter */
case 0x12: /* Dispatch Control */ case 0x12: /* Dispatch Control */
...@@ -3445,7 +3479,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) ...@@ -3445,7 +3479,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
rs1 = GET_FIELD(insn, 13, 17); rs1 = GET_FIELD(insn, 13, 17);
switch (rs1) { switch (rs1) {
case 0: // hpstate case 0: // hpstate
// gen_op_rdhpstate(); tcg_gen_ld_i64(cpu_dst, cpu_env,
offsetof(CPUSPARCState, hpstate));
break; break;
case 1: // htstate case 1: // htstate
// gen_op_rdhtstate(); // gen_op_rdhtstate();
...@@ -4535,8 +4570,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) ...@@ -4535,8 +4570,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
break; break;
case 16: // UA2005 gl case 16: // UA2005 gl
CHECK_IU_FEATURE(dc, GL); CHECK_IU_FEATURE(dc, GL);
tcg_gen_st32_tl(cpu_tmp0, cpu_env, gen_helper_wrgl(cpu_env, cpu_tmp0);
offsetof(CPUSPARCState, gl));
break; break;
case 26: // UA2005 strand status case 26: // UA2005 strand status
CHECK_IU_FEATURE(dc, HYPV); CHECK_IU_FEATURE(dc, HYPV);
...@@ -4570,7 +4604,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) ...@@ -4570,7 +4604,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2);
switch (rd) { switch (rd) {
case 0: // hpstate case 0: // hpstate
// XXX gen_op_wrhpstate(); tcg_gen_st_i64(cpu_tmp0, cpu_env,
offsetof(CPUSPARCState,
hpstate));
save_state(dc); save_state(dc);
gen_op_next_insn(); gen_op_next_insn();
tcg_gen_exit_tb(0); tcg_gen_exit_tb(0);
...@@ -5710,9 +5746,15 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) ...@@ -5710,9 +5746,15 @@ void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
dc->fpu_enabled = tb_fpu_enabled(tb->flags); dc->fpu_enabled = tb_fpu_enabled(tb->flags);
dc->address_mask_32bit = tb_am_enabled(tb->flags); dc->address_mask_32bit = tb_am_enabled(tb->flags);
dc->singlestep = (cs->singlestep_enabled || singlestep); dc->singlestep = (cs->singlestep_enabled || singlestep);
#ifndef CONFIG_USER_ONLY
dc->supervisor = (tb->flags & TB_FLAG_SUPER) != 0;
#endif
#ifdef TARGET_SPARC64 #ifdef TARGET_SPARC64
dc->fprs_dirty = 0; dc->fprs_dirty = 0;
dc->asi = (tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff; dc->asi = (tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff;
#ifndef CONFIG_USER_ONLY
dc->hypervisor = (tb->flags & TB_FLAG_HYPER) != 0;
#endif
#endif #endif
num_insns = 0; num_insns = 0;
......
...@@ -290,6 +290,10 @@ void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp) ...@@ -290,6 +290,10 @@ void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp)
static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate) static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate)
{ {
if (env->def->features & CPU_FEATURE_GL) {
return env->glregs + (env->gl & 7) * 8;
}
switch (pstate) { switch (pstate) {
default: default:
trace_win_helper_gregset_error(pstate); trace_win_helper_gregset_error(pstate);
...@@ -305,14 +309,40 @@ static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate) ...@@ -305,14 +309,40 @@ static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate)
} }
} }
static inline uint64_t *get_gl_gregset(CPUSPARCState *env, uint32_t gl)
{
return env->glregs + (gl & 7) * 8;
}
/* Switch global register bank */
void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl)
{
uint64_t *src, *dst;
src = get_gl_gregset(env, new_gl);
dst = get_gl_gregset(env, env->gl);
if (src != dst) {
memcpy32(dst, env->gregs);
memcpy32(env->gregs, src);
}
}
void helper_wrgl(CPUSPARCState *env, target_ulong new_gl)
{
cpu_gl_switch_gregs(env, new_gl & 7);
env->gl = new_gl & 7;
}
void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate) void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate)
{ {
uint32_t pstate_regs, new_pstate_regs; uint32_t pstate_regs, new_pstate_regs;
uint64_t *src, *dst; uint64_t *src, *dst;
if (env->def->features & CPU_FEATURE_GL) { if (env->def->features & CPU_FEATURE_GL) {
/* PS_AG is not implemented in this case */ /* PS_AG, IG and MG are not implemented in this case */
new_pstate &= ~PS_AG; new_pstate &= ~(PS_AG | PS_IG | PS_MG);
env->pstate = new_pstate;
return;
} }
pstate_regs = env->pstate & 0xc01; pstate_regs = env->pstate & 0xc01;
...@@ -366,6 +396,12 @@ void helper_done(CPUSPARCState *env) ...@@ -366,6 +396,12 @@ void helper_done(CPUSPARCState *env)
env->asi = (tsptr->tstate >> 24) & 0xff; env->asi = (tsptr->tstate >> 24) & 0xff;
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
cpu_put_cwp64(env, tsptr->tstate & 0xff); cpu_put_cwp64(env, tsptr->tstate & 0xff);
if (cpu_has_hypervisor(env)) {
uint32_t new_gl = (tsptr->tstate >> 40) & 7;
env->hpstate = env->htstate[env->tl];
cpu_gl_switch_gregs(env, new_gl);
env->gl = new_gl;
}
env->tl--; env->tl--;
trace_win_helper_done(env->tl); trace_win_helper_done(env->tl);
...@@ -387,6 +423,12 @@ void helper_retry(CPUSPARCState *env) ...@@ -387,6 +423,12 @@ void helper_retry(CPUSPARCState *env)
env->asi = (tsptr->tstate >> 24) & 0xff; env->asi = (tsptr->tstate >> 24) & 0xff;
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f);
cpu_put_cwp64(env, tsptr->tstate & 0xff); cpu_put_cwp64(env, tsptr->tstate & 0xff);
if (cpu_has_hypervisor(env)) {
uint32_t new_gl = (tsptr->tstate >> 40) & 7;
env->hpstate = env->htstate[env->tl];
cpu_gl_switch_gregs(env, new_gl);
env->gl = new_gl;
}
env->tl--; env->tl--;
trace_win_helper_retry(env->tl); trace_win_helper_retry(env->tl);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册