Compare commits

...

8 Commits

Author SHA1 Message Date
Alibek Omarov af82362cd6 hw/sparc64: add basic NBSR implementation (only traces calls)
* IOHub implementation must be moved from e2k branch where it's almost works

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-13 21:09:48 +03:00
Alibek Omarov 1a7bf88bfb hw/intc/apic: expose APICBASE through register 0x01 for Elbrus 90S
Should be disabled for other CPUs!

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-07 04:59:56 +03:00
Alibek Omarov 343be8ce22 target/sparc: first attempt at wiring APIC to virtualized SPARC CPU
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-07 04:59:22 +03:00
Alibek Omarov 1b0f6c544b hw/intc/apic: add few macros to reference SPARCCPU instead of x86 in APIC code
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-07 04:57:22 +03:00
Alibek Omarov aca1aef5bb hw/intc/apic: make apic_mem_* functions public so they can be called from ASI sparc helper
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-07 04:55:11 +03:00
Alibek Omarov 3dc681a5ff target/sparc: add ASI_LAPIC definition for E90S
Add ASI_LAPIC support in disas as well

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-07 04:48:14 +03:00
Alibek Omarov 0c54dd11a7 hw/sparc64/e90s: add basic Elbrus-90S machine defintion
Does nothing useful right now.
Crashes almost instantly somewhere in firmware code, needs APIC to be enabled.

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-06 01:00:18 +03:00
Alibek Omarov bd659fcbdb target/sparc: add basic definitions for Elbrus R1000 and R2000
Allows me to select Elbrus CPU in E90S machine, and distinguish
MCST extensions in ASI emulation code.

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2023-04-06 00:50:35 +03:00
14 changed files with 438 additions and 5 deletions

View File

@ -10,3 +10,4 @@
#
CONFIG_SUN4U=y
CONFIG_NIAGARA=y
CONFIG_E90S=y

View File

@ -2139,6 +2139,7 @@ static const arg asi_table_v9[] =
{ 0x67, "#ASI_IC_TAG"},
/* FIXME: There are dozens of them. Not sure we want them all.
Most are for kernel building but some are for vis type stuff. */
{ 0x68, "#ASI_LAPIC"},
{ 0, NULL }
};

View File

