mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -725,6 +725,13 @@ S: Maintained
|
||||
F: hw/sparc64/sun4u.c
|
||||
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
|
||||
M: Fabien Chouteau <chouteau@adacore.com>
|
||||
S: Maintained
|
||||
|
||||
@@ -13,3 +13,5 @@ CONFIG_IDE_CMD646=y
|
||||
CONFIG_PCI_APB=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
CONFIG_SUN4V_RTC=y
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
obj-y += sparc64.o
|
||||
obj-y += sun4u.o
|
||||
obj-y += niagara.o
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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)
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
+4
-375
@@ -38,25 +38,15 @@
|
||||
#include "hw/boards.h"
|
||||
#include "hw/nvram/sun_nvram.h"
|
||||
#include "hw/nvram/chrp_nvram.h"
|
||||
#include "hw/sparc/sparc64.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ide.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
//#define DEBUG_IRQ
|
||||
//#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
|
||||
#define EBUS_DPRINTF(fmt, ...) \
|
||||
@@ -65,13 +55,6 @@
|
||||
#define EBUS_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 KERNEL_LOAD_ADDR 0x00404000
|
||||
#define CMDLINE_ADDR 0x003ff000
|
||||
#define PROM_SIZE_MAX (4 * 1024 * 1024)
|
||||
@@ -89,8 +72,6 @@
|
||||
|
||||
#define IVEC_MAX 0x40
|
||||
|
||||
#define TICK_MAX 0x7fffffffffffffffULL
|
||||
|
||||
struct hwdef {
|
||||
const char * const default_cpu_model;
|
||||
uint16_t machine_id;
|
||||
@@ -216,293 +197,11 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void isa_irq_handler(void *opaque, int n, int level)
|
||||
{
|
||||
static const int isa_irq_to_ivec[16] = {
|
||||
@@ -723,46 +422,6 @@ static const TypeInfo ram_info = {
|
||||
.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,
|
||||
MachineState *machine,
|
||||
const struct hwdef *hwdef)
|
||||
@@ -781,14 +440,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
FWCfgState *fw_cfg;
|
||||
|
||||
/* 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 */
|
||||
ram_init(0, machine->ram_size);
|
||||
|
||||
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_bus3, &pbm_irqs);
|
||||
pci_vga_init(pci_bus);
|
||||
@@ -882,7 +542,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
enum {
|
||||
sun4u_id = 0,
|
||||
sun4v_id = 64,
|
||||
niagara_id,
|
||||
};
|
||||
|
||||
static const struct hwdef hwdefs[] = {
|
||||
@@ -900,13 +559,6 @@ static const struct hwdef hwdefs[] = {
|
||||
.prom_addr = 0x1fff0000000ULL,
|
||||
.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 */
|
||||
@@ -921,12 +573,6 @@ static void sun4v_init(MachineState *machine)
|
||||
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)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
@@ -960,22 +606,6 @@ static const TypeInfo sun4v_type = {
|
||||
.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)
|
||||
{
|
||||
type_register_static(&ebus_info);
|
||||
@@ -984,7 +614,6 @@ static void sun4u_register_types(void)
|
||||
|
||||
type_register_static(&sun4u_type);
|
||||
type_register_static(&sun4v_type);
|
||||
type_register_static(&niagara_type);
|
||||
}
|
||||
|
||||
type_init(sun4u_register_types)
|
||||
|
||||
@@ -34,3 +34,5 @@ obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
|
||||
|
||||
common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
|
||||
|
||||
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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)
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
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);
|
||||
@@ -0,0 +1 @@
|
||||
void sun4v_rtc_init(hwaddr addr);
|
||||
+1
-1
@@ -1166,7 +1166,7 @@ void cpu_loop (CPUSPARCState *env)
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
if (trapnr == TT_DFAULT)
|
||||
info._sifields._sigfault._addr = env->dmmuregs[4];
|
||||
info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
|
||||
else
|
||||
info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
|
||||
+12
-2
@@ -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
|
||||
Niagara (T1) machine. The Sun4u emulator is mostly complete, being
|
||||
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:
|
||||
|
||||
@@ -2173,7 +2183,7 @@ Set OpenBIOS variables in NVRAM, for example:
|
||||
qemu-system-sparc64 -prom-env 'auto-boot?=false'
|
||||
@end example
|
||||
|
||||
@item -M [sun4u|sun4v|Niagara]
|
||||
@item -M [sun4u|sun4v|niagara]
|
||||
|
||||
Set the emulated machine type. The default is sun4u.
|
||||
|
||||
|
||||
@@ -211,6 +211,7 @@
|
||||
#define ASI_AFSR 0x4c /* Async fault status register */
|
||||
#define ASI_AFAR 0x4d /* Async fault address register */
|
||||
#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_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */
|
||||
#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */
|
||||
|
||||
+10
-3
@@ -57,9 +57,13 @@ static void sparc_cpu_reset(CPUState *s)
|
||||
env->psrps = 1;
|
||||
#endif
|
||||
#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->tl = env->maxtl;
|
||||
env->gl = 2;
|
||||
cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
|
||||
env->lsu = 0;
|
||||
#else
|
||||
@@ -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_fprintf(f, " xcc: ");
|
||||
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,
|
||||
env->psrpil);
|
||||
cpu_fprintf(f, ") asi: %02x tl: %d pil: %x gl: %d\n", env->asi, env->tl,
|
||||
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 "
|
||||
"cleanwin: %d cwp: %d\n",
|
||||
env->cansave, env->canrestore, env->otherwin, env->wstate,
|
||||
env->cleanwin, env->nwindows - 1 - env->cwp);
|
||||
cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
|
||||
TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
|
||||
|
||||
#else
|
||||
cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
|
||||
cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
|
||||
|
||||
+73
-32
@@ -68,6 +68,8 @@
|
||||
#define TT_DATA_ACCESS 0x32
|
||||
#define TT_UNALIGNED 0x34
|
||||
#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_IVEC 0x60
|
||||
#define TT_TMISS 0x64
|
||||
@@ -77,6 +79,7 @@
|
||||
#define TT_FILL 0xc0
|
||||
#define TT_WOTHER (1 << 5)
|
||||
#define TT_TRAP 0x100
|
||||
#define TT_HTRAP 0x180
|
||||
#endif
|
||||
|
||||
#define PSR_NEG_SHIFT 23
|
||||
@@ -227,7 +230,7 @@ enum {
|
||||
#if !defined(TARGET_SPARC64)
|
||||
#define NB_MMU_MODES 3
|
||||
#else
|
||||
#define NB_MMU_MODES 7
|
||||
#define NB_MMU_MODES 6
|
||||
typedef struct trap_state {
|
||||
uint64_t tpc;
|
||||
uint64_t tnpc;
|
||||
@@ -302,21 +305,42 @@ enum {
|
||||
#define TTE_W_OK_BIT (1ULL << 1)
|
||||
#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_NFO(tte) ((tte) & TTE_NFO_BIT)
|
||||
#define TTE_IS_USED(tte) ((tte) & TTE_USED_BIT)
|
||||
#define TTE_IS_LOCKED(tte) ((tte) & TTE_LOCKED_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_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_SET_USED(tte) ((tte) |= TTE_USED_BIT)
|
||||
#define TTE_SET_UNUSED(tte) ((tte) &= ~TTE_USED_BIT)
|
||||
|
||||
#define TTE_PGSIZE(tte) (((tte) >> 61) & 3ULL)
|
||||
#define TTE_PGSIZE_UA2005(tte) ((tte) & 7ULL)
|
||||
#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_TM_BIT (1ULL << 15) /* JPS1 TLB Miss */
|
||||
#define SFSR_FT_VA_IMMU_BIT (1ULL << 13) /* USIIi VA out of range (IMMU) */
|
||||
@@ -360,6 +384,9 @@ enum {
|
||||
#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
|
||||
#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 {
|
||||
uint64_t tag;
|
||||
uint64_t tte;
|
||||
@@ -380,7 +407,24 @@ struct CPUTimer
|
||||
typedef struct CPUTimer CPUTimer;
|
||||
|
||||
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 {
|
||||
target_ulong gregs[8]; /* general registers */
|
||||
target_ulong *regwptr; /* pointer to current register window */
|
||||
@@ -433,31 +477,8 @@ struct CPUSPARCState {
|
||||
uint64_t lsu;
|
||||
#define DMMU_E 0x8
|
||||
#define IMMU_E 0x4
|
||||
//typedef struct SparcMMU
|
||||
union {
|
||||
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;
|
||||
};
|
||||
SparcV9MMU immu;
|
||||
SparcV9MMU dmmu;
|
||||
SparcTLBEntry itlb[64];
|
||||
SparcTLBEntry dtlb[64];
|
||||
uint32_t mmu_version;
|
||||
@@ -487,6 +508,7 @@ struct CPUSPARCState {
|
||||
uint64_t bgregs[8]; /* backup for normal global registers */
|
||||
uint64_t igregs[8]; /* interrupt general registers */
|
||||
uint64_t mgregs[8]; /* mmu general registers */
|
||||
uint64_t glregs[8 * MAXTL_MAX];
|
||||
uint64_t fprs;
|
||||
uint64_t tick_cmpr, stick_cmpr;
|
||||
CPUTimer *tick, *stick;
|
||||
@@ -496,6 +518,7 @@ struct CPUSPARCState {
|
||||
uint32_t gl; // UA2005
|
||||
/* UA 2005 hyperprivileged registers */
|
||||
uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
|
||||
uint64_t scratch[8];
|
||||
CPUTimer *hstick; // UA 2005
|
||||
/* Interrupt vector registers */
|
||||
uint64_t ivec_status;
|
||||
@@ -586,6 +609,7 @@ void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
|
||||
target_ulong cpu_get_cwp64(CPUSPARCState *env1);
|
||||
void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
|
||||
void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
|
||||
void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl);
|
||||
#endif
|
||||
int cpu_cwp_inc(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);
|
||||
#define MMU_KERNEL_IDX 2
|
||||
#define MMU_KERNEL_SECONDARY_IDX 3
|
||||
#define MMU_NUCLEUS_IDX 4
|
||||
#define MMU_HYPV_IDX 5
|
||||
#define MMU_PHYS_IDX 6
|
||||
#define MMU_PHYS_IDX 5
|
||||
#else
|
||||
#define MMU_USER_IDX 0
|
||||
#define MMU_KERNEL_IDX 1
|
||||
@@ -668,6 +691,11 @@ static inline int cpu_supervisor_mode(CPUSPARCState *env1)
|
||||
{
|
||||
return env1->pstate & PS_PRIV;
|
||||
}
|
||||
#else
|
||||
static inline int cpu_supervisor_mode(CPUSPARCState *env1)
|
||||
{
|
||||
return env1->psrs;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 & DMMU_E) == 0) {
|
||||
return MMU_PHYS_IDX;
|
||||
} else if (cpu_hypervisor_mode(env)) {
|
||||
return MMU_PHYS_IDX;
|
||||
} else if (env->tl > 0) {
|
||||
return MMU_NUCLEUS_IDX;
|
||||
} else if (cpu_hypervisor_mode(env)) {
|
||||
return MMU_HYPV_IDX;
|
||||
} else if (cpu_supervisor_mode(env)) {
|
||||
return MMU_KERNEL_IDX;
|
||||
} else {
|
||||
@@ -704,8 +732,9 @@ static inline int cpu_interrupts_enabled(CPUSPARCState *env1)
|
||||
if (env1->psret != 0)
|
||||
return 1;
|
||||
#else
|
||||
if (env1->pstate & PS_IE)
|
||||
if ((env1->pstate & PS_IE) && !cpu_hypervisor_mode(env1)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -734,6 +763,8 @@ trap_state* cpu_tsptr(CPUSPARCState* env);
|
||||
#define TB_FLAG_MMU_MASK 7
|
||||
#define TB_FLAG_FPU_ENABLED (1 << 4)
|
||||
#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
|
||||
|
||||
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;
|
||||
*cs_base = env->npc;
|
||||
flags = cpu_mmu_index(env, false);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu_supervisor_mode(env)) {
|
||||
flags |= TB_FLAG_SUPER;
|
||||
}
|
||||
#endif
|
||||
#ifdef TARGET_SPARC64
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (cpu_hypervisor_mode(env)) {
|
||||
flags |= TB_FLAG_HYPER;
|
||||
}
|
||||
#endif
|
||||
if (env->pstate & PS_AM) {
|
||||
flags |= TB_FLAG_AM_ENABLED;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ DEF_HELPER_1(rdpsr, tl, env)
|
||||
DEF_HELPER_1(power_down, void, env)
|
||||
#else
|
||||
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_1(done, void, env)
|
||||
DEF_HELPER_1(retry, void, env)
|
||||
|
||||
@@ -78,8 +78,10 @@ void sparc_cpu_do_interrupt(CPUState *cs)
|
||||
static int count;
|
||||
const char *name;
|
||||
|
||||
if (intno < 0 || intno >= 0x180) {
|
||||
if (intno < 0 || intno >= 0x1ff) {
|
||||
name = "Unknown";
|
||||
} else if (intno >= 0x180) {
|
||||
name = "Hyperprivileged Trap Instruction";
|
||||
} else if (intno >= 0x100) {
|
||||
name = "Trap Instruction";
|
||||
} else if (intno >= 0xc0) {
|
||||
@@ -135,16 +137,42 @@ void sparc_cpu_do_interrupt(CPUState *cs)
|
||||
tsptr->tnpc = env->npc;
|
||||
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) {
|
||||
case TT_IVEC:
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
|
||||
if (!cpu_has_hypervisor(env)) {
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
|
||||
}
|
||||
break;
|
||||
case TT_TFAULT:
|
||||
case TT_DFAULT:
|
||||
case TT_TMISS ... TT_TMISS + 3:
|
||||
case TT_DMISS ... TT_DMISS + 3:
|
||||
case TT_DPROT ... TT_DPROT + 3:
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case TT_INSN_REAL_TRANSLATION_MISS ... TT_DATA_REAL_TRANSLATION_MISS:
|
||||
case TT_HTRAP ... TT_HTRAP + 127:
|
||||
env->hpstate |= HS_PRIV;
|
||||
break;
|
||||
default:
|
||||
cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
|
||||
@@ -158,8 +186,13 @@ void sparc_cpu_do_interrupt(CPUState *cs)
|
||||
} else if ((intno & 0x1c0) == TT_FILL) {
|
||||
cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
|
||||
}
|
||||
env->pc = env->tbr & ~0x7fffULL;
|
||||
env->pc |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
|
||||
|
||||
if (cpu_hypervisor_mode(env)) {
|
||||
env->pc = (env->htba & ~0x3fffULL) | (intno << 5);
|
||||
} else {
|
||||
env->pc = env->tbr & ~0x7fffULL;
|
||||
env->pc |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
|
||||
}
|
||||
env->npc = env->pc + 4;
|
||||
cs->exception_index = -1;
|
||||
}
|
||||
|
||||
+309
-78
File diff suppressed because it is too large
Load Diff
@@ -148,8 +148,8 @@ const VMStateDescription vmstate_sparc_cpu = {
|
||||
VMSTATE_UINT64_ARRAY(env.mmubpregs, SPARCCPU, 4),
|
||||
#else
|
||||
VMSTATE_UINT64(env.lsu, SPARCCPU),
|
||||
VMSTATE_UINT64_ARRAY(env.immuregs, SPARCCPU, 16),
|
||||
VMSTATE_UINT64_ARRAY(env.dmmuregs, SPARCCPU, 16),
|
||||
VMSTATE_UINT64_ARRAY(env.immu.mmuregs, SPARCCPU, 16),
|
||||
VMSTATE_UINT64_ARRAY(env.dmmu.mmuregs, SPARCCPU, 16),
|
||||
VMSTATE_STRUCT_ARRAY(env.itlb, SPARCCPU, 64, 0,
|
||||
vmstate_tlb_entry, SparcTLBEntry),
|
||||
VMSTATE_STRUCT_ARRAY(env.dtlb, SPARCCPU, 64, 0,
|
||||
|
||||
@@ -456,23 +456,7 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
|
||||
uint64_t address, uint64_t context,
|
||||
hwaddr *physical)
|
||||
{
|
||||
uint64_t mask;
|
||||
|
||||
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;
|
||||
}
|
||||
uint64_t mask = -(8192ULL << 3 * TTE_PGSIZE(tlb->tte));
|
||||
|
||||
/* valid, context match, virtual address match? */
|
||||
if (TTE_IS_VALID(tlb->tte) &&
|
||||
@@ -757,6 +741,8 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
|
||||
PRId64 "\n",
|
||||
env->dmmu.mmu_primary_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) {
|
||||
(*cpu_fprintf)(f, "DMMU disabled\n");
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user