@ -636,7 +636,7 @@ static void apic_timer(void *opaque)
apic_timer_update(s, s->next_time);
}
static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
{
DeviceState *dev;
APICCommonState *s;
@ -655,6 +655,9 @@ static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
index = (addr >> 4) & 0xff;
switch(index) {
case 0x01: /* elbrus bsp */
val = s->apicbase;
break;
case 0x02: /* id */
val = s->id << 24;
break;
@ -737,7 +740,7 @@ static void apic_send_msi(MSIMessage *msi)
apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
}
static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
DeviceState *dev;

View File

@ -19,3 +19,9 @@ config NIAGARA
select EMPTY_SLOT
select SUN4V_RTC
select UNIMP
config E90S
bool
select ESCC
select APIC
select IOAPIC

236
hw/sparc64/e90s.c Normal file
View File

@ -0,0 +1,236 @@
#include "qemu/osdep.h"
#include "qemu/datadir.h"
#include "qemu/error-report.h"
#include "qemu/typedefs.h"
#include "qemu/units.h"
#include "qom/object.h"
#include "qapi/error.h"
#include "elf.h"
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/qdev-properties.h"
#include "hw/char/escc.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
#include "hw/sparc/sparc64.h"
#include "hw/sparc/sun4u_iommu.h"
#include "migration/vmstate.h"
#include "sysemu/sysemu.h"
#include "cpu.h"
#include "trace.h"
// memory map
#define PROM_BASE 0xFFFF000000UL // bootloader
#define PCIIO_BASE 0xFF20000000UL
#define PEXCFG_BASE 0xFF10000000UL // pci express configuration registers
#define NBSR_BASE 0xFE00000000UL // north bridge system registers (?)
#define NBSR_SIZE (1 * MiB)
#define PROM_SIZE_MAX (16 * MiB)
#define PROM_FILENAME "_4R.bin"
#define ESCC_CLOCK 4915200 // TODO: why?
#define TYPE_E90S MACHINE_TYPE_NAME("e90s")
#define TYPE_E90S_NBSR "e90s-nbsr"
#define TYPE_E90S_IOHUB "e90s-iohub"
typedef struct E90SState {
MemoryRegion prom;
MemoryRegion nbsr;
} E90SState;
DECLARE_INSTANCE_CHECKER(E90SState, E90S, TYPE_E90S)
typedef struct NBSRState {
SysBusDevice parent_obj;
MemoryRegion region;
} NBSRState;
DECLARE_INSTANCE_CHECKER(NBSRState, NBSR, TYPE_E90S_NBSR)
typedef struct IOHubState {
PCIHostState parent_obj;
MemoryRegion pci_cfg;
MemoryRegion pci_io;
MemoryRegion pci_mmio;
} IOHubState;
DECLARE_INSTANCE_CHECKER(IOHubState, IOHUB, TYPE_E90S_IOHUB)
/* North Bridge System Registers */
static uint64_t nbsr_read(void *opaque, hwaddr addr, unsigned size)
{
trace_nbsr_read(addr, 0, size);
return 0;
}
static void nbsr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
trace_nbsr_write(addr, val, size);
}
static const MemoryRegionOps nbsr_ops = {
.read = nbsr_read,
.write = nbsr_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void nbsr_realize(DeviceState *d, Error **errp)
{
NBSRState *nbsr = NBSR(d);
memory_region_init_io(&nbsr->region, OBJECT(d),
&nbsr_ops, OBJECT(d), "e90s.nbsr", NBSR_SIZE);
memory_region_add_subregion(get_system_memory(), NBSR_BASE,
&nbsr->region);
}
static void nbsr_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = nbsr_realize;
}
static const TypeInfo nbsr_info = {
.name = TYPE_E90S_NBSR,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(NBSRState),
.class_init = nbsr_class_init,
};
/* IOHub */
/* TODO: move to hw/pci/ */
static void pci_iohub_set_irq(void *opaque, int irq_num, int level)
{
// TODO:
}
static int pci_iohub_map_irq(PCIDevice *pci_dev, int irq_num)
{
return irq_num;
}
static void iohub_realize(DeviceState *dev, Error **errp)
{
IOHubState *s = IOHUB(dev);
PCIHostState *phb = PCI_HOST_BRIDGE(dev);
phb->bus = pci_register_root_bus(dev, "pci", pci_iohub_set_irq, pci_iohub_map_irq,
s, &s->pci_mmio, &s->pci_io, 0, 0x40, TYPE_PCI_BUS);
// pci_create_simple(phb->bus, 0, TYPE_IOHUB_PCI_DEVICE);
}
static void iohub_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = iohub_realize;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "pci";
}
const TypeInfo iohub_info = {
.name = TYPE_E90S_IOHUB,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(IOHubState),
.class_init = iohub_class_init,
};
static void pci_init(E90SState *e90s)
{
#if 0
dev = qdev_new(TYPE_ESCC);
qdev_prop_set_uint32(dev, "disabled", 0);
qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(dev, "it_shift", 0);
qdev_prop_set_chr(dev, "chrB", serial_hd(1));
qdev_prop_set_chr(dev, "chrA", serial_hd(0));
qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
sb = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sb, &error_fatal);
sysbus_mmio_map(sb, 0, ELBRUS_SCC_START);
#endif
}
/* Boot PROM */
static void prom_init(hwaddr addr, const char *bios_name)
{
char *filename;
int ret;
/* load boot prom */
if (bios_name == NULL) {
bios_name = PROM_FILENAME;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
// as we're working with raw images, no elf parsing needed
ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
g_free(filename);
} else {
ret = -1;
}
if (ret < 0 || ret > PROM_SIZE_MAX) {
error_report("could not load prom '%s'", bios_name);
exit(1);
}
}
static void e90s_init(MachineState *machine)
{
E90SState *s = E90S(machine);
DeviceState *dev;
SysBusDevice *sb;
// SPARCCPU *cpu;
/* init CPUs */
sparc64_cpu_devinit(machine->cpu_type, PROM_BASE);
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
memory_region_init_ram(&s->prom, OBJECT(machine),
"e90s.prom", PROM_SIZE_MAX, &error_fatal);
memory_region_add_subregion(get_system_memory(), PROM_BASE, &s->prom);
prom_init(PROM_BASE, machine->firmware);
dev = qdev_new(TYPE_E90S_NBSR);
sb = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sb, &error_fatal);
pci_init(s);
}
static void e90s_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "E90S platform";
mc->init = e90s_init;
mc->max_cpus = 1; /* XXX for now */
mc->default_boot_order = "c";
mc->default_cpu_type = SPARC_CPU_TYPE_NAME("MCST-Elbrus-R1000");
mc->default_ram_id = "e90s.ram";
}
static const TypeInfo e90s_info = {
.name = MACHINE_TYPE_NAME("e90s"),
.parent = TYPE_MACHINE,
.class_init = e90s_class_init,
};
static void e90s_register_types(void)
{
type_register_static(&nbsr_info);
// type_register_static(&iohub_info);
type_register_static(&e90s_info);
}
type_init(e90s_register_types)

View File

@ -2,5 +2,6 @@ sparc64_ss = ss.source_set()
sparc64_ss.add(files('sparc64.c'))
sparc64_ss.add(when: 'CONFIG_NIAGARA', if_true: files('niagara.c'))
sparc64_ss.add(when: 'CONFIG_SUN4U', if_true: files('sun4u.c', 'sun4u_iommu.c'))
sparc64_ss.add(when: 'CONFIG_E90S', if_true: files('e90s.c'))
hw_arch += {'sparc64': sparc64_ss}

View File

@ -30,10 +30,27 @@
#include "qemu/timer.h"
#include "sysemu/reset.h"
#include "trace.h"
#include "qapi/error.h"
#include "hw/i386/apic_internal.h"
#define TICK_MAX 0x7fffffffffffffffULL
DeviceState *cpu_get_current_apic(void)
{
if (current_cpu) {
SPARCCPU *cpu = SPARC_CPU(current_cpu);
return cpu->apic_state;
} else {
return NULL;
}
}
void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip,
TPRAccess access)
{
// TODO: stub!
}
static void cpu_kick_irq(SPARCCPU *cpu)
{
CPUState *cs = CPU(cpu);
@ -271,7 +288,9 @@ SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr)
uint32_t stick_frequency = 100 * 1000000;
uint32_t hstick_frequency = 100 * 1000000;
cpu = SPARC_CPU(cpu_create(cpu_type));
cpu = SPARC_CPU(object_new(cpu_type));
object_property_set_uint(OBJECT(cpu), "apic-id", 0, &error_fatal);
qdev_realize(DEVICE(cpu), NULL, &error_fatal);
qdev_init_gpio_in_named(DEVICE(cpu), sparc64_cpu_set_ivec_irq,
"ivec-irq", IVEC_MAX);
env = &cpu->env;

View File

@ -1,5 +1,9 @@
# See docs/devel/tracing.rst for syntax documentation.
# e90s.c
nbsr_read(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d"
nbsr_write(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d"
# sun4u.c
ebus_isa_irq_handler(int n, int level) "Set ISA IRQ %d level %d"
@ -21,3 +25,4 @@ sparc64_cpu_tick_set_count(const char *name, uint64_t real_count, const char *np
sparc64_cpu_tick_get_count(const char *name, uint64_t real_count, const char *npt, void *p) "%s get_count count=0x%"PRIx64" (npt %s) p=%p"
sparc64_cpu_tick_set_limit(const char *name, uint64_t real_limit, const char *dis, void *p, uint64_t limit, uint64_t t, uint64_t dt) "%s set_limit limit=0x%"PRIx64 " (%s) p=%p called with limit=0x%"PRIx64" at 0x%"PRIx64" (delta=0x%"PRIx64")"
sparc64_cpu_tick_set_limit_zero(const char *name) "%s set_limit limit=ZERO - not starting timer"

View File

@ -1,6 +1,7 @@
#ifndef APIC_H
#define APIC_H
#include "exec/hwaddr.h"
/* apic.c */
void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
@ -18,6 +19,8 @@ void apic_sipi(DeviceState *s);
void apic_poll_irq(DeviceState *d);
void apic_designate_bsp(DeviceState *d, bool bsp);
int apic_get_highest_priority_irr(DeviceState *dev);
void apic_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size);
uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size);
/* pc.c */
DeviceState *cpu_get_current_apic(void);

View File

@ -24,7 +24,11 @@
#include "cpu.h"
#include "exec/memory.h"
#include "qemu/timer.h"
#if defined(TARGET_SPARC) || defined(TARGET_SPARC64)
#include "target/sparc/cpu-qom.h"
#else
#include "target/i386/cpu-qom.h"
#endif
#include "qom/object.h"
/* APIC Local Vector Table */
@ -156,7 +160,11 @@ struct APICCommonState {
/*< public >*/
MemoryRegion io_memory;
#if defined(TARGET_SPARC) || defined(TARGET_SPARC64)
SPARCCPU *cpu;
#else
X86CPU *cpu;
#endif
uint32_t apicbase;
uint8_t id; /* legacy APIC ID */
uint32_t initial_apic_id;

View File

@ -142,7 +142,7 @@
* UltraSparc-III and later specific ASIs. The "(CMT)" marker designates
* Chip Multi Threading specific ASIs. "(NG)" designates Niagara specific
* ASIs, "(4V)" designates SUN4V specific ASIs. "(NG4)" designates SPARC-T4
* and later ASIs.
* and later ASIs. "(E90)" designates Elbrus-90S specific ASIs.
*/
#define ASI_REAL 0x14 /* Real address, cachable */
#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */
@ -234,6 +234,7 @@
#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */
#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */
#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */
#define ASI_LAPIC 0x68 /* (E90S) LAPIC register */
#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */
#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag */
#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag*/

View File

@ -26,9 +26,42 @@
#include "hw/qdev-properties.h"
#include "qapi/visitor.h"
#include "tcg/tcg.h"
#include "hw/i386/apic_internal.h"
//#define DEBUG_FEATURES
#ifndef CONFIG_USER_ONLY
APICCommonClass *apic_get_class(Error **errp)
{
return APIC_COMMON_CLASS(object_class_by_name("apic"));
}
static void sparc_cpu_apic_create(SPARCCPU *cpu, Error **errp)
{
APICCommonState *apic;
APICCommonClass *apic_class = apic_get_class(errp);
if (!apic_class)
return;
cpu->apic_state = DEVICE(object_new_with_class(OBJECT_CLASS(apic_class)));
object_property_add_child(OBJECT(cpu), "lapic", OBJECT(cpu->apic_state));
object_unref(cpu->apic_state);
object_property_set_bool(OBJECT(cpu->apic_state), "vapic", false, errp);
qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
apic = APIC_COMMON(cpu->apic_state);
apic->cpu = cpu;
apic->apicbase = MSR_IA32_APICBASE_ENABLE; // don't care about the address, it's handled through ASI
}
static void sparc_cpu_apic_realize(SPARCCPU *cpu, Error **errp)
{
qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
}
#endif
static void sparc_cpu_reset_hold(Object *obj)
{
CPUState *s = CPU(obj);
@ -60,6 +93,7 @@ static void sparc_cpu_reset_hold(Object *obj)
env->psrs = 1;
env->psrps = 1;
#endif
apic_designate_bsp(cpu->apic_state, s->cpu_index == 0);
#ifdef TARGET_SPARC64
env->pstate = PS_PRIV | PS_RED | PS_PEF;
if (!cpu_has_hypervisor(env)) {
@ -365,6 +399,24 @@ static const sparc_def_t sparc_defs[] = {
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES,
},
{
.name = "MCST Elbrus R1000", /* also called 4R */
.iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)), /* TODO: why? */
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_ELBRUS_R1000,
},
{
.name = "MCST Elbrus R2000", /* also called Sapphire */
.iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)), /* TODO: why? */
.fpu_version = 0x00000000,
.mmu_version = mmu_us_12,
.nwindows = 8,
.maxtl = 5,
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_ELBRUS_R1000 | CPU_FEATURE_ELBRUS_R2000,
},
#else
{
.name = "Fujitsu MB86904",
@ -782,7 +834,32 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
return;
}
#if !defined(CONFIG_USER_ONLY)
if (env->def.features & CPU_FEATURE_ELBRUS_R1000) {
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
error_setg(errp, "apic-id property was not initialized properly");
return;
}
sparc_cpu_apic_create(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
}
#endif
qemu_init_vcpu(cs);
#if !defined(CONFIG_USER_ONLY)
if (env->def.features & CPU_FEATURE_ELBRUS_R1000) {
sparc_cpu_apic_realize(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
}
#endif
scc->parent_realize(dev, errp);
}
@ -858,6 +935,7 @@ static Property sparc_cpu_properties[] = {
DEFINE_PROP_UINT32("mmu-version", SPARCCPU, env.def.mmu_version, 0),
DEFINE_PROP("nwindows", SPARCCPU, env.def.nwindows,
qdev_prop_nwindows, uint32_t),
DEFINE_PROP_UINT32("apic-id", SPARCCPU, apic_id, UNASSIGNED_APIC_ID),
DEFINE_PROP_END_OF_LIST()
};

View File

@ -6,6 +6,10 @@
#include "exec/cpu-defs.h"
#include "qemu/cpu-float.h"
#ifndef CONFIG_USER_ONLY
#include "hw/i386/apic.h"
#endif
#if !defined(TARGET_SPARC64)
#define TARGET_DPREGS 16
#else
@ -287,6 +291,8 @@ struct sparc_def_t {
#define CPU_FEATURE_CACHE_CTRL (1 << 16)
#define CPU_FEATURE_POWERDOWN (1 << 17)
#define CPU_FEATURE_CASA (1 << 18)
#define CPU_FEATURE_ELBRUS_R1000 (1 << 19) /* Elbrus R1000-specific extensions (few packed insns) */
#define CPU_FEATURE_ELBRUS_R2000 (1 << 20) /* Elbrus R2000-specific extensions (HWCAP_SAPPHIRE) */
#ifndef TARGET_SPARC64
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
@ -420,6 +426,32 @@ struct CPUTimer
typedef struct CPUTimer CPUTimer;
#define UNASSIGNED_APIC_ID 0xFFFFFFFF
#define APIC_DEFAULT_ADDRESS 0xfee00000
#define APIC_SPACE_SIZE 0x100000
#define MSR_IA32_APICBASE 0x1b
#define MSR_IA32_APICBASE_BSP (1<<8)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_EXTD (1 << 10)
#define MSR_IA32_APICBASE_BASE (0xfffffU<<12)
/* i386-specific interrupt pending bits. */
#define CPU_INTERRUPT_POLL CPU_INTERRUPT_TGT_EXT_1
#define CPU_INTERRUPT_SMI CPU_INTERRUPT_TGT_EXT_2
#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3
#define CPU_INTERRUPT_MCE CPU_INTERRUPT_TGT_EXT_4
#define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_INT_0
#define CPU_INTERRUPT_SIPI CPU_INTERRUPT_TGT_INT_1
#define CPU_INTERRUPT_TPR CPU_INTERRUPT_TGT_INT_2
typedef enum TPRAccess {
TPR_ACCESS_READ,
TPR_ACCESS_WRITE,
} TPRAccess;
/* Use a clearer name for this. */
#define CPU_INTERRUPT_INIT CPU_INTERRUPT_RESET
typedef struct CPUArchState CPUSPARCState;
#if defined(TARGET_SPARC64)
typedef union {
@ -563,6 +595,10 @@ struct ArchCPU {
CPUNegativeOffsetState neg;
CPUSPARCState env;
/* Elbrus APIC */
struct DeviceState *apic_state;
uint32_t apic_id;
};
@ -651,6 +687,9 @@ void sparc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
int mmu_idx);
#endif
void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
TPRAccess access);
#endif
#define SPARC_CPU_TYPE_SUFFIX "-" TYPE_SPARC_CPU
@ -817,6 +856,29 @@ static inline bool tb_am_enabled(int tb_flags)
#endif
}
#ifndef CONFIG_USER_ONLY
static inline void cpu_clear_apic_feature(CPUArchState *env)
{
env->def.features &= ~(CPU_FEATURE_ELBRUS_R1000|CPU_FEATURE_ELBRUS_R2000);
}
static inline void cpu_x86_load_seg_cache_sipi(ArchCPU *cpu, uint8_t sipi_vector)
{
// TODO:
abort();
}
static inline void cpu_report_tpr_access(CPUArchState *env, TPRAccess access)
{
// TODO:
}
static inline bool cpu_is_bsp(ArchCPU *cpu)
{
return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP;
}
#endif
#ifdef TARGET_SPARC64
/* win_helper.c */
target_ulong cpu_get_ccr(CPUSPARCState *env1);

View File

@ -25,6 +25,9 @@
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "asi.h"
#ifndef CONFIG_USER_ONLY
#include "hw/i386/apic.h"
#endif
//#define DEBUG_MMU
//#define DEBUG_MXCC
@ -1564,6 +1567,9 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
case ASI_EC_W: /* E-cache tag */
case ASI_EC_R: /* E-cache tag */
break;
case ASI_LAPIC: /* Elbrus LAPIC access */
ret = apic_mem_read(NULL, addr, size);
break;
case ASI_DMMU_TSB_DIRECT_PTR: /* D-MMU data pointer */
case ASI_ITLB_DATA_IN: /* I-MMU data in, WO */
case ASI_IMMU_DEMAP: /* I-MMU demap, WO */
@ -1917,6 +1923,9 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
case ASI_EC_W: /* E-cache tag */
case ASI_EC_R: /* E-cache tag */
return;
case ASI_LAPIC: /* Elbrus LAPIC access */
apic_mem_write(NULL, addr, val, size);
break;
case ASI_IMMU_TSB_8KB_PTR: /* I-MMU 8k TSB pointer, RO */
case ASI_IMMU_TSB_64KB_PTR: /* I-MMU 64k TSB pointer, RO */
case ASI_ITLB_TAG_READ: /* I-MMU tag read, RO */