Merge remote-tracking branch 'elbrus/e2k' into e2k-bsd-user
This commit is contained in:
commit
22dbdd7c74
24
MAINTAINERS
24
MAINTAINERS
|
@ -212,6 +212,13 @@ S: Maintained
|
|||
F: target/hppa/
|
||||
F: disas/hppa.c
|
||||
|
||||
LoongArch TCG CPUs
|
||||
M: Song Gao <gaosong@loongson.cn>
|
||||
M: Xiaojuan Yang <yangxiaojuan@loongson.cn>
|
||||
S: Maintained
|
||||
F: target/loongarch/
|
||||
F: tests/tcg/loongarch64/
|
||||
|
||||
M68K TCG CPUs
|
||||
M: Laurent Vivier <laurent@vivier.eu>
|
||||
S: Maintained
|
||||
|
@ -1116,6 +1123,23 @@ F: include/hw/net/lasi_82596.h
|
|||
F: include/hw/pci-host/dino.h
|
||||
F: pc-bios/hppa-firmware.img
|
||||
|
||||
LoongArch Machines
|
||||
------------------
|
||||
Virt
|
||||
M: Xiaojuan Yang <yangxiaojuan@loongson.cn>
|
||||
M: Song Gao <gaosong@loongson.cn>
|
||||
S: Maintained
|
||||
F: docs/system/loongarch/loongson3.rst
|
||||
F: configs/targets/loongarch64-softmmu.mak
|
||||
F: configs/devices/loongarch64-softmmu/default.mak
|
||||
F: hw/loongarch/
|
||||
F: include/hw/loongarch/virt.h
|
||||
F: include/hw/intc/loongarch_*.h
|
||||
F: hw/intc/loongarch_*.c
|
||||
F: include/hw/pci-host/ls7a.h
|
||||
F: hw/rtc/ls7a_rtc.c
|
||||
F: gdb-xml/loongarch*.xml
|
||||
|
||||
M68K Machines
|
||||
-------------
|
||||
an5206
|
||||
|
|
|
@ -120,12 +120,12 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
|||
{
|
||||
hvf_slot *mem;
|
||||
MemoryRegion *area = section->mr;
|
||||
bool writeable = !area->readonly && !area->rom_device;
|
||||
bool writable = !area->readonly && !area->rom_device;
|
||||
hv_memory_flags_t flags;
|
||||
uint64_t page_size = qemu_real_host_page_size();
|
||||
|
||||
if (!memory_region_is_ram(area)) {
|
||||
if (writeable) {
|
||||
if (writable) {
|
||||
return;
|
||||
} else if (!memory_region_is_romd(area)) {
|
||||
/*
|
||||
|
|
|
@ -1346,13 +1346,13 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
|
|||
KVMSlot *mem;
|
||||
int err;
|
||||
MemoryRegion *mr = section->mr;
|
||||
bool writeable = !mr->readonly && !mr->rom_device;
|
||||
bool writable = !mr->readonly && !mr->rom_device;
|
||||
hwaddr start_addr, size, slot_size, mr_offset;
|
||||
ram_addr_t ram_start_offset;
|
||||
void *ram;
|
||||
|
||||
if (!memory_region_is_ram(mr)) {
|
||||
if (writeable || !kvm_readonly_mem_allowed) {
|
||||
if (writable || !kvm_readonly_mem_allowed) {
|
||||
return;
|
||||
} else if (!mr->romd_mode) {
|
||||
/* If the memory device is not in romd_mode, then we actually want
|
||||
|
|
|
@ -101,10 +101,10 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write)
|
|||
* Return true if the write fault has been handled, and should be re-tried.
|
||||
*
|
||||
* Note that it is important that we don't call page_unprotect() unless
|
||||
* this is really a "write to nonwriteable page" fault, because
|
||||
* this is really a "write to nonwritable page" fault, because
|
||||
* page_unprotect() assumes that if it is called for an access to
|
||||
* a page that's writeable this means we had two threads racing and
|
||||
* another thread got there first and already made the page writeable;
|
||||
* a page that's writable this means we had two threads racing and
|
||||
* another thread got there first and already made the page writable;
|
||||
* so we will retry the access. If we were to call page_unprotect()
|
||||
* for some other kind of fault that should really be passed to the
|
||||
* guest, we'd end up in an infinite loop of retrying the faulting access.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Default configuration for loongarch64-softmmu
|
||||
|
||||
CONFIG_LOONGARCH_VIRT=y
|
|
@ -0,0 +1,2 @@
|
|||
TARGET_ARCH=e2k
|
||||
TARGET_XML_FILES= gdb-xml/e2k-v1.xml gdb-xml/e2k-v2.xml gdb-xml/e2k-v3.xml gdb-xml/e2k-v5.xml
|
|
@ -0,0 +1,5 @@
|
|||
TARGET_ARCH=e2k32
|
||||
TARGET_BASE_ARCH=e2k
|
||||
TARGET_ABI_DIR=e2k
|
||||
TARGET_ABI32=y
|
||||
TARGET_XML_FILES= gdb-xml/e2k-v1.xml gdb-xml/e2k-v2.xml gdb-xml/e2k-v3.xml gdb-xml/e2k-v5.xml
|
|
@ -0,0 +1,4 @@
|
|||
TARGET_ARCH=loongarch64
|
||||
TARGET_BASE_ARCH=loongarch
|
||||
TARGET_SUPPORTS_MTTCG=y
|
||||
TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
|
|
@ -1837,6 +1837,7 @@ fi
|
|||
: ${cross_prefix_arm="arm-linux-gnueabihf-"}
|
||||
: ${cross_prefix_armeb="$cross_prefix_arm"}
|
||||
: ${cross_prefix_hexagon="hexagon-unknown-linux-musl-"}
|
||||
: ${cross_prefix_loongarch64="loongarch64-unknown-linux-gnu-"}
|
||||
: ${cross_prefix_hppa="hppa-linux-gnu-"}
|
||||
: ${cross_prefix_i386="i686-linux-gnu-"}
|
||||
: ${cross_prefix_m68k="m68k-linux-gnu-"}
|
||||
|
@ -1871,6 +1872,8 @@ fi
|
|||
: ${cross_cc_sparc="$cross_cc_sparc64"}
|
||||
: ${cross_cc_cflags_sparc="-m32 -mcpu=supersparc"}
|
||||
: ${cross_cc_cflags_x86_64="-m64"}
|
||||
: ${cross_cc_e2k="e2k-linux-as"} # C compiler isn't public yet
|
||||
: ${cross_cc_e2k_ignore_checks="yes"}
|
||||
|
||||
compute_target_variable() {
|
||||
if eval test -n "\"\${cross_prefix_$1}\""; then
|
||||
|
|
2
disas.c
2
disas.c
|
@ -201,6 +201,8 @@ static void initialize_debug_host(CPUDebug *s)
|
|||
s->info.cap_insn_split = 6;
|
||||
#elif defined(__hppa__)
|
||||
s->info.print_insn = print_insn_hppa;
|
||||
#elif defined(__e2k__)
|
||||
s->info.print_insn = print_insn_e2k;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,556 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define COMMON_PART \
|
||||
const char *name; \
|
||||
int (* parse_args) (char **, const struct e2k_opcode_templ *); \
|
||||
const char * (* merge) (struct e2k_opcode_templ *, const struct e2k_opcode_templ *)
|
||||
|
||||
#define ALOPF1 1
|
||||
#define ALOPF2 2
|
||||
#define ALOPF3 3
|
||||
#define ALOPF7 4
|
||||
#define ALOPF8 5
|
||||
#define ALOPF10 6
|
||||
#define ALOPF11 7
|
||||
#define ALOPF11_LIT8 8
|
||||
#define ALOPF11_MERGE 9
|
||||
#define ALOPF12 10
|
||||
#define ALOPF12_PSHUFH 11
|
||||
#define ALOPF12_IBRANCHD 12
|
||||
#define ALOPF12_ICALLD 13
|
||||
#define ALOPF13 14
|
||||
#define ALOPF15 15
|
||||
#define ALOPF16 16
|
||||
#define ALOPF21 17
|
||||
#define ALOPF21_MERGE 18
|
||||
#define ALOPF22 19
|
||||
#define MERGE 20
|
||||
#define MMURR 21
|
||||
#define MMURW 22
|
||||
#define AAURR 23
|
||||
#define AAURW 24
|
||||
#define ALOPF17 25
|
||||
|
||||
#define ALF_PART \
|
||||
u_int8_t alopf; \
|
||||
int need_mas; \
|
||||
u_int8_t opc; \
|
||||
int allowed_channels[6]
|
||||
|
||||
|
||||
#define MAS 1
|
||||
#define NO_MAS 0
|
||||
|
||||
/* ALES.opc2 values. See B.1.2 in iset.single. */
|
||||
#define EXT 0x1
|
||||
#define EXT1 0x2
|
||||
#define EXT2 0x3
|
||||
#define FLB 0x4
|
||||
#define FLH 0x5
|
||||
#define FLW 0x6
|
||||
#define FLD 0x7
|
||||
#define ICMB0 0x8
|
||||
#define ICMB1 0x9
|
||||
#define ICMB2 0xA
|
||||
#define ICMB3 0xB
|
||||
|
||||
#define FCMB0 0xC
|
||||
#define FCMB1 0xD
|
||||
#define PFCMB0 0XE
|
||||
#define PFCMB1 0xF
|
||||
#define LCMBD0 0x10
|
||||
#define LCMBD1 0x11
|
||||
#define LCMBQ0 0x12
|
||||
#define LCMBQ1 0x13
|
||||
#define QPFCMB0 0x16
|
||||
#define QPFCMB1 0x17
|
||||
|
||||
|
||||
/* ALES.opce values. */
|
||||
#define NONE 0xc0
|
||||
|
||||
|
||||
/* It seems that LAS doesn't support %xr's, that's
|
||||
why everywhere where an x-args is supposed we
|
||||
use a d-one. */
|
||||
typedef enum {
|
||||
SINGLE,
|
||||
DOUBLE,
|
||||
QUAD,
|
||||
QPACKED
|
||||
} e2k_register_format;
|
||||
|
||||
|
||||
#define ARGS_S SINGLE
|
||||
#define ARGS_D DOUBLE
|
||||
#define ARGS_Q QUAD
|
||||
#define ARGS_P QPACKED
|
||||
|
||||
#define ARGS_SS {SINGLE, SINGLE}
|
||||
#define ARGS_SD {SINGLE, DOUBLE}
|
||||
#define ARGS_SQ {SINGLE, QUAD}
|
||||
#define ARGS_DS {DOUBLE, SINGLE}
|
||||
#define ARGS_DD {DOUBLE, DOUBLE}
|
||||
#define ARGS_DQ {DOUBLE, QUAD}
|
||||
#define ARGS_DP {DOUBLE, QPACKED}
|
||||
#define ARGS_QS {QUAD, SINGLE}
|
||||
#define ARGS_PS {QPACKED, SINGLE}
|
||||
#define ARGS_QD {QUAD, DOUBLE}
|
||||
#define ARGS_PD {QPACKED, DOUBLE}
|
||||
#define ARGS_QQ {QUAD, QUAD}
|
||||
#define ARGS_PP {QPACKED, QPACKED}
|
||||
|
||||
#define ARGS_SSS {SINGLE, SINGLE, SINGLE}
|
||||
#define ARGS_SSD {SINGLE, SINGLE, DOUBLE}
|
||||
#define ARGS_SSQ {SINGLE, SINGLE, QUAD}
|
||||
#define ARGS_SSP {SINGLE, SINGLE, QPACKED}
|
||||
#define ARGS_SDD {SINGLE, DOUBLE, DOUBLE}
|
||||
#define ARGS_DSS {DOUBLE, SINGLE, SINGLE}
|
||||
#define ARGS_DSD {DOUBLE, SINGLE, DOUBLE}
|
||||
#define ARGS_DDS {DOUBLE, DOUBLE, SINGLE}
|
||||
#define ARGS_DDD {DOUBLE, DOUBLE, DOUBLE}
|
||||
#define ARGS_DDQ {DOUBLE, DOUBLE, QUAD}
|
||||
#define ARGS_DDP {DOUBLE, DOUBLE, QPACKED}
|
||||
#define ARGS_DQQ {DOUBLE, QUAD, QUAD}
|
||||
#define ARGS_DPP {DOUBLE, QPACKED, QPACKED}
|
||||
#define ARGS_QSS {QUAD, SINGLE, SINGLE}
|
||||
#define ARGS_QSD {QUAD, SINGLE, DOUBLE}
|
||||
#define ARGS_QSQ {QUAD, SINGLE, QUAD}
|
||||
#define ARGS_PSP {QPACKED, SINGLE, QPACKED}
|
||||
#define ARGS_QSP {QUAD, SINGLE, QPACKED}
|
||||
#define ARGS_QDQ {QUAD, DOUBLE, QUAD}
|
||||
#define ARGS_PDP {QPACKED, DOUBLE, QPACKED}
|
||||
#define ARGS_QQD {QUAD, QUAD, DOUBLE}
|
||||
#define ARGS_PPD {QPACKED, QPACKED, DOUBLE}
|
||||
#define ARGS_QQQ {QUAD, QUAD, QUAD}
|
||||
#define ARGS_PPP {QPACKED, QPACKED, QPACKED}
|
||||
|
||||
#define ARGS_SSSS {SINGLE, SINGLE, SINGLE, SINGLE}
|
||||
#define ARGS_DDSD {DOUBLE, DOUBLE, SINGLE, DOUBLE}
|
||||
#define ARGS_DDDD {DOUBLE, DOUBLE, DOUBLE, DOUBLE}
|
||||
#define ARGS_QQQQ {QUAD, QUAD, QUAD, QUAD}
|
||||
#define ARGS_PPPP {QPACKED, QPACKED, QPACKED, QPACKED}
|
||||
|
||||
#define ALL_SINGLE {SINGLE, SINGLE, SINGLE}
|
||||
#define ALL_DOUBLE {DOUBLE, DOUBLE, DOUBLE}
|
||||
|
||||
|
||||
|
||||
typedef struct e2k_opcode_templ
|
||||
{
|
||||
COMMON_PART;
|
||||
} e2k_opcode_templ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
} e2k_alf_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALF1_PART \
|
||||
e2k_register_format arg_fmt[3]
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF1_PART;
|
||||
} e2k_alf1_opcode_templ;
|
||||
|
||||
|
||||
#define ALF2_PART \
|
||||
e2k_register_format arg_fmt[2]; \
|
||||
u_int8_t opce
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF2_PART;
|
||||
} e2k_alf2_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALF3_PART \
|
||||
e2k_register_format arg_fmt[3]
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF3_PART;
|
||||
} e2k_alf3_opcode_templ;
|
||||
|
||||
|
||||
#define ALOPF12_PART \
|
||||
e2k_register_format arg_fmt[2]; \
|
||||
u_int8_t opce; \
|
||||
u_int8_t ales_opce; \
|
||||
u_int8_t ales_opc2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF12_PART;
|
||||
} e2k_alopf12_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALOPF13_PART \
|
||||
e2k_register_format arg_fmt[3]; \
|
||||
u_int8_t ales_opce; \
|
||||
u_int8_t ales_opc2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF13_PART;
|
||||
} e2k_alopf13_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALOPF15_PART \
|
||||
e2k_register_format arg_fmt
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF15_PART;
|
||||
} e2k_alopf15_opcode_templ;
|
||||
|
||||
typedef e2k_alopf15_opcode_templ e2k_alopf16_opcode_templ;
|
||||
|
||||
#define CMPsb 0x20
|
||||
#define CMPdb 0x21
|
||||
#define CMPANDsb 0x22
|
||||
#define FXCMPxb 0x2b
|
||||
#define FCMPdb 0x2f
|
||||
|
||||
typedef enum {
|
||||
CMPOPCE_0 = 0,
|
||||
CMPOPCE_1,
|
||||
CMPOPCE_2,
|
||||
CMPOPCE_3,
|
||||
CMPOPCE_4,
|
||||
CMPOPCE_5,
|
||||
CMPOPCE_6,
|
||||
CMPOPCE_7
|
||||
} cmpopce_t;
|
||||
|
||||
#define ALF7_PART \
|
||||
e2k_register_format arg_fmt[2]; \
|
||||
cmpopce_t cmpopce; \
|
||||
int implicit_nops;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF7_PART;
|
||||
} e2k_alf7_opcode_templ;
|
||||
|
||||
#define ALF9_PART \
|
||||
e2k_register_format arg_fmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF9_PART;
|
||||
} e2k_alf9_opcode_templ;
|
||||
|
||||
|
||||
#define ALF10_PART \
|
||||
e2k_register_format arg_fmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF10_PART;
|
||||
} e2k_alf10_opcode_templ;
|
||||
|
||||
|
||||
#define ALF8_PART \
|
||||
e2k_register_format arg_fmt; \
|
||||
cmpopce_t cmpopce
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF8_PART;
|
||||
} e2k_alf8_opcode_templ;
|
||||
|
||||
#define ALOPF11_PART \
|
||||
e2k_register_format arg_fmt[3]; \
|
||||
u_int8_t ales_opce; \
|
||||
u_int8_t ales_opc2[6]; \
|
||||
int explicit_ales25_v4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF11_PART;
|
||||
} e2k_alopf11_opcode_templ;
|
||||
|
||||
|
||||
#define ALOPF11_LIT8_PART \
|
||||
u_int8_t max_lit8; \
|
||||
const char *warn
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF11_PART;
|
||||
ALOPF11_LIT8_PART;
|
||||
} e2k_alopf11_lit8_opcode_templ;
|
||||
|
||||
|
||||
#define ALOPF21_PART \
|
||||
e2k_register_format arg_fmt[4]; \
|
||||
u_int8_t ales_opc2;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF21_PART;
|
||||
} e2k_alopf21_opcode_templ;
|
||||
|
||||
|
||||
#define NO_LABEL 0
|
||||
#define EXPECT_LABEL 1
|
||||
|
||||
#define NO_CTPR {0, 0, 0}
|
||||
#define CTPR2 {0, 1, 0}
|
||||
#define CTPR3 {0, 0, 1}
|
||||
#define ALL_CTPRS {1, 1, 1}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
u_int8_t ctp_opc;
|
||||
int allowed_ctprs[3];
|
||||
int label_expected;
|
||||
} e2k_copf2_opcode_templ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
unsigned id;
|
||||
} e2k_setcmd_opcode_templ;
|
||||
|
||||
#define MOVA_PART \
|
||||
u_int16_t opc; \
|
||||
e2k_register_format arg_fmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
MOVA_PART;
|
||||
} e2k_mova_opcode_templ;
|
||||
|
||||
|
||||
|
||||
|
||||
static int parse_alf_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_copf2_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_pref_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_copf4_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_nop_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_setcmd_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_setsft_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_wait_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ct_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_hcall_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ipd_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_loop_mode_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_alc_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abn_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abg_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_bap_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_eap_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
|
||||
static int parse_pass_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_andp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_landp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ibranch_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_done_hret_glaunch_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_incr_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_mova_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_fapb_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_movep_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_flushts_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_cpl_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_set_mark_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_vfdi_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
|
||||
|
||||
extern struct e2k_opcode_templ *e2k_opcode_templs[];
|
||||
extern size_t e2k_num_opcodes;
|
||||
|
||||
|
||||
typedef enum {
|
||||
WINDOW,
|
||||
BASED,
|
||||
GLOBAL,
|
||||
SPECIAL,
|
||||
AASTI
|
||||
} e2k_register_type;
|
||||
|
||||
typedef struct {
|
||||
u_int8_t idx;
|
||||
e2k_register_type type;
|
||||
e2k_register_format fmt;
|
||||
} e2k_generic_register;
|
||||
|
||||
|
||||
typedef enum {
|
||||
LITERAL_4 = -3,
|
||||
LITERAL_5,
|
||||
/* LITERAL_8 should be used exclusively for encoding ALEF2.opce
|
||||
in PSHUF{W,H}. */
|
||||
LITERAL_8,
|
||||
LITERAL_16,
|
||||
LITERAL_32,
|
||||
LITERAL_64
|
||||
} e2k_literal_size;
|
||||
|
||||
typedef struct {
|
||||
e2k_literal_size size;
|
||||
int sgnd;
|
||||
} e2k_literal_format;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int negated;
|
||||
int pred_num;
|
||||
int pred_fld;
|
||||
} e2k_pred;
|
||||
|
||||
/* The maximal possible number of ALCes in the wide instruction. */
|
||||
#define ALS_CHANNELS_NUMBER 6
|
||||
|
||||
#define opc_field \
|
||||
struct { \
|
||||
u_int8_t cop : 7; \
|
||||
u_int8_t spec : 1; \
|
||||
} opc
|
||||
|
||||
#define GENERIC_ALS \
|
||||
/* May be 1, 2, 3, 5, 6, 7, 8, 9, 10 for appropriate ALF's. */ \
|
||||
int fmt; \
|
||||
/* Pointer to a function which will finalize this ALS after all long \
|
||||
literals in the containing wide instruction have been \
|
||||
accommodated. */ \
|
||||
int (* finish) (struct e2k_als *); \
|
||||
/* The value of ALS which should be encoded. */ \
|
||||
union { \
|
||||
struct { \
|
||||
u_int8_t dst, src2, src1; \
|
||||
opc_field; \
|
||||
} alf1; \
|
||||
struct { \
|
||||
u_int8_t dst, src2, opce; \
|
||||
opc_field; \
|
||||
} alf2; \
|
||||
struct { \
|
||||
u_int8_t src3, src2, src1; \
|
||||
opc_field; \
|
||||
} alf3; \
|
||||
struct { \
|
||||
u_int8_t regn, src2, opce; \
|
||||
opc_field; \
|
||||
} alf5; \
|
||||
struct { \
|
||||
u_int8_t dst, none, regn; \
|
||||
opc_field; \
|
||||
} alf6; \
|
||||
struct { \
|
||||
struct { \
|
||||
u_int8_t pdst : 5; \
|
||||
u_int8_t cmpopce : 3; \
|
||||
} dst2; \
|
||||
u_int8_t src2, src1; \
|
||||
opc_field; \
|
||||
} alf7; \
|
||||
struct { \
|
||||
struct { \
|
||||
u_int8_t pdst : 5; \
|
||||
u_int8_t cmpopce : 3; \
|
||||
} dst2; \
|
||||
u_int8_t src2, opce; \
|
||||
opc_field; \
|
||||
} alf8; \
|
||||
struct { \
|
||||
u_int8_t dst; \
|
||||
u_int8_t opce1_lo; \
|
||||
u_int8_t opce1_hi; \
|
||||
opc_field; \
|
||||
} alf9; \
|
||||
struct { \
|
||||
u_int8_t src3; \
|
||||
u_int8_t opce1_lo; \
|
||||
u_int8_t opce1_hi; \
|
||||
opc_field; \
|
||||
} alf10; \
|
||||
u_int32_t val; \
|
||||
} u[2]; \
|
||||
\
|
||||
/* Therse two are used for quad ops occupying two channels. */ \
|
||||
unsigned real_als_nmb; \
|
||||
/* The first element in real_alses will always be the minor \
|
||||
channel number. I want the user to be able to write \
|
||||
stapq,5 instead of stapq,2. */ \
|
||||
unsigned real_alses[6][2]; \
|
||||
\
|
||||
/* This means that ALS{j,k}.src1 should contain the same value \
|
||||
in both channels. This is required to encode LDAPQ and STAPQ \
|
||||
properly. */ \
|
||||
int same_src1_quad; \
|
||||
\
|
||||
/* The number of valid placements. It can be 6 at maximum, which \
|
||||
corresponds to ALC0, . . , ALC5. */ \
|
||||
int plcmnt_nmb; \
|
||||
int pos[ALS_CHANNELS_NUMBER]; \
|
||||
/* The most optimal index in pos[]. */ \
|
||||
int optimal_plcmnt_idx
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
u_int8_t src3;
|
||||
u_int8_t opc2;
|
||||
} alef1;
|
||||
|
||||
struct {
|
||||
u_int8_t opce;
|
||||
u_int8_t opc2;
|
||||
} alef2;
|
||||
|
||||
u_int16_t hword;
|
||||
} e2k_ales;
|
||||
|
||||
|
||||
extern void init_opcode_templs (void);
|
||||
|
||||
extern int mcpu;
|
|
@ -6,6 +6,7 @@ common_ss.add(when: 'CONFIG_ARM_A64_DIS', if_true: files('arm-a64.cc'))
|
|||
common_ss.add_all(when: 'CONFIG_ARM_A64_DIS', if_true: libvixl_ss)
|
||||
common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c'))
|
||||
common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c'))
|
||||
common_ss.add(when: 'CONFIG_E2K_DIS', if_true: files('e2k.c'))
|
||||
common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c'))
|
||||
common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c'))
|
||||
common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c'))
|
||||
|
|
|
@ -222,7 +222,7 @@ Virtio device config space
|
|||
:size: a 32-bit configuration space access size in bytes
|
||||
|
||||
:flags: a 32-bit value:
|
||||
- 0: Vhost front-end messages used for writeable fields
|
||||
- 0: Vhost front-end messages used for writable fields
|
||||
- 1: Vhost front-end messages used for live migration
|
||||
|
||||
:payload: Size bytes array holding the contents of the virtio
|
||||
|
|
|
@ -153,7 +153,7 @@ change the contents of the memory at runtime, specifically when starting a
|
|||
backed-up or snapshotted image. In order to do this, QEMU must know the
|
||||
address that has been allocated.
|
||||
|
||||
The mechanism chosen for this memory sharing is writeable fw_cfg blobs.
|
||||
The mechanism chosen for this memory sharing is writable fw_cfg blobs.
|
||||
These are data object that are visible to both QEMU and guests, and are
|
||||
addressable as sequential files.
|
||||
|
||||
|
@ -164,7 +164,7 @@ Two fw_cfg blobs are used in this case:
|
|||
/etc/vmgenid_guid - contains the actual VM Generation ID GUID
|
||||
- read-only to the guest
|
||||
/etc/vmgenid_addr - contains the address of the downloaded vmgenid blob
|
||||
- writeable by the guest
|
||||
- writable by the guest
|
||||
|
||||
|
||||
QEMU sends the following commands to the guest at startup:
|
||||
|
|
|
@ -23,6 +23,7 @@ the following architecture extensions:
|
|||
- FEAT_Debugv8p2 (Debug changes for v8.2)
|
||||
- FEAT_Debugv8p4 (Debug changes for v8.4)
|
||||
- FEAT_DotProd (Advanced SIMD dot product instructions)
|
||||
- FEAT_DoubleFault (Double Fault Extension)
|
||||
- FEAT_FCMA (Floating-point complex number instructions)
|
||||
- FEAT_FHM (Floating-point half-precision multiplication instructions)
|
||||
- FEAT_FP16 (Half-precision floating-point data processing)
|
||||
|
@ -52,6 +53,7 @@ the following architecture extensions:
|
|||
- FEAT_PMUv3p1 (PMU Extensions v3.1)
|
||||
- FEAT_PMUv3p4 (PMU Extensions v3.4)
|
||||
- FEAT_RAS (Reliability, availability, and serviceability)
|
||||
- FEAT_RASv1p1 (RAS Extension v1.1)
|
||||
- FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions)
|
||||
- FEAT_RNG (Random number generator)
|
||||
- FEAT_S2FWB (Stage 2 forced Write-Back)
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
:orphan:
|
||||
|
||||
==========================================
|
||||
loongson3 virt generic platform (``virt``)
|
||||
==========================================
|
||||
|
||||
The ``virt`` machine use gpex host bridge, and there are some
|
||||
emulated devices on virt board, such as loongson7a RTC device,
|
||||
IOAPIC device, ACPI device and so on.
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
|
||||
The ``virt`` machine supports:
|
||||
- Gpex host bridge
|
||||
- Ls7a RTC device
|
||||
- Ls7a IOAPIC device
|
||||
- Ls7a ACPI device
|
||||
- Fw_cfg device
|
||||
- PCI/PCIe devices
|
||||
- Memory device
|
||||
- CPU device. Type: Loongson-3A5000.
|
||||
|
||||
CPU and machine Type
|
||||
--------------------
|
||||
|
||||
The ``qemu-system-loongarch64`` provides emulation for virt
|
||||
machine. You can specify the machine type ``virt`` and
|
||||
cpu type ``Loongson-3A5000``.
|
||||
|
||||
Boot options
|
||||
------------
|
||||
|
||||
Now the ``virt`` machine can run test program in ELF format and the
|
||||
method of compiling is in target/loongarch/README.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-loongarch64 -machine virt -m 4G -cpu Loongson-3A5000 \
|
||||
-smp 1 -kernel hello -monitor none -display none \
|
||||
-chardev file,path=hello.out,id=output -serial chardev:output
|
|
@ -138,7 +138,7 @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
|
|||
/* !snan_bit_is_one, set all bits */
|
||||
frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
|
||||
#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
|
||||
|| defined(TARGET_MICROBLAZE)
|
||||
|| defined(TARGET_MICROBLAZE) || defined(TARGET_E2K)
|
||||
/* !snan_bit_is_one, set sign and msb */
|
||||
frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
|
||||
sign = 1;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
<feature name="org.mcst.gdb.elbrus-v2.linux">
|
||||
|
||||
<!-- 840 -->
|
||||
<reg name="idr" bitsize="64" type="uint64"/>
|
||||
|
||||
</feature>
|
|
@ -0,0 +1,6 @@
|
|||
<feature name="org.mcst.gdb.elbrus-v3.linux">
|
||||
|
||||
<!-- 841 -->
|
||||
<reg name="core_mode" bitsize="64" type="uint64"/>
|
||||
|
||||
</feature>
|
|
@ -0,0 +1,86 @@
|
|||
<feature name="org.mcst.gdb.elbrus-v5.linux">
|
||||
|
||||
<!-- This type seems to be common for %lsr1 and %ilcr1 -->
|
||||
<!-- lsr1 -->
|
||||
<struct id="lsr1_bits" size="8">
|
||||
<field name="lcnt_lo" start="0" end="31"/>
|
||||
<field name="lcnt_hi" start="32" end="63"/>
|
||||
</struct>
|
||||
|
||||
<union id="lsr1">
|
||||
<field name="dword" type="uint64"/>
|
||||
<field name="" type="lsr1_bits"/>
|
||||
</union>
|
||||
|
||||
|
||||
<reg name="lsr1" bitsize="64" type="lsr1"/>
|
||||
<reg name="ilcr1" bitsize="64" type="lsr1"/>
|
||||
|
||||
<reg name="_gext_v5_0" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_1" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_2" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_3" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_4" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_5" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_6" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_7" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_8" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_9" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_10" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_11" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_12" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_13" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_14" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_15" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_16" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_17" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_18" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_19" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_20" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_21" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_22" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_23" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_24" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_25" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_26" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_27" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_28" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_29" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_30" bitsize="16" type="uint64"/>
|
||||
<reg name="_gext_v5_31" bitsize="16" type="uint64"/>
|
||||
|
||||
<reg name="_gtag_v5_0" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_1" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_2" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_3" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_4" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_5" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_6" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_7" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_8" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_9" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_10" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_11" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_12" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_13" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_14" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_15" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_16" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_17" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_18" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_19" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_20" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_21" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_22" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_23" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_24" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_25" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_26" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_27" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_28" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_29" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_30" bitsize="8" type="uint8"/>
|
||||
<reg name="_gtag_v5_31" bitsize="8" type="uint8"/>
|
||||
|
||||
|
||||
</feature>
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.loongarch.base">
|
||||
<reg name="r0" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r1" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r2" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r3" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r4" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r5" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r6" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r7" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r8" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r9" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r10" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r11" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r12" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r13" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r14" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r15" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r16" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r17" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r18" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r19" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r20" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r21" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r22" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r23" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r24" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r25" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r26" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r27" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r28" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r29" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r30" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="r31" bitsize="64" type="uint64" group="general"/>
|
||||
<reg name="pc" bitsize="64" type="code_ptr" group="general"/>
|
||||
<reg name="badvaddr" bitsize="64" type="code_ptr" group="general"/>
|
||||
</feature>
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.loongarch.fpu">
|
||||
|
||||
<union id="fpu64type">
|
||||
<field name="f" type="ieee_single"/>
|
||||
<field name="d" type="ieee_double"/>
|
||||
</union>
|
||||
|
||||
<reg name="f0" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f1" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f2" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f3" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f4" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f5" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f6" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f7" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f8" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f9" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f10" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f11" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f12" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f13" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f14" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f15" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f16" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f17" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f18" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f19" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f20" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f21" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f22" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f23" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f24" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f25" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f26" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f27" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f28" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f29" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f30" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="f31" bitsize="64" type="fpu64type" group="float"/>
|
||||
<reg name="fcc0" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcc1" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcc2" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcc3" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcc4" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcc5" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcc6" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcc7" bitsize="8" type="uint8" group="float"/>
|
||||
<reg name="fcsr" bitsize="32" type="uint32" group="float"/>
|
||||
</feature>
|
40
gdbstub.c
40
gdbstub.c
|
@ -2211,6 +2211,12 @@ static void handle_query_supported(GArray *params, void *user_ctx)
|
|||
gdbserver_state.multiprocess = true;
|
||||
}
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
// TODO: qXfer:tags:write+
|
||||
// TODO: qXfer:packed_tags:read+
|
||||
g_string_append(gdbserver_state.str_buf, ";qXfer:tags:read+");
|
||||
#endif
|
||||
|
||||
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
|
||||
put_strbuf();
|
||||
}
|
||||
|
@ -2357,6 +2363,32 @@ static void handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
static void handle_query_e2k_tags_read(GArray *params, void *user_ctx)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(gdbserver_state.g_cpu);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
target_ulong addr = get_param(params, 0)->val_ull;
|
||||
unsigned long len = get_param(params, 1)->val_ul;
|
||||
unsigned int i;
|
||||
int tags = 0;
|
||||
|
||||
g_string_assign(gdbserver_state.str_buf, "l");
|
||||
if (env->psp.base <= addr && addr < (env->psp.base + env->psp.size)) {
|
||||
target_ulong offset = addr - env->psp.base;
|
||||
tags = cpu_ldub_data(env, env->psp.base_tag + offset / 8);
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int tag = (tags >> (i * 2)) & 0x3;
|
||||
g_string_append_c(gdbserver_state.str_buf, tag);
|
||||
}
|
||||
|
||||
put_packet_binary(gdbserver_state.str_buf->str,
|
||||
gdbserver_state.str_buf->len, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
|
||||
/* Order is important if has same prefix */
|
||||
{
|
||||
|
@ -2451,6 +2483,14 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
|
|||
.cmd = "qemu.PhyMemMode",
|
||||
},
|
||||
#endif
|
||||
#ifdef TARGET_E2K
|
||||
{
|
||||
.handler = handle_query_e2k_tags_read,
|
||||
.cmd = "Xfer:tags:read::",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "L,l0",
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static const GdbCmdParseEntry gdb_gen_set_table[] = {
|
||||
|
|
|
@ -50,6 +50,7 @@ source avr/Kconfig
|
|||
source cris/Kconfig
|
||||
source hppa/Kconfig
|
||||
source i386/Kconfig
|
||||
source loongarch/Kconfig
|
||||
source m68k/Kconfig
|
||||
source microblaze/Kconfig
|
||||
source mips/Kconfig
|
||||
|
|
|
@ -249,7 +249,7 @@ void build_ghes_error_table(GArray *hardware_errors, BIOSLinker *linker)
|
|||
for (i = 0; i < ACPI_GHES_ERROR_SOURCE_COUNT; i++) {
|
||||
/*
|
||||
* Initialize the value of read_ack_register to 1, so GHES can be
|
||||
* writeable after (re)boot.
|
||||
* writable after (re)boot.
|
||||
* ACPI 6.2: 18.3.2.8 Generic Hardware Error Source version 2
|
||||
* (GHESv2 - Type 10)
|
||||
*/
|
||||
|
|
|
@ -60,10 +60,10 @@
|
|||
#define SERDES_SIZE 0x20000
|
||||
|
||||
#define DP_ADDR 0xfd4a0000
|
||||
#define DP_IRQ 113
|
||||
#define DP_IRQ 0x77
|
||||
|
||||
#define DPDMA_ADDR 0xfd4c0000
|
||||
#define DPDMA_IRQ 116
|
||||
#define DPDMA_IRQ 0x7a
|
||||
|
||||
#define APU_ADDR 0xfd5c0000
|
||||
#define APU_IRQ 153
|
||||
|
|
|
@ -114,6 +114,7 @@
|
|||
#define DP_TX_N_AUD (0x032C >> 2)
|
||||
#define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2)
|
||||
#define DP_INT_STATUS (0x03A0 >> 2)
|
||||
#define DP_INT_VBLNK_START (1 << 13)
|
||||
#define DP_INT_MASK (0x03A4 >> 2)
|
||||
#define DP_INT_EN (0x03A8 >> 2)
|
||||
#define DP_INT_DS (0x03AC >> 2)
|
||||
|
@ -260,7 +261,7 @@ typedef enum DPVideoFmt DPVideoFmt;
|
|||
|
||||
static const VMStateDescription vmstate_dp = {
|
||||
.name = TYPE_XLNX_DP,
|
||||
.version_id = 1,
|
||||
.version_id = 2,
|
||||
.fields = (VMStateField[]){
|
||||
VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState,
|
||||
DP_CORE_REG_ARRAY_SIZE),
|
||||
|
@ -270,10 +271,15 @@ static const VMStateDescription vmstate_dp = {
|
|||
DP_VBLEND_REG_ARRAY_SIZE),
|
||||
VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState,
|
||||
DP_AUDIO_REG_ARRAY_SIZE),
|
||||
VMSTATE_PTIMER(vblank, XlnxDPState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define DP_VBLANK_PTIMER_POLICY (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \
|
||||
PTIMER_POLICY_CONTINUOUS_TRIGGER | \
|
||||
PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)
|
||||
|
||||
static void xlnx_dp_update_irq(XlnxDPState *s);
|
||||
|
||||
static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size)
|
||||
|
@ -773,6 +779,13 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value,
|
|||
break;
|
||||
case DP_TRANSMITTER_ENABLE:
|
||||
s->core_registers[offset] = value & 0x01;
|
||||
ptimer_transaction_begin(s->vblank);
|
||||
if (value & 0x1) {
|
||||
ptimer_run(s->vblank, 0);
|
||||
} else {
|
||||
ptimer_stop(s->vblank);
|
||||
}
|
||||
ptimer_transaction_commit(s->vblank);
|
||||
break;
|
||||
case DP_FORCE_SCRAMBLER_RESET:
|
||||
/*
|
||||
|
@ -876,7 +889,7 @@ static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value,
|
|||
xlnx_dp_update_irq(s);
|
||||
break;
|
||||
case DP_INT_DS:
|
||||
s->core_registers[DP_INT_MASK] |= ~value;
|
||||
s->core_registers[DP_INT_MASK] |= value;
|
||||
xlnx_dp_update_irq(s);
|
||||
break;
|
||||
default:
|
||||
|
@ -1177,9 +1190,6 @@ static void xlnx_dp_update_display(void *opaque)
|
|||
return;
|
||||
}
|
||||
|
||||
s->core_registers[DP_INT_STATUS] |= (1 << 13);
|
||||
xlnx_dp_update_irq(s);
|
||||
|
||||
xlnx_dpdma_trigger_vsync_irq(s->dpdma);
|
||||
|
||||
/*
|
||||
|
@ -1219,19 +1229,22 @@ static void xlnx_dp_init(Object *obj)
|
|||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
XlnxDPState *s = XLNX_DP(obj);
|
||||
|
||||
memory_region_init(&s->container, obj, TYPE_XLNX_DP, 0xC050);
|
||||
memory_region_init(&s->container, obj, TYPE_XLNX_DP, DP_CONTAINER_SIZE);
|
||||
|
||||
memory_region_init_io(&s->core_iomem, obj, &dp_ops, s, TYPE_XLNX_DP
|
||||
".core", 0x3AF);
|
||||
memory_region_add_subregion(&s->container, 0x0000, &s->core_iomem);
|
||||
".core", sizeof(s->core_registers));
|
||||
memory_region_add_subregion(&s->container, DP_CORE_REG_OFFSET,
|
||||
&s->core_iomem);
|
||||
|
||||
memory_region_init_io(&s->vblend_iomem, obj, &vblend_ops, s, TYPE_XLNX_DP
|
||||
".v_blend", 0x1DF);
|
||||
memory_region_add_subregion(&s->container, 0xA000, &s->vblend_iomem);
|
||||
".v_blend", sizeof(s->vblend_registers));
|
||||
memory_region_add_subregion(&s->container, DP_VBLEND_REG_OFFSET,
|
||||
&s->vblend_iomem);
|
||||
|
||||
memory_region_init_io(&s->avbufm_iomem, obj, &avbufm_ops, s, TYPE_XLNX_DP
|
||||
".av_buffer_manager", 0x238);
|
||||
memory_region_add_subregion(&s->container, 0xB000, &s->avbufm_iomem);
|
||||
".av_buffer_manager", sizeof(s->avbufm_registers));
|
||||
memory_region_add_subregion(&s->container, DP_AVBUF_REG_OFFSET,
|
||||
&s->avbufm_iomem);
|
||||
|
||||
memory_region_init_io(&s->audio_iomem, obj, &audio_ops, s, TYPE_XLNX_DP
|
||||
".audio", sizeof(s->audio_registers));
|
||||
|
@ -1272,6 +1285,14 @@ static void xlnx_dp_finalize(Object *obj)
|
|||
fifo8_destroy(&s->rx_fifo);
|
||||
}
|
||||
|
||||
static void vblank_hit(void *opaque)
|
||||
{
|
||||
XlnxDPState *s = XLNX_DP(opaque);
|
||||
|
||||
s->core_registers[DP_INT_STATUS] |= DP_INT_VBLNK_START;
|
||||
xlnx_dp_update_irq(s);
|
||||
}
|
||||
|
||||
static void xlnx_dp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
XlnxDPState *s = XLNX_DP(dev);
|
||||
|
@ -1306,6 +1327,10 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp)
|
|||
&as);
|
||||
AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255);
|
||||
xlnx_dp_audio_activate(s);
|
||||
s->vblank = ptimer_init(vblank_hit, s, DP_VBLANK_PTIMER_POLICY);
|
||||
ptimer_transaction_begin(s->vblank);
|
||||
ptimer_set_freq(s->vblank, 30);
|
||||
ptimer_transaction_commit(s->vblank);
|
||||
}
|
||||
|
||||
static void xlnx_dp_reset(DeviceState *dev)
|
||||
|
|
|
@ -246,8 +246,7 @@ static void pc_init1(MachineState *machine,
|
|||
if (pcmc->pci_enabled) {
|
||||
PCIDevice *dev;
|
||||
|
||||
dev = pci_create_simple(pci_bus, piix3_devfn + 1,
|
||||
xen_enabled() ? "piix3-ide-xen" : "piix3-ide");
|
||||
dev = pci_create_simple(pci_bus, piix3_devfn + 1, "piix3-ide");
|
||||
pci_ide_create_devs(dev);
|
||||
idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
|
||||
idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/ide.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/xen/xen_common.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
@ -134,6 +135,51 @@ static void pci_unplug_nics(PCIBus *bus)
|
|||
pci_for_each_device(bus, 0, unplug_nic, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Xen HVM unplug protocol [1] specifies a mechanism to allow guests to
|
||||
* request unplug of 'aux' disks (which is stated to mean all IDE disks,
|
||||
* except the primary master).
|
||||
*
|
||||
* NOTE: The semantics of what happens if unplug of all disks and 'aux' disks
|
||||
* is simultaneously requested is not clear. The implementation assumes
|
||||
* that an 'all' request overrides an 'aux' request.
|
||||
*
|
||||
* [1] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/misc/hvm-emulated-unplug.pandoc
|
||||
*/
|
||||
static void pci_xen_ide_unplug(DeviceState *dev, bool aux)
|
||||
{
|
||||
PCIIDEState *pci_ide;
|
||||
int i;
|
||||
IDEDevice *idedev;
|
||||
IDEBus *idebus;
|
||||
BlockBackend *blk;
|
||||
|
||||
pci_ide = PCI_IDE(dev);
|
||||
|
||||
for (i = aux ? 1 : 0; i < 4; i++) {
|
||||
idebus = &pci_ide->bus[i / 2];
|
||||
blk = idebus->ifs[i % 2].blk;
|
||||
|
||||
if (blk && idebus->ifs[i % 2].drive_kind != IDE_CD) {
|
||||
if (!(i % 2)) {
|
||||
idedev = idebus->master;
|
||||
} else {
|
||||
idedev = idebus->slave;
|
||||
}
|
||||
|
||||
blk_drain(blk);
|
||||
blk_flush(blk);
|
||||
|
||||
blk_detach_dev(blk, DEVICE(idedev));
|
||||
idebus->ifs[i % 2].blk = NULL;
|
||||
idedev->conf.blk = NULL;
|
||||
monitor_remove_blk(blk);
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
qdev_reset_all(dev);
|
||||
}
|
||||
|
||||
static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
|
||||
{
|
||||
uint32_t flags = *(uint32_t *)opaque;
|
||||
|
@ -147,7 +193,7 @@ static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
|
|||
|
||||
switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
|
||||
case PCI_CLASS_STORAGE_IDE:
|
||||
pci_piix3_xen_ide_unplug(DEVICE(d), aux);
|
||||
pci_xen_ide_unplug(DEVICE(d), aux);
|
||||
break;
|
||||
|
||||
case PCI_CLASS_STORAGE_SCSI:
|
||||
|
|
|
@ -173,41 +173,6 @@ static void pci_piix_ide_realize(PCIDevice *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux)
|
||||
{
|
||||
PCIIDEState *pci_ide;
|
||||
int i;
|
||||
IDEDevice *idedev;
|
||||
IDEBus *idebus;
|
||||
BlockBackend *blk;
|
||||
|
||||
pci_ide = PCI_IDE(dev);
|
||||
|
||||
for (i = aux ? 1 : 0; i < 4; i++) {
|
||||
idebus = &pci_ide->bus[i / 2];
|
||||
blk = idebus->ifs[i % 2].blk;
|
||||
|
||||
if (blk && idebus->ifs[i % 2].drive_kind != IDE_CD) {
|
||||
if (!(i % 2)) {
|
||||
idedev = idebus->master;
|
||||
} else {
|
||||
idedev = idebus->slave;
|
||||
}
|
||||
|
||||
blk_drain(blk);
|
||||
blk_flush(blk);
|
||||
|
||||
blk_detach_dev(blk, DEVICE(idedev));
|
||||
idebus->ifs[i % 2].blk = NULL;
|
||||
idedev->conf.blk = NULL;
|
||||
monitor_remove_blk(blk);
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
qdev_reset_all(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_piix_ide_exitfn(PCIDevice *dev)
|
||||
{
|
||||
PCIIDEState *d = PCI_IDE(dev);
|
||||
|
@ -241,12 +206,6 @@ static const TypeInfo piix3_ide_info = {
|
|||
.class_init = piix3_ide_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo piix3_ide_xen_info = {
|
||||
.name = "piix3-ide-xen",
|
||||
.parent = TYPE_PCI_IDE,
|
||||
.class_init = piix3_ide_class_init,
|
||||
};
|
||||
|
||||
/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
|
||||
static void piix4_ide_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
|
@ -272,7 +231,6 @@ static const TypeInfo piix4_ide_info = {
|
|||
static void piix_ide_register_types(void)
|
||||
{
|
||||
type_register_static(&piix3_ide_info);
|
||||
type_register_static(&piix3_ide_xen_info);
|
||||
type_register_static(&piix4_ide_info);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,3 +87,18 @@ config M68K_IRQC
|
|||
|
||||
config NIOS2_VIC
|
||||
bool
|
||||
|
||||
config LOONGARCH_IPI
|
||||
bool
|
||||
|
||||
config LOONGARCH_PCH_PIC
|
||||
bool
|
||||
select UNIMP
|
||||
|
||||
config LOONGARCH_PCH_MSI
|
||||
select MSI_NONBROKEN
|
||||
bool
|
||||
select UNIMP
|
||||
|
||||
config LOONGARCH_EXTIOI
|
||||
bool
|
||||
|
|
|
@ -2047,7 +2047,7 @@ static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR;
|
||||
}
|
||||
|
||||
/* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */
|
||||
/* The only bit stored in icc_ctlr_el3 which is writable is EOIMODE_EL3: */
|
||||
mask = ICC_CTLR_EL3_EOIMODE_EL3;
|
||||
|
||||
cs->icc_ctlr_el3 &= ~mask;
|
||||
|
|
|
@ -611,7 +611,7 @@ static bool gicd_writel(GICv3State *s, hwaddr offset,
|
|||
if (value & mask & GICD_CTLR_DS) {
|
||||
/* We just set DS, so the ARE_NS and EnG1S bits are now RES0.
|
||||
* Note that this is a one-way transition because if DS is set
|
||||
* then it's not writeable, so it can only go back to 0 with a
|
||||
* then it's not writable, so it can only go back to 0 with a
|
||||
* hardware reset.
|
||||
*/
|
||||
s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS);
|
||||
|
|
|
@ -257,7 +257,7 @@ static void gicr_write_vpendbaser(GICv3CPUState *cs, uint64_t newval)
|
|||
|
||||
/*
|
||||
* The DIRTY bit is read-only and for us is always zero;
|
||||
* other fields are writeable.
|
||||
* other fields are writable.
|
||||
*/
|
||||
newval &= R_GICR_VPENDBASER_INNERCACHE_MASK |
|
||||
R_GICR_VPENDBASER_SHAREABILITY_MASK |
|
||||
|
@ -491,7 +491,7 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
|
|||
/* RAZ/WI for our implementation */
|
||||
return MEMTX_OK;
|
||||
case GICR_WAKER:
|
||||
/* Only the ProcessorSleep bit is writeable. When the guest sets
|
||||
/* Only the ProcessorSleep bit is writable. When the guest sets
|
||||
* it it requests that we transition the channel between the
|
||||
* redistributor and the cpu interface to quiescent, and that
|
||||
* we set the ChildrenAsleep bit once the inteface has reached the
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Loongson 3A5000 ext interrupt controller emulation
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/intc/loongarch_extioi.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level)
|
||||
{
|
||||
int ipnum, cpu, found, irq_index, irq_mask;
|
||||
|
||||
ipnum = s->sw_ipmap[irq / 32];
|
||||
cpu = s->sw_coremap[irq];
|
||||
irq_index = irq / 32;
|
||||
irq_mask = 1 << (irq & 0x1f);
|
||||
|
||||
if (level) {
|
||||
/* if not enable return false */
|
||||
if (((s->enable[irq_index]) & irq_mask) == 0) {
|
||||
return;
|
||||
}
|
||||
s->coreisr[cpu][irq_index] |= irq_mask;
|
||||
found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
|
||||
set_bit(irq, s->sw_isr[cpu][ipnum]);
|
||||
if (found < EXTIOI_IRQS) {
|
||||
/* other irq is handling, need not update parent irq level */
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
s->coreisr[cpu][irq_index] &= ~irq_mask;
|
||||
clear_bit(irq, s->sw_isr[cpu][ipnum]);
|
||||
found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
|
||||
if (found < EXTIOI_IRQS) {
|
||||
/* other irq is handling, need not update parent irq level */
|
||||
return;
|
||||
}
|
||||
}
|
||||
qemu_set_irq(s->parent_irq[cpu][ipnum], level);
|
||||
}
|
||||
|
||||
static void extioi_setirq(void *opaque, int irq, int level)
|
||||
{
|
||||
LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
|
||||
trace_loongarch_extioi_setirq(irq, level);
|
||||
if (level) {
|
||||
/*
|
||||
* s->isr should be used in vmstate structure,
|
||||
* but it not support 'unsigned long',
|
||||
* so we have to switch it.
|
||||
*/
|
||||
set_bit(irq, (unsigned long *)s->isr);
|
||||
} else {
|
||||
clear_bit(irq, (unsigned long *)s->isr);
|
||||
}
|
||||
extioi_update_irq(s, irq, level);
|
||||
}
|
||||
|
||||
static uint64_t extioi_readw(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
|
||||
unsigned long offset = addr & 0xffff;
|
||||
uint32_t index, cpu, ret = 0;
|
||||
|
||||
switch (offset) {
|
||||
case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
|
||||
index = (offset - EXTIOI_NODETYPE_START) >> 2;
|
||||
ret = s->nodetype[index];
|
||||
break;
|
||||
case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
|
||||
index = (offset - EXTIOI_IPMAP_START) >> 2;
|
||||
ret = s->ipmap[index];
|
||||
break;
|
||||
case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
|
||||
index = (offset - EXTIOI_ENABLE_START) >> 2;
|
||||
ret = s->enable[index];
|
||||
break;
|
||||
case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
|
||||
index = (offset - EXTIOI_BOUNCE_START) >> 2;
|
||||
ret = s->bounce[index];
|
||||
break;
|
||||
case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
|
||||
index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
|
||||
cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
|
||||
ret = s->coreisr[cpu][index];
|
||||
break;
|
||||
case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
|
||||
index = (offset - EXTIOI_COREMAP_START) >> 2;
|
||||
ret = s->coremap[index];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_extioi_readw(addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
|
||||
uint32_t mask, int level)
|
||||
{
|
||||
uint32_t val;
|
||||
int irq;
|
||||
|
||||
val = mask & s->isr[index];
|
||||
irq = ctz32(val);
|
||||
while (irq != 32) {
|
||||
/*
|
||||
* enable bit change from 0 to 1,
|
||||
* need to update irq by pending bits
|
||||
*/
|
||||
extioi_update_irq(s, irq + index * 32, level);
|
||||
val &= ~(1 << irq);
|
||||
irq = ctz32(val);
|
||||
}
|
||||
}
|
||||
|
||||
static void extioi_writew(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
|
||||
int i, cpu, index, old_data, irq;
|
||||
uint32_t offset;
|
||||
|
||||
trace_loongarch_extioi_writew(addr, val);
|
||||
offset = addr & 0xffff;
|
||||
|
||||
switch (offset) {
|
||||
case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
|
||||
index = (offset - EXTIOI_NODETYPE_START) >> 2;
|
||||
s->nodetype[index] = val;
|
||||
break;
|
||||
case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
|
||||
/*
|
||||
* ipmap cannot be set at runtime, can be set only at the beginning
|
||||
* of intr driver, need not update upper irq level
|
||||
*/
|
||||
index = (offset - EXTIOI_IPMAP_START) >> 2;
|
||||
s->ipmap[index] = val;
|
||||
/*
|
||||
* loongarch only support little endian,
|
||||
* so we paresd the value with little endian.
|
||||
*/
|
||||
val = cpu_to_le64(val);
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint8_t ipnum;
|
||||
ipnum = val & 0xff;
|
||||
ipnum = ctz32(ipnum);
|
||||
ipnum = (ipnum >= 4) ? 0 : ipnum;
|
||||
s->sw_ipmap[index * 4 + i] = ipnum;
|
||||
val = val >> 8;
|
||||
}
|
||||
|
||||
break;
|
||||
case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
|
||||
index = (offset - EXTIOI_ENABLE_START) >> 2;
|
||||
old_data = s->enable[index];
|
||||
s->enable[index] = val;
|
||||
|
||||
/* unmask irq */
|
||||
val = s->enable[index] & ~old_data;
|
||||
extioi_enable_irq(s, index, val, 1);
|
||||
|
||||
/* mask irq */
|
||||
val = ~s->enable[index] & old_data;
|
||||
extioi_enable_irq(s, index, val, 0);
|
||||
break;
|
||||
case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
|
||||
/* do not emulate hw bounced irq routing */
|
||||
index = (offset - EXTIOI_BOUNCE_START) >> 2;
|
||||
s->bounce[index] = val;
|
||||
break;
|
||||
case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
|
||||
index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
|
||||
cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
|
||||
old_data = s->coreisr[cpu][index];
|
||||
s->coreisr[cpu][index] = old_data & ~val;
|
||||
/* write 1 to clear interrrupt */
|
||||
old_data &= val;
|
||||
irq = ctz32(old_data);
|
||||
while (irq != 32) {
|
||||
extioi_update_irq(s, irq + index * 32, 0);
|
||||
old_data &= ~(1 << irq);
|
||||
irq = ctz32(old_data);
|
||||
}
|
||||
break;
|
||||
case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
|
||||
irq = offset - EXTIOI_COREMAP_START;
|
||||
index = irq / 4;
|
||||
s->coremap[index] = val;
|
||||
/*
|
||||
* loongarch only support little endian,
|
||||
* so we paresd the value with little endian.
|
||||
*/
|
||||
val = cpu_to_le64(val);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
cpu = val & 0xff;
|
||||
cpu = ctz32(cpu);
|
||||
cpu = (cpu >= 4) ? 0 : cpu;
|
||||
val = val >> 8;
|
||||
|
||||
if (s->sw_coremap[irq + i] == cpu) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (test_bit(irq, (unsigned long *)s->isr)) {
|
||||
/*
|
||||
* lower irq at old cpu and raise irq at new cpu
|
||||
*/
|
||||
extioi_update_irq(s, irq + i, 0);
|
||||
s->sw_coremap[irq + i] = cpu;
|
||||
extioi_update_irq(s, irq + i, 1);
|
||||
} else {
|
||||
s->sw_coremap[irq + i] = cpu;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps extioi_ops = {
|
||||
.read = extioi_readw,
|
||||
.write = extioi_writew,
|
||||
.impl.min_access_size = 4,
|
||||
.impl.max_access_size = 4,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 8,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_loongarch_extioi = {
|
||||
.name = TYPE_LOONGARCH_EXTIOI,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
|
||||
VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, LOONGARCH_MAX_VCPUS,
|
||||
EXTIOI_IRQS_GROUP_COUNT),
|
||||
VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
|
||||
EXTIOI_IRQS_NODETYPE_COUNT / 2),
|
||||
VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32),
|
||||
VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32),
|
||||
VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4),
|
||||
VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4),
|
||||
VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE),
|
||||
VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void loongarch_extioi_instance_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
|
||||
int i, cpu, pin;
|
||||
|
||||
for (i = 0; i < EXTIOI_IRQS; i++) {
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
|
||||
}
|
||||
|
||||
qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
|
||||
|
||||
for (cpu = 0; cpu < LOONGARCH_MAX_VCPUS; cpu++) {
|
||||
memory_region_init_io(&s->extioi_iocsr_mem[cpu], OBJECT(s), &extioi_ops,
|
||||
s, "extioi_iocsr", 0x900);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_iocsr_mem[cpu]);
|
||||
for (pin = 0; pin < LS3A_INTC_IP; pin++) {
|
||||
qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1);
|
||||
}
|
||||
}
|
||||
memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
|
||||
s, "extioi_system_mem", 0x900);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->extioi_system_mem);
|
||||
}
|
||||
|
||||
static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_loongarch_extioi;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_extioi_info = {
|
||||
.name = TYPE_LOONGARCH_EXTIOI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_init = loongarch_extioi_instance_init,
|
||||
.instance_size = sizeof(struct LoongArchExtIOI),
|
||||
.class_init = loongarch_extioi_class_init,
|
||||
};
|
||||
|
||||
static void loongarch_extioi_register_types(void)
|
||||
{
|
||||
type_register_static(&loongarch_extioi_info);
|
||||
}
|
||||
|
||||
type_init(loongarch_extioi_register_types)
|
|
@ -0,0 +1,242 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch ipi interrupt support
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/intc/loongarch_ipi.h"
|
||||
#include "hw/irq.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "target/loongarch/internals.h"
|
||||
#include "trace.h"
|
||||
|
||||
static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
IPICore *s = opaque;
|
||||
uint64_t ret = 0;
|
||||
int index = 0;
|
||||
|
||||
addr &= 0xff;
|
||||
switch (addr) {
|
||||
case CORE_STATUS_OFF:
|
||||
ret = s->status;
|
||||
break;
|
||||
case CORE_EN_OFF:
|
||||
ret = s->en;
|
||||
break;
|
||||
case CORE_SET_OFF:
|
||||
ret = 0;
|
||||
break;
|
||||
case CORE_CLEAR_OFF:
|
||||
ret = 0;
|
||||
break;
|
||||
case CORE_BUF_20 ... CORE_BUF_38 + 4:
|
||||
index = (addr - CORE_BUF_20) >> 2;
|
||||
ret = s->buf[index];
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_ipi_data(target_ulong val)
|
||||
{
|
||||
int i, mask, data;
|
||||
|
||||
data = val >> 32;
|
||||
mask = (val >> 27) & 0xf;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((mask >> i) & 1) {
|
||||
data &= ~(0xff << (i * 8));
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void ipi_send(uint64_t val)
|
||||
{
|
||||
int cpuid, data;
|
||||
CPULoongArchState *env;
|
||||
|
||||
cpuid = (val >> 16) & 0x3ff;
|
||||
/* IPI status vector */
|
||||
data = 1 << (val & 0x1f);
|
||||
qemu_mutex_lock_iothread();
|
||||
CPUState *cs = qemu_get_cpu(cpuid);
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
|
||||
env = &cpu->env;
|
||||
loongarch_cpu_set_irq(cpu, IRQ_IPI, 1);
|
||||
qemu_mutex_unlock_iothread();
|
||||
address_space_stl(&env->address_space_iocsr, 0x1008,
|
||||
data, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void mail_send(uint64_t val)
|
||||
{
|
||||
int cpuid, data;
|
||||
hwaddr addr;
|
||||
CPULoongArchState *env;
|
||||
|
||||
cpuid = (val >> 16) & 0x3ff;
|
||||
addr = 0x1020 + (val & 0x1c);
|
||||
CPUState *cs = qemu_get_cpu(cpuid);
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
|
||||
env = &cpu->env;
|
||||
data = get_ipi_data(val);
|
||||
address_space_stl(&env->address_space_iocsr, addr,
|
||||
data, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
static void any_send(uint64_t val)
|
||||
{
|
||||
int cpuid, data;
|
||||
hwaddr addr;
|
||||
CPULoongArchState *env;
|
||||
|
||||
cpuid = (val >> 16) & 0x3ff;
|
||||
addr = val & 0xffff;
|
||||
CPUState *cs = qemu_get_cpu(cpuid);
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
|
||||
env = &cpu->env;
|
||||
data = get_ipi_data(val);
|
||||
address_space_stl(&env->address_space_iocsr, addr,
|
||||
data, MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
}
|
||||
|
||||
static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
IPICore *s = opaque;
|
||||
int index = 0;
|
||||
|
||||
addr &= 0xff;
|
||||
trace_loongarch_ipi_write(size, (uint64_t)addr, val);
|
||||
switch (addr) {
|
||||
case CORE_STATUS_OFF:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
|
||||
break;
|
||||
case CORE_EN_OFF:
|
||||
s->en = val;
|
||||
break;
|
||||
case CORE_SET_OFF:
|
||||
s->status |= val;
|
||||
if (s->status != 0 && (s->status & s->en) != 0) {
|
||||
qemu_irq_raise(s->irq);
|
||||
}
|
||||
break;
|
||||
case CORE_CLEAR_OFF:
|
||||
s->status &= ~val;
|
||||
if (s->status == 0 && s->en != 0) {
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
break;
|
||||
case CORE_BUF_20 ... CORE_BUF_38 + 4:
|
||||
index = (addr - CORE_BUF_20) >> 2;
|
||||
s->buf[index] = val;
|
||||
break;
|
||||
case IOCSR_IPI_SEND:
|
||||
ipi_send(val);
|
||||
break;
|
||||
case IOCSR_MAIL_SEND:
|
||||
mail_send(val);
|
||||
break;
|
||||
case IOCSR_ANY_SEND:
|
||||
any_send(val);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps loongarch_ipi_ops = {
|
||||
.read = loongarch_ipi_readl,
|
||||
.write = loongarch_ipi_writel,
|
||||
.impl.min_access_size = 4,
|
||||
.impl.max_access_size = 4,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 8,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void loongarch_ipi_init(Object *obj)
|
||||
{
|
||||
int cpu;
|
||||
LoongArchMachineState *lams;
|
||||
LoongArchIPI *s = LOONGARCH_IPI(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
Object *machine = qdev_get_machine();
|
||||
ObjectClass *mc = object_get_class(machine);
|
||||
/* 'lams' should be initialized */
|
||||
if (!strcmp(MACHINE_CLASS(mc)->name, "none")) {
|
||||
return;
|
||||
}
|
||||
lams = LOONGARCH_MACHINE(machine);
|
||||
for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) {
|
||||
memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops,
|
||||
&lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x100);
|
||||
sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]);
|
||||
qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ipi_core = {
|
||||
.name = "ipi-single",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(status, IPICore),
|
||||
VMSTATE_UINT32(en, IPICore),
|
||||
VMSTATE_UINT32(set, IPICore),
|
||||
VMSTATE_UINT32(clear, IPICore),
|
||||
VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_loongarch_ipi = {
|
||||
.name = TYPE_LOONGARCH_IPI,
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_ARRAY(ipi_core, LoongArchMachineState,
|
||||
MAX_IPI_CORE_NUM, 0,
|
||||
vmstate_ipi_core, IPICore),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_loongarch_ipi;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_ipi_info = {
|
||||
.name = TYPE_LOONGARCH_IPI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LoongArchIPI),
|
||||
.instance_init = loongarch_ipi_init,
|
||||
.class_init = loongarch_ipi_class_init,
|
||||
};
|
||||
|
||||
static void loongarch_ipi_register_types(void)
|
||||
{
|
||||
type_register_static(&loongarch_ipi_info);
|
||||
}
|
||||
|
||||
type_init(loongarch_ipi_register_types)
|
|
@ -0,0 +1,73 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QEMU Loongson 7A1000 msi interrupt controller.
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/intc/loongarch_pch_msi.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
|
||||
int irq_num = val & 0xff;
|
||||
|
||||
trace_loongarch_msi_set_irq(irq_num);
|
||||
assert(irq_num < PCH_MSI_IRQ_NUM);
|
||||
qemu_set_irq(s->pch_msi_irq[irq_num], 1);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps loongarch_pch_msi_ops = {
|
||||
.read = loongarch_msi_mem_read,
|
||||
.write = loongarch_msi_mem_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void pch_msi_irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
|
||||
|
||||
qemu_set_irq(s->pch_msi_irq[irq], level);
|
||||
}
|
||||
|
||||
static void loongarch_pch_msi_init(Object *obj)
|
||||
{
|
||||
LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->msi_mmio, obj, &loongarch_pch_msi_ops,
|
||||
s, TYPE_LOONGARCH_PCH_MSI, 0x8);
|
||||
sysbus_init_mmio(sbd, &s->msi_mmio);
|
||||
msi_nonbroken = true;
|
||||
|
||||
qdev_init_gpio_out(DEVICE(obj), s->pch_msi_irq, PCH_MSI_IRQ_NUM);
|
||||
qdev_init_gpio_in(DEVICE(obj), pch_msi_irq_handler, PCH_MSI_IRQ_NUM);
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_pch_msi_info = {
|
||||
.name = TYPE_LOONGARCH_PCH_MSI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LoongArchPCHMSI),
|
||||
.instance_init = loongarch_pch_msi_init,
|
||||
};
|
||||
|
||||
static void loongarch_pch_msi_register_types(void)
|
||||
{
|
||||
type_register_static(&loongarch_pch_msi_info);
|
||||
}
|
||||
|
||||
type_init(loongarch_pch_msi_register_types)
|
|
@ -0,0 +1,431 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QEMU Loongson 7A1000 I/O interrupt controller.
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
|
||||
{
|
||||
unsigned long val;
|
||||
int irq;
|
||||
|
||||
if (level) {
|
||||
val = mask & s->intirr & ~s->int_mask;
|
||||
if (val) {
|
||||
irq = find_first_bit(&val, 64);
|
||||
s->intisr |= 0x1ULL << irq;
|
||||
qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
|
||||
}
|
||||
} else {
|
||||
val = mask & s->intisr;
|
||||
if (val) {
|
||||
irq = find_first_bit(&val, 64);
|
||||
s->intisr &= ~(0x1ULL << irq);
|
||||
qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pch_pic_irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t mask = 1ULL << irq;
|
||||
|
||||
assert(irq < PCH_PIC_IRQ_NUM);
|
||||
trace_loongarch_pch_pic_irq_handler(irq, level);
|
||||
|
||||
if (s->intedge & mask) {
|
||||
/* Edge triggered */
|
||||
if (level) {
|
||||
if ((s->last_intirr & mask) == 0) {
|
||||
s->intirr |= mask;
|
||||
}
|
||||
s->last_intirr |= mask;
|
||||
} else {
|
||||
s->last_intirr &= ~mask;
|
||||
}
|
||||
} else {
|
||||
/* Level triggered */
|
||||
if (level) {
|
||||
s->intirr |= mask;
|
||||
s->last_intirr |= mask;
|
||||
} else {
|
||||
s->intirr &= ~mask;
|
||||
s->last_intirr &= ~mask;
|
||||
}
|
||||
}
|
||||
pch_pic_update_irq(s, mask, level);
|
||||
}
|
||||
|
||||
static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t val = 0;
|
||||
uint32_t offset = addr & 0xfff;
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_INT_ID_LO:
|
||||
val = PCH_PIC_INT_ID_VAL;
|
||||
break;
|
||||
case PCH_PIC_INT_ID_HI:
|
||||
val = PCH_PIC_INT_ID_NUM;
|
||||
break;
|
||||
case PCH_PIC_INT_MASK_LO:
|
||||
val = (uint32_t)s->int_mask;
|
||||
break;
|
||||
case PCH_PIC_INT_MASK_HI:
|
||||
val = s->int_mask >> 32;
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_LO:
|
||||
val = (uint32_t)s->intedge;
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_HI:
|
||||
val = s->intedge >> 32;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_LO:
|
||||
val = (uint32_t)s->htmsi_en;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_HI:
|
||||
val = s->htmsi_en >> 32;
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_LO:
|
||||
case PCH_PIC_AUTO_CTRL0_HI:
|
||||
case PCH_PIC_AUTO_CTRL1_LO:
|
||||
case PCH_PIC_AUTO_CTRL1_HI:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_pch_pic_low_readw(size, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi)
|
||||
{
|
||||
uint64_t mask = 0xffffffff00000000;
|
||||
uint64_t data = target;
|
||||
|
||||
return hi ? (value & ~mask) | (data << 32) : (value & mask) | data;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint32_t offset, old_valid, data = (uint32_t)value;
|
||||
uint64_t old, int_mask;
|
||||
offset = addr & 0xfff;
|
||||
|
||||
trace_loongarch_pch_pic_low_writew(size, addr, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_INT_MASK_LO:
|
||||
old = s->int_mask;
|
||||
s->int_mask = get_writew_val(old, data, 0);
|
||||
old_valid = (uint32_t)old;
|
||||
if (old_valid & ~data) {
|
||||
pch_pic_update_irq(s, (old_valid & ~data), 1);
|
||||
}
|
||||
if (~old_valid & data) {
|
||||
pch_pic_update_irq(s, (~old_valid & data), 0);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_INT_MASK_HI:
|
||||
old = s->int_mask;
|
||||
s->int_mask = get_writew_val(old, data, 1);
|
||||
old_valid = (uint32_t)(old >> 32);
|
||||
int_mask = old_valid & ~data;
|
||||
if (int_mask) {
|
||||
pch_pic_update_irq(s, int_mask << 32, 1);
|
||||
}
|
||||
int_mask = ~old_valid & data;
|
||||
if (int_mask) {
|
||||
pch_pic_update_irq(s, int_mask << 32, 0);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_LO:
|
||||
s->intedge = get_writew_val(s->intedge, data, 0);
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_HI:
|
||||
s->intedge = get_writew_val(s->intedge, data, 1);
|
||||
break;
|
||||
case PCH_PIC_INT_CLEAR_LO:
|
||||
if (s->intedge & data) {
|
||||
s->intirr &= (~data);
|
||||
pch_pic_update_irq(s, data, 0);
|
||||
s->intisr &= (~data);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_INT_CLEAR_HI:
|
||||
value <<= 32;
|
||||
if (s->intedge & value) {
|
||||
s->intirr &= (~value);
|
||||
pch_pic_update_irq(s, value, 0);
|
||||
s->intisr &= (~value);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_LO:
|
||||
s->htmsi_en = get_writew_val(s->htmsi_en, data, 0);
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_HI:
|
||||
s->htmsi_en = get_writew_val(s->htmsi_en, data, 1);
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_LO:
|
||||
case PCH_PIC_AUTO_CTRL0_HI:
|
||||
case PCH_PIC_AUTO_CTRL1_LO:
|
||||
case PCH_PIC_AUTO_CTRL1_HI:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t val = 0;
|
||||
uint32_t offset = addr & 0xfff;
|
||||
|
||||
switch (offset) {
|
||||
case STATUS_LO_START:
|
||||
val = (uint32_t)(s->intisr & (~s->int_mask));
|
||||
break;
|
||||
case STATUS_HI_START:
|
||||
val = (s->intisr & (~s->int_mask)) >> 32;
|
||||
break;
|
||||
case POL_LO_START:
|
||||
val = (uint32_t)s->int_polarity;
|
||||
break;
|
||||
case POL_HI_START:
|
||||
val = s->int_polarity >> 32;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_pch_pic_high_readw(size, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint32_t offset, data = (uint32_t)value;
|
||||
offset = addr & 0xfff;
|
||||
|
||||
trace_loongarch_pch_pic_high_writew(size, addr, data);
|
||||
|
||||
switch (offset) {
|
||||
case STATUS_LO_START:
|
||||
s->intisr = get_writew_val(s->intisr, data, 0);
|
||||
break;
|
||||
case STATUS_HI_START:
|
||||
s->intisr = get_writew_val(s->intisr, data, 1);
|
||||
break;
|
||||
case POL_LO_START:
|
||||
s->int_polarity = get_writew_val(s->int_polarity, data, 0);
|
||||
break;
|
||||
case POL_HI_START:
|
||||
s->int_polarity = get_writew_val(s->int_polarity, data, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t val = 0;
|
||||
uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
int64_t offset_tmp;
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
|
||||
offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
val = s->htmsi_vector[offset_tmp];
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
val = s->route_entry[offset_tmp];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_pch_pic_readb(size, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
int32_t offset_tmp;
|
||||
uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
|
||||
trace_loongarch_pch_pic_writeb(size, addr, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
|
||||
offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
|
||||
.read = loongarch_pch_pic_low_readw,
|
||||
.write = loongarch_pch_pic_low_writew,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
|
||||
.read = loongarch_pch_pic_high_readw,
|
||||
.write = loongarch_pch_pic_high_writew,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
|
||||
.read = loongarch_pch_pic_readb,
|
||||
.write = loongarch_pch_pic_writeb,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void loongarch_pch_pic_reset(DeviceState *d)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
|
||||
int i;
|
||||
|
||||
s->int_mask = -1;
|
||||
s->htmsi_en = 0x0;
|
||||
s->intedge = 0x0;
|
||||
s->intclr = 0x0;
|
||||
s->auto_crtl0 = 0x0;
|
||||
s->auto_crtl1 = 0x0;
|
||||
for (i = 0; i < 64; i++) {
|
||||
s->route_entry[i] = 0x1;
|
||||
s->htmsi_vector[i] = 0x0;
|
||||
}
|
||||
s->intirr = 0x0;
|
||||
s->intisr = 0x0;
|
||||
s->last_intirr = 0x0;
|
||||
s->int_polarity = 0x0;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_init(Object *obj)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem32_low, obj,
|
||||
&loongarch_pch_pic_reg32_low_ops,
|
||||
s, PCH_PIC_NAME(.reg32_part1), 0x100);
|
||||
memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
|
||||
s, PCH_PIC_NAME(.reg8), 0x2a0);
|
||||
memory_region_init_io(&s->iomem32_high, obj,
|
||||
&loongarch_pch_pic_reg32_high_ops,
|
||||
s, PCH_PIC_NAME(.reg32_part2), 0xc60);
|
||||
sysbus_init_mmio(sbd, &s->iomem32_low);
|
||||
sysbus_init_mmio(sbd, &s->iomem8);
|
||||
sysbus_init_mmio(sbd, &s->iomem32_high);
|
||||
|
||||
qdev_init_gpio_out(DEVICE(obj), s->parent_irq, PCH_PIC_IRQ_NUM);
|
||||
qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_loongarch_pch_pic = {
|
||||
.name = TYPE_LOONGARCH_PCH_PIC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(int_mask, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intedge, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intclr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC),
|
||||
VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
|
||||
VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
|
||||
VMSTATE_UINT64(last_intirr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intirr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intisr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(int_polarity, LoongArchPCHPIC),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = loongarch_pch_pic_reset;
|
||||
dc->vmsd = &vmstate_loongarch_pch_pic;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_pch_pic_info = {
|
||||
.name = TYPE_LOONGARCH_PCH_PIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LoongArchPCHPIC),
|
||||
.instance_init = loongarch_pch_pic_init,
|
||||
.class_init = loongarch_pch_pic_class_init,
|
||||
};
|
||||
|
||||
static void loongarch_pch_pic_register_types(void)
|
||||
{
|
||||
type_register_static(&loongarch_pch_pic_info);
|
||||
}
|
||||
|
||||
type_init(loongarch_pch_pic_register_types)
|
|
@ -63,3 +63,7 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
|
|||
specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
|
||||
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
|
||||
specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
|
||||
|
|
|
@ -463,7 +463,7 @@ static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
|
|||
/* Claim software interrupt bits */
|
||||
for (i = 0; i < swi->num_harts; i++) {
|
||||
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i));
|
||||
/* We don't claim mip.SSIP because it is writeable by software */
|
||||
/* We don't claim mip.SSIP because it is writable by software */
|
||||
if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) {
|
||||
error_report("MSIP already claimed");
|
||||
exit(1);
|
||||
|
|
|
@ -646,7 +646,7 @@ static void riscv_aplic_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
}
|
||||
|
||||
if (addr == APLIC_DOMAINCFG) {
|
||||
/* Only IE bit writeable at the moment */
|
||||
/* Only IE bit writable at the moment */
|
||||
value &= APLIC_DOMAINCFG_IE;
|
||||
aplic->domaincfg = value;
|
||||
} else if ((APLIC_SOURCECFG_BASE <= addr) &&
|
||||
|
|
|
@ -287,3 +287,25 @@ sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u -
|
|||
sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx"
|
||||
sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx"
|
||||
sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
|
||||
|
||||
# loongarch_ipi.c
|
||||
loongarch_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
|
||||
loongarch_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
|
||||
|
||||
# loongarch_pch_pic.c
|
||||
loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d"
|
||||
loongarch_pch_pic_low_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_low_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
|
||||
# loongarch_pch_msi.c
|
||||
loongarch_msi_set_irq(int irq_num) "set msi irq %d"
|
||||
|
||||
# loongarch_extioi.c
|
||||
loongarch_extioi_setirq(int irq, int level) "set extirq irq %d level %d"
|
||||
loongarch_extioi_readw(uint64_t addr, uint32_t val) "addr: 0x%"PRIx64 "val: 0x%x"
|
||||
loongarch_extioi_writew(uint64_t addr, uint64_t val) "addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
config LOONGARCH_VIRT
|
||||
bool
|
||||
select PCI
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
imply VGA_PCI
|
||||
imply VIRTIO_VGA
|
||||
imply PCI_DEVICES
|
||||
select ISA_BUS
|
||||
select SERIAL
|
||||
select SERIAL_ISA
|
||||
select VIRTIO_PCI
|
||||
select LOONGARCH_IPI
|
||||
select LOONGARCH_PCH_PIC
|
||||
select LOONGARCH_PCH_MSI
|
||||
select LOONGARCH_EXTIOI
|
||||
select LS7A_RTC
|
|
@ -0,0 +1,382 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QEMU loongson 3a5000 develop board emulation
|
||||
*
|
||||
* Copyright (c) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/rtc.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/irq.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "hw/intc/loongarch_ipi.h"
|
||||
#include "hw/intc/loongarch_extioi.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "hw/intc/loongarch_pch_msi.h"
|
||||
#include "hw/pci-host/ls7a.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
|
||||
#include "target/loongarch/cpu.h"
|
||||
|
||||
#define PM_BASE 0x10080000
|
||||
#define PM_SIZE 0x100
|
||||
#define PM_CTRL 0x10
|
||||
|
||||
/*
|
||||
* This is a placeholder for missing ACPI,
|
||||
* and will eventually be replaced.
|
||||
*/
|
||||
static uint64_t loongarch_virt_pm_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void loongarch_virt_pm_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
if (addr != PM_CTRL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (val) {
|
||||
case 0x00:
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
return;
|
||||
case 0xff:
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps loongarch_virt_pm_ops = {
|
||||
.read = loongarch_virt_pm_read,
|
||||
.write = loongarch_virt_pm_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1
|
||||
}
|
||||
};
|
||||
|
||||
static struct _loaderparams {
|
||||
uint64_t ram_size;
|
||||
const char *kernel_filename;
|
||||
} loaderparams;
|
||||
|
||||
static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
|
||||
{
|
||||
return addr & 0x1fffffffll;
|
||||
}
|
||||
|
||||
static int64_t load_kernel_info(void)
|
||||
{
|
||||
uint64_t kernel_entry, kernel_low, kernel_high;
|
||||
ssize_t kernel_size;
|
||||
|
||||
kernel_size = load_elf(loaderparams.kernel_filename, NULL,
|
||||
cpu_loongarch_virt_to_phys, NULL,
|
||||
&kernel_entry, &kernel_low,
|
||||
&kernel_high, NULL, 0,
|
||||
EM_LOONGARCH, 1, 0);
|
||||
|
||||
if (kernel_size < 0) {
|
||||
error_report("could not load kernel '%s': %s",
|
||||
loaderparams.kernel_filename,
|
||||
load_elf_strerror(kernel_size));
|
||||
exit(1);
|
||||
}
|
||||
return kernel_entry;
|
||||
}
|
||||
|
||||
static void loongarch_devices_init(DeviceState *pch_pic)
|
||||
{
|
||||
DeviceState *gpex_dev;
|
||||
SysBusDevice *d;
|
||||
PCIBus *pci_bus;
|
||||
MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg;
|
||||
MemoryRegion *mmio_alias, *mmio_reg, *pm_mem;
|
||||
int i;
|
||||
|
||||
gpex_dev = qdev_new(TYPE_GPEX_HOST);
|
||||
d = SYS_BUS_DEVICE(gpex_dev);
|
||||
sysbus_realize_and_unref(d, &error_fatal);
|
||||
pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus;
|
||||
|
||||
/* Map only part size_ecam bytes of ECAM space */
|
||||
ecam_alias = g_new0(MemoryRegion, 1);
|
||||
ecam_reg = sysbus_mmio_get_region(d, 0);
|
||||
memory_region_init_alias(ecam_alias, OBJECT(gpex_dev), "pcie-ecam",
|
||||
ecam_reg, 0, LS_PCIECFG_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), LS_PCIECFG_BASE,
|
||||
ecam_alias);
|
||||
|
||||
/* Map PCI mem space */
|
||||
mmio_alias = g_new0(MemoryRegion, 1);
|
||||
mmio_reg = sysbus_mmio_get_region(d, 1);
|
||||
memory_region_init_alias(mmio_alias, OBJECT(gpex_dev), "pcie-mmio",
|
||||
mmio_reg, LS7A_PCI_MEM_BASE, LS7A_PCI_MEM_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), LS7A_PCI_MEM_BASE,
|
||||
mmio_alias);
|
||||
|
||||
/* Map PCI IO port space. */
|
||||
pio_alias = g_new0(MemoryRegion, 1);
|
||||
pio_reg = sysbus_mmio_get_region(d, 2);
|
||||
memory_region_init_alias(pio_alias, OBJECT(gpex_dev), "pcie-io", pio_reg,
|
||||
LS7A_PCI_IO_OFFSET, LS7A_PCI_IO_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE,
|
||||
pio_alias);
|
||||
|
||||
for (i = 0; i < GPEX_NUM_IRQS; i++) {
|
||||
sysbus_connect_irq(d, i,
|
||||
qdev_get_gpio_in(pch_pic, 16 + i));
|
||||
gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
|
||||
}
|
||||
|
||||
serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
|
||||
qdev_get_gpio_in(pch_pic,
|
||||
LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
|
||||
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
/* Network init */
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
|
||||
if (!nd->model) {
|
||||
nd->model = g_strdup("virtio");
|
||||
}
|
||||
|
||||
pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
|
||||
}
|
||||
|
||||
/* VGA setup */
|
||||
pci_vga_init(pci_bus);
|
||||
|
||||
/*
|
||||
* There are some invalid guest memory access.
|
||||
* Create some unimplemented devices to emulate this.
|
||||
*/
|
||||
create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
|
||||
sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE,
|
||||
qdev_get_gpio_in(pch_pic,
|
||||
LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET));
|
||||
|
||||
pm_mem = g_new(MemoryRegion, 1);
|
||||
memory_region_init_io(pm_mem, NULL, &loongarch_virt_pm_ops,
|
||||
NULL, "loongarch_virt_pm", PM_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), PM_BASE, pm_mem);
|
||||
}
|
||||
|
||||
static void loongarch_irq_init(LoongArchMachineState *lams)
|
||||
{
|
||||
MachineState *ms = MACHINE(lams);
|
||||
DeviceState *pch_pic, *pch_msi, *cpudev;
|
||||
DeviceState *ipi, *extioi;
|
||||
SysBusDevice *d;
|
||||
LoongArchCPU *lacpu;
|
||||
CPULoongArchState *env;
|
||||
CPUState *cpu_state;
|
||||
int cpu, pin, i;
|
||||
|
||||
ipi = qdev_new(TYPE_LOONGARCH_IPI);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
|
||||
|
||||
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
|
||||
|
||||
/*
|
||||
* The connection of interrupts:
|
||||
* +-----+ +---------+ +-------+
|
||||
* | IPI |--> | CPUINTC | <-- | Timer |
|
||||
* +-----+ +---------+ +-------+
|
||||
* ^
|
||||
* |
|
||||
* +---------+
|
||||
* | EIOINTC |
|
||||
* +---------+
|
||||
* ^ ^
|
||||
* | |
|
||||
* +---------+ +---------+
|
||||
* | PCH-PIC | | PCH-MSI |
|
||||
* +---------+ +---------+
|
||||
* ^ ^ ^
|
||||
* | | |
|
||||
* +--------+ +---------+ +---------+
|
||||
* | UARTs | | Devices | | Devices |
|
||||
* +--------+ +---------+ +---------+
|
||||
*/
|
||||
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
||||
cpu_state = qemu_get_cpu(cpu);
|
||||
cpudev = DEVICE(cpu_state);
|
||||
lacpu = LOONGARCH_CPU(cpu_state);
|
||||
env = &(lacpu->env);
|
||||
|
||||
/* connect ipi irq to cpu irq */
|
||||
qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
|
||||
/* IPI iocsr memory region */
|
||||
memory_region_add_subregion(&env->system_iocsr, SMP_IPI_MAILBOX,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
|
||||
cpu));
|
||||
/* extioi iocsr memory region */
|
||||
memory_region_add_subregion(&env->system_iocsr, APIC_BASE,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi),
|
||||
cpu));
|
||||
}
|
||||
|
||||
/*
|
||||
* connect ext irq to the cpu irq
|
||||
* cpu_pin[9:2] <= intc_pin[7:0]
|
||||
*/
|
||||
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
||||
cpudev = DEVICE(qemu_get_cpu(cpu));
|
||||
for (pin = 0; pin < LS3A_INTC_IP; pin++) {
|
||||
qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
|
||||
qdev_get_gpio_in(cpudev, pin + 2));
|
||||
}
|
||||
}
|
||||
|
||||
pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
|
||||
d = SYS_BUS_DEVICE(pch_pic);
|
||||
sysbus_realize_and_unref(d, &error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), LS7A_IOAPIC_REG_BASE,
|
||||
sysbus_mmio_get_region(d, 0));
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
LS7A_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
|
||||
sysbus_mmio_get_region(d, 1));
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
LS7A_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
|
||||
sysbus_mmio_get_region(d, 2));
|
||||
|
||||
/* Connect 64 pch_pic irqs to extioi */
|
||||
for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
|
||||
qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
|
||||
}
|
||||
|
||||
pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
|
||||
d = SYS_BUS_DEVICE(pch_msi);
|
||||
sysbus_realize_and_unref(d, &error_fatal);
|
||||
sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW);
|
||||
for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
|
||||
/* Connect 192 pch_msi irqs to extioi */
|
||||
qdev_connect_gpio_out(DEVICE(d), i,
|
||||
qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
|
||||
}
|
||||
|
||||
loongarch_devices_init(pch_pic);
|
||||
}
|
||||
|
||||
static void reset_load_elf(void *opaque)
|
||||
{
|
||||
LoongArchCPU *cpu = opaque;
|
||||
CPULoongArchState *env = &cpu->env;
|
||||
|
||||
cpu_reset(CPU(cpu));
|
||||
if (env->load_elf) {
|
||||
cpu_set_pc(CPU(cpu), env->elf_address);
|
||||
}
|
||||
}
|
||||
|
||||
static void loongarch_init(MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = machine->cpu_type;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
ram_addr_t offset = 0;
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
uint64_t highram_size = 0;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
|
||||
LoongArchCPU *lacpu;
|
||||
int i;
|
||||
int64_t kernel_addr = 0;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
|
||||
}
|
||||
|
||||
if (!strstr(cpu_model, "la464")) {
|
||||
error_report("LoongArch/TCG needs cpu type la464");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ram_size < 1 * GiB) {
|
||||
error_report("ram_size must be greater than 1G.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Init CPUs */
|
||||
for (i = 0; i < machine->smp.cpus; i++) {
|
||||
cpu_create(machine->cpu_type);
|
||||
}
|
||||
|
||||
/* Add memory region */
|
||||
memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
|
||||
machine->ram, 0, 256 * MiB);
|
||||
memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
|
||||
offset += 256 * MiB;
|
||||
highram_size = ram_size - 256 * MiB;
|
||||
memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
|
||||
machine->ram, offset, highram_size);
|
||||
memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
|
||||
/* Add isa io region */
|
||||
memory_region_init_alias(&lams->isa_io, NULL, "isa-io",
|
||||
get_system_io(), 0, LOONGARCH_ISA_IO_SIZE);
|
||||
memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE,
|
||||
&lams->isa_io);
|
||||
if (kernel_filename) {
|
||||
loaderparams.ram_size = ram_size;
|
||||
loaderparams.kernel_filename = kernel_filename;
|
||||
kernel_addr = load_kernel_info();
|
||||
if (!machine->firmware) {
|
||||
for (i = 0; i < machine->smp.cpus; i++) {
|
||||
lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
|
||||
lacpu->env.load_elf = true;
|
||||
lacpu->env.elf_address = kernel_addr;
|
||||
qemu_register_reset(reset_load_elf, lacpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Initialize the IO interrupt subsystem */
|
||||
loongarch_irq_init(lams);
|
||||
}
|
||||
|
||||
static void loongarch_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Loongson-3A5000 LS7A1000 machine";
|
||||
mc->init = loongarch_init;
|
||||
mc->default_ram_size = 1 * GiB;
|
||||
mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
|
||||
mc->default_ram_id = "loongarch.ram";
|
||||
mc->max_cpus = LOONGARCH_MAX_VCPUS;
|
||||
mc->is_default = 1;
|
||||
mc->default_kernel_irqchip_split = false;
|
||||
mc->block_default_type = IF_VIRTIO;
|
||||
mc->default_boot_order = "c";
|
||||
mc->no_cdrom = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_machine_types[] = {
|
||||
{
|
||||
.name = TYPE_LOONGARCH_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(LoongArchMachineState),
|
||||
.class_init = loongarch_class_init,
|
||||
}
|
||||
};
|
||||
|
||||
DEFINE_TYPES(loongarch_machine_types)
|
|
@ -0,0 +1,4 @@
|
|||
loongarch_ss = ss.source_set()
|
||||
loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('loongson3.c'))
|
||||
|
||||
hw_arch += {'loongarch': loongarch_ss}
|
|
@ -50,6 +50,7 @@ subdir('avr')
|
|||
subdir('cris')
|
||||
subdir('hppa')
|
||||
subdir('i386')
|
||||
subdir('loongarch')
|
||||
subdir('m68k')
|
||||
subdir('microblaze')
|
||||
subdir('mips')
|
||||
|
|
|
@ -456,7 +456,7 @@ static int shpc_cap_add_config(PCIDevice *d, Error **errp)
|
|||
pci_set_byte(config + SHPC_CAP_CxP, 0);
|
||||
pci_set_long(config + SHPC_CAP_DWORD_DATA, 0);
|
||||
d->shpc->cap = config_offset;
|
||||
/* Make dword select and data writeable. */
|
||||
/* Make dword select and data writable. */
|
||||
pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
|
||||
pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
|
||||
return 0;
|
||||
|
|
|
@ -27,3 +27,6 @@ config SUN4V_RTC
|
|||
|
||||
config GOLDFISH_RTC
|
||||
bool
|
||||
|
||||
config LS7A_RTC
|
||||
bool
|
||||
|
|
|
@ -0,0 +1,528 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Loongarch LS7A Real Time Clock emulation
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "include/hw/register.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/log.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "sysemu/rtc.h"
|
||||
#include "hw/registerfields.h"
|
||||
|
||||
#define SYS_TOYTRIM 0x20
|
||||
#define SYS_TOYWRITE0 0x24
|
||||
#define SYS_TOYWRITE1 0x28
|
||||
#define SYS_TOYREAD0 0x2C
|
||||
#define SYS_TOYREAD1 0x30
|
||||
#define SYS_TOYMATCH0 0x34
|
||||
#define SYS_TOYMATCH1 0x38
|
||||
#define SYS_TOYMATCH2 0x3C
|
||||
#define SYS_RTCCTRL 0x40
|
||||
#define SYS_RTCTRIM 0x60
|
||||
#define SYS_RTCWRTIE0 0x64
|
||||
#define SYS_RTCREAD0 0x68
|
||||
#define SYS_RTCMATCH0 0x6C
|
||||
#define SYS_RTCMATCH1 0x70
|
||||
#define SYS_RTCMATCH2 0x74
|
||||
|
||||
#define LS7A_RTC_FREQ 32768
|
||||
#define TIMER_NUMS 3
|
||||
/*
|
||||
* Shift bits and filed mask
|
||||
*/
|
||||
|
||||
FIELD(TOY, MON, 26, 6)
|
||||
FIELD(TOY, DAY, 21, 5)
|
||||
FIELD(TOY, HOUR, 16, 5)
|
||||
FIELD(TOY, MIN, 10, 6)
|
||||
FIELD(TOY, SEC, 4, 6)
|
||||
FIELD(TOY, MSEC, 0, 4)
|
||||
|
||||
FIELD(TOY_MATCH, YEAR, 26, 6)
|
||||
FIELD(TOY_MATCH, MON, 22, 4)
|
||||
FIELD(TOY_MATCH, DAY, 17, 5)
|
||||
FIELD(TOY_MATCH, HOUR, 12, 5)
|
||||
FIELD(TOY_MATCH, MIN, 6, 6)
|
||||
FIELD(TOY_MATCH, SEC, 0, 6)
|
||||
|
||||
FIELD(RTC_CTRL, RTCEN, 13, 1)
|
||||
FIELD(RTC_CTRL, TOYEN, 11, 1)
|
||||
FIELD(RTC_CTRL, EO, 8, 1)
|
||||
|
||||
#define TYPE_LS7A_RTC "ls7a_rtc"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LS7ARtcState, LS7A_RTC)
|
||||
|
||||
struct LS7ARtcState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
/*
|
||||
* Needed to preserve the tick_count across migration, even if the
|
||||
* absolute value of the rtc_clock is different on the source and
|
||||
* destination.
|
||||
*/
|
||||
int64_t offset_toy;
|
||||
int64_t offset_rtc;
|
||||
uint64_t save_toy_mon;
|
||||
uint64_t save_toy_year;
|
||||
uint64_t save_rtc;
|
||||
int64_t data;
|
||||
int tidx;
|
||||
uint32_t toymatch[3];
|
||||
uint32_t toytrim;
|
||||
uint32_t cntrctl;
|
||||
uint32_t rtctrim;
|
||||
uint32_t rtccount;
|
||||
uint32_t rtcmatch[3];
|
||||
QEMUTimer *toy_timer[TIMER_NUMS];
|
||||
QEMUTimer *rtc_timer[TIMER_NUMS];
|
||||
qemu_irq irq;
|
||||
};
|
||||
|
||||
/* switch nanoseconds time to rtc ticks */
|
||||
static inline uint64_t ls7a_rtc_ticks(void)
|
||||
{
|
||||
return qemu_clock_get_ns(rtc_clock) * LS7A_RTC_FREQ / NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
|
||||
/* switch rtc ticks to nanoseconds */
|
||||
static inline uint64_t ticks_to_ns(uint64_t ticks)
|
||||
{
|
||||
return ticks * NANOSECONDS_PER_SECOND / LS7A_RTC_FREQ;
|
||||
}
|
||||
|
||||
static inline bool toy_enabled(LS7ARtcState *s)
|
||||
{
|
||||
return FIELD_EX32(s->cntrctl, RTC_CTRL, TOYEN) &&
|
||||
FIELD_EX32(s->cntrctl, RTC_CTRL, EO);
|
||||
}
|
||||
|
||||
static inline bool rtc_enabled(LS7ARtcState *s)
|
||||
{
|
||||
return FIELD_EX32(s->cntrctl, RTC_CTRL, RTCEN) &&
|
||||
FIELD_EX32(s->cntrctl, RTC_CTRL, EO);
|
||||
}
|
||||
|
||||
/* parse toy value to struct tm */
|
||||
static inline void toy_val_to_time_mon(uint64_t toy_val, struct tm *tm)
|
||||
{
|
||||
tm->tm_sec = FIELD_EX32(toy_val, TOY, SEC);
|
||||
tm->tm_min = FIELD_EX32(toy_val, TOY, MIN);
|
||||
tm->tm_hour = FIELD_EX32(toy_val, TOY, HOUR);
|
||||
tm->tm_mday = FIELD_EX32(toy_val, TOY, DAY);
|
||||
tm->tm_mon = FIELD_EX32(toy_val, TOY, MON) - 1;
|
||||
}
|
||||
|
||||
static inline void toy_val_to_time_year(uint64_t toy_year, struct tm *tm)
|
||||
{
|
||||
tm->tm_year = toy_year;
|
||||
}
|
||||
|
||||
/* parse struct tm to toy value */
|
||||
static inline uint64_t toy_time_to_val_mon(struct tm tm)
|
||||
{
|
||||
uint64_t val = 0;
|
||||
|
||||
val = FIELD_DP32(val, TOY, MON, tm.tm_mon + 1);
|
||||
val = FIELD_DP32(val, TOY, DAY, tm.tm_mday);
|
||||
val = FIELD_DP32(val, TOY, HOUR, tm.tm_hour);
|
||||
val = FIELD_DP32(val, TOY, MIN, tm.tm_min);
|
||||
val = FIELD_DP32(val, TOY, SEC, tm.tm_sec);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline uint64_t toy_time_to_val_year(struct tm tm)
|
||||
{
|
||||
uint64_t year;
|
||||
|
||||
year = tm.tm_year;
|
||||
return year;
|
||||
}
|
||||
|
||||
static inline void toymatch_val_to_time(uint64_t val, struct tm *tm)
|
||||
{
|
||||
tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC);
|
||||
tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN);
|
||||
tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR);
|
||||
tm->tm_mday = FIELD_EX32(val, TOY_MATCH, DAY);
|
||||
tm->tm_mon = FIELD_EX32(val, TOY_MATCH, MON) - 1;
|
||||
tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f));
|
||||
}
|
||||
|
||||
static void toymatch_write(LS7ARtcState *s, struct tm *tm, uint64_t val, int num)
|
||||
{
|
||||
int64_t now, expire_time;
|
||||
|
||||
/* it do not support write when toy disabled */
|
||||
if (toy_enabled(s)) {
|
||||
s->toymatch[num] = val;
|
||||
/* caculate expire time */
|
||||
now = qemu_clock_get_ms(rtc_clock);
|
||||
toymatch_val_to_time(val, tm);
|
||||
expire_time = now + (qemu_timedate_diff(tm) - s->offset_toy) * 1000;
|
||||
timer_mod(s->toy_timer[num], expire_time);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num)
|
||||
{
|
||||
uint64_t expire_ns;
|
||||
|
||||
/* it do not support write when toy disabled */
|
||||
if (rtc_enabled(s)) {
|
||||
s->rtcmatch[num] = val;
|
||||
/* caculate expire time */
|
||||
expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc);
|
||||
timer_mod_ns(s->rtc_timer[num], expire_ns);
|
||||
}
|
||||
}
|
||||
|
||||
static void ls7a_toy_stop(LS7ARtcState *s)
|
||||
{
|
||||
int i;
|
||||
struct tm tm;
|
||||
/*
|
||||
* save time when disabled toy,
|
||||
* because toy time not add counters.
|
||||
*/
|
||||
qemu_get_timedate(&tm, s->offset_toy);
|
||||
s->save_toy_mon = toy_time_to_val_mon(tm);
|
||||
s->save_toy_year = toy_time_to_val_year(tm);
|
||||
|
||||
/* delete timers, and when re-enabled, recaculate expire time */
|
||||
for (i = 0; i < TIMER_NUMS; i++) {
|
||||
timer_del(s->toy_timer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ls7a_rtc_stop(LS7ARtcState *s)
|
||||
{
|
||||
int i;
|
||||
uint64_t time;
|
||||
|
||||
/* save rtc time */
|
||||
time = ls7a_rtc_ticks() + s->offset_rtc;
|
||||
s->save_rtc = time;
|
||||
|
||||
/* delete timers, and when re-enabled, recaculate expire time */
|
||||
for (i = 0; i < TIMER_NUMS; i++) {
|
||||
timer_del(s->rtc_timer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void ls7a_toy_start(LS7ARtcState *s)
|
||||
{
|
||||
int i;
|
||||
uint64_t expire_time, now;
|
||||
struct tm tm;
|
||||
/*
|
||||
* need to recaculate toy offset
|
||||
* and expire time when enable it.
|
||||
*/
|
||||
toy_val_to_time_mon(s->save_toy_mon, &tm);
|
||||
toy_val_to_time_year(s->save_toy_year, &tm);
|
||||
|
||||
s->offset_toy = qemu_timedate_diff(&tm);
|
||||
now = qemu_clock_get_ms(rtc_clock);
|
||||
|
||||
/* recaculate expire time and enable timer */
|
||||
for (i = 0; i < TIMER_NUMS; i++) {
|
||||
toymatch_val_to_time(s->toymatch[i], &tm);
|
||||
expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000;
|
||||
timer_mod(s->toy_timer[i], expire_time);
|
||||
}
|
||||
}
|
||||
|
||||
static void ls7a_rtc_start(LS7ARtcState *s)
|
||||
{
|
||||
int i;
|
||||
uint64_t expire_time, now;
|
||||
|
||||
/*
|
||||
* need to recaculate rtc offset
|
||||
* and expire time when enable it.
|
||||
*/
|
||||
now = ls7a_rtc_ticks();
|
||||
s->offset_rtc = s->save_rtc - now;
|
||||
|
||||
/* recaculate expire time and enable timer */
|
||||
for (i = 0; i < TIMER_NUMS; i++) {
|
||||
expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc);
|
||||
timer_mod_ns(s->rtc_timer[i], expire_time);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
LS7ARtcState *s = LS7A_RTC(opaque);
|
||||
struct tm tm;
|
||||
int val = 0;
|
||||
|
||||
switch (addr) {
|
||||
case SYS_TOYREAD0:
|
||||
/* if toy disabled, read save toy time */
|
||||
if (toy_enabled(s)) {
|
||||
qemu_get_timedate(&tm, s->offset_toy);
|
||||
val = toy_time_to_val_mon(tm);
|
||||
} else {
|
||||
/* read save mon val */
|
||||
val = s->save_toy_mon;
|
||||
}
|
||||
break;
|
||||
case SYS_TOYREAD1:
|
||||
/* if toy disabled, read save toy time */
|
||||
if (toy_enabled(s)) {
|
||||
qemu_get_timedate(&tm, s->offset_toy);
|
||||
val = tm.tm_year;
|
||||
} else {
|
||||
/* read save year val */
|
||||
val = s->save_toy_year;
|
||||
}
|
||||
break;
|
||||
case SYS_TOYMATCH0:
|
||||
val = s->toymatch[0];
|
||||
break;
|
||||
case SYS_TOYMATCH1:
|
||||
val = s->toymatch[1];
|
||||
break;
|
||||
case SYS_TOYMATCH2:
|
||||
val = s->toymatch[2];
|
||||
break;
|
||||
case SYS_RTCCTRL:
|
||||
val = s->cntrctl;
|
||||
break;
|
||||
case SYS_RTCREAD0:
|
||||
/* if rtc disabled, read save rtc time */
|
||||
if (rtc_enabled(s)) {
|
||||
val = ls7a_rtc_ticks() + s->offset_rtc;
|
||||
} else {
|
||||
val = s->save_rtc;
|
||||
}
|
||||
break;
|
||||
case SYS_RTCMATCH0:
|
||||
val = s->rtcmatch[0];
|
||||
break;
|
||||
case SYS_RTCMATCH1:
|
||||
val = s->rtcmatch[1];
|
||||
break;
|
||||
case SYS_RTCMATCH2:
|
||||
val = s->rtcmatch[2];
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ls7a_rtc_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
int old_toyen, old_rtcen, new_toyen, new_rtcen;
|
||||
LS7ARtcState *s = LS7A_RTC(opaque);
|
||||
struct tm tm;
|
||||
|
||||
switch (addr) {
|
||||
case SYS_TOYWRITE0:
|
||||
/* it do not support write when toy disabled */
|
||||
if (toy_enabled(s)) {
|
||||
qemu_get_timedate(&tm, s->offset_toy);
|
||||
tm.tm_sec = FIELD_EX32(val, TOY, SEC);
|
||||
tm.tm_min = FIELD_EX32(val, TOY, MIN);
|
||||
tm.tm_hour = FIELD_EX32(val, TOY, HOUR);
|
||||
tm.tm_mday = FIELD_EX32(val, TOY, DAY);
|
||||
tm.tm_mon = FIELD_EX32(val, TOY, MON) - 1;
|
||||
s->offset_toy = qemu_timedate_diff(&tm);
|
||||
}
|
||||
break;
|
||||
case SYS_TOYWRITE1:
|
||||
if (toy_enabled(s)) {
|
||||
qemu_get_timedate(&tm, s->offset_toy);
|
||||
tm.tm_year = val;
|
||||
s->offset_toy = qemu_timedate_diff(&tm);
|
||||
}
|
||||
break;
|
||||
case SYS_TOYMATCH0:
|
||||
toymatch_write(s, &tm, val, 0);
|
||||
break;
|
||||
case SYS_TOYMATCH1:
|
||||
toymatch_write(s, &tm, val, 1);
|
||||
break;
|
||||
case SYS_TOYMATCH2:
|
||||
toymatch_write(s, &tm, val, 2);
|
||||
break;
|
||||
case SYS_RTCCTRL:
|
||||
/* get old ctrl */
|
||||
old_toyen = toy_enabled(s);
|
||||
old_rtcen = rtc_enabled(s);
|
||||
|
||||
s->cntrctl = val;
|
||||
/* get new ctrl */
|
||||
new_toyen = toy_enabled(s);
|
||||
new_rtcen = rtc_enabled(s);
|
||||
|
||||
/*
|
||||
* we do not consider if EO changed, as it always set at most time.
|
||||
* toy or rtc enabled should start timer. otherwise, stop timer
|
||||
*/
|
||||
if (old_toyen != new_toyen) {
|
||||
if (new_toyen) {
|
||||
ls7a_toy_start(s);
|
||||
} else {
|
||||
ls7a_toy_stop(s);
|
||||
}
|
||||
}
|
||||
if (old_rtcen != new_rtcen) {
|
||||
if (new_rtcen) {
|
||||
ls7a_rtc_start(s);
|
||||
} else {
|
||||
ls7a_rtc_stop(s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SYS_RTCWRTIE0:
|
||||
if (rtc_enabled(s)) {
|
||||
s->offset_rtc = val - ls7a_rtc_ticks();
|
||||
}
|
||||
break;
|
||||
case SYS_RTCMATCH0:
|
||||
rtcmatch_write(s, val, 0);
|
||||
break;
|
||||
case SYS_RTCMATCH1:
|
||||
rtcmatch_write(s, val, 1);
|
||||
break;
|
||||
case SYS_RTCMATCH2:
|
||||
rtcmatch_write(s, val, 2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ls7a_rtc_ops = {
|
||||
.read = ls7a_rtc_read,
|
||||
.write = ls7a_rtc_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void toy_timer_cb(void *opaque)
|
||||
{
|
||||
LS7ARtcState *s = opaque;
|
||||
|
||||
if (toy_enabled(s)) {
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtc_timer_cb(void *opaque)
|
||||
{
|
||||
LS7ARtcState *s = opaque;
|
||||
|
||||
if (rtc_enabled(s)) {
|
||||
qemu_irq_pulse(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static void ls7a_rtc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
int i;
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
LS7ARtcState *d = LS7A_RTC(sbd);
|
||||
memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops,
|
||||
(void *)d, "ls7a_rtc", 0x100);
|
||||
|
||||
sysbus_init_irq(sbd, &d->irq);
|
||||
|
||||
sysbus_init_mmio(sbd, &d->iomem);
|
||||
for (i = 0; i < TIMER_NUMS; i++) {
|
||||
d->toymatch[i] = 0;
|
||||
d->rtcmatch[i] = 0;
|
||||
d->toy_timer[i] = timer_new_ms(rtc_clock, toy_timer_cb, d);
|
||||
d->rtc_timer[i] = timer_new_ms(rtc_clock, rtc_timer_cb, d);
|
||||
}
|
||||
d->offset_toy = 0;
|
||||
d->offset_rtc = 0;
|
||||
d->save_toy_mon = 0;
|
||||
d->save_toy_year = 0;
|
||||
d->save_rtc = 0;
|
||||
|
||||
create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4);
|
||||
}
|
||||
|
||||
static int ls7a_rtc_pre_save(void *opaque)
|
||||
{
|
||||
LS7ARtcState *s = LS7A_RTC(opaque);
|
||||
|
||||
ls7a_toy_stop(s);
|
||||
ls7a_rtc_stop(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ls7a_rtc_post_load(void *opaque, int version_id)
|
||||
{
|
||||
LS7ARtcState *s = LS7A_RTC(opaque);
|
||||
if (toy_enabled(s)) {
|
||||
ls7a_toy_start(s);
|
||||
}
|
||||
|
||||
if (rtc_enabled(s)) {
|
||||
ls7a_rtc_start(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ls7a_rtc = {
|
||||
.name = "ls7a_rtc",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = ls7a_rtc_pre_save,
|
||||
.post_load = ls7a_rtc_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT64(offset_toy, LS7ARtcState),
|
||||
VMSTATE_INT64(offset_rtc, LS7ARtcState),
|
||||
VMSTATE_UINT64(save_toy_mon, LS7ARtcState),
|
||||
VMSTATE_UINT64(save_toy_year, LS7ARtcState),
|
||||
VMSTATE_UINT64(save_rtc, LS7ARtcState),
|
||||
VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS),
|
||||
VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS),
|
||||
VMSTATE_UINT32(cntrctl, LS7ARtcState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
dc->vmsd = &vmstate_ls7a_rtc;
|
||||
dc->realize = ls7a_rtc_realize;
|
||||
dc->desc = "ls7a rtc";
|
||||
}
|
||||
|
||||
static const TypeInfo ls7a_rtc_info = {
|
||||
.name = TYPE_LS7A_RTC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LS7ARtcState),
|
||||
.class_init = ls7a_rtc_class_init,
|
||||
};
|
||||
|
||||
static void ls7a_rtc_register_types(void)
|
||||
{
|
||||
type_register_static(&ls7a_rtc_info);
|
||||
}
|
||||
|
||||
type_init(ls7a_rtc_register_types)
|
|
@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_rtc.c'))
|
|||
softmmu_ss.add(when: 'CONFIG_SUN4V_RTC', if_true: files('sun4v-rtc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_rtc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
|
||||
|
||||
specific_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
|
||||
|
|
|
@ -633,7 +633,7 @@ struct mfi_ctrl_props {
|
|||
* metadata and user data
|
||||
* 1=5%, 2=10%, 3=15% and so on
|
||||
*/
|
||||
uint8_t viewSpace; /* snapshot writeable VIEWs
|
||||
uint8_t viewSpace; /* snapshot writable VIEWs
|
||||
* capacity as a % of source LD
|
||||
* capacity. 0=READ only
|
||||
* 1=5%, 2=10%, 3=15% and so on
|
||||
|
|
|
@ -165,7 +165,7 @@ static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu,
|
|||
}
|
||||
|
||||
if (tte & IOMMU_TTE_DATA_W) {
|
||||
/* Writeable */
|
||||
/* Writable */
|
||||
ret.perm = IOMMU_RW;
|
||||
} else {
|
||||
ret.perm = IOMMU_RO;
|
||||
|
|
|
@ -324,7 +324,7 @@ static void sse_timer_write(void *opaque, hwaddr offset, uint64_t value,
|
|||
{
|
||||
uint32_t old_ctl = s->cntp_aival_ctl;
|
||||
|
||||
/* EN bit is writeable; CLR bit is write-0-to-clear, write-1-ignored */
|
||||
/* EN bit is writable; CLR bit is write-0-to-clear, write-1-ignored */
|
||||
s->cntp_aival_ctl &= ~R_CNTP_AIVAL_CTL_EN_MASK;
|
||||
s->cntp_aival_ctl |= value & R_CNTP_AIVAL_CTL_EN_MASK;
|
||||
if (!(value & R_CNTP_AIVAL_CTL_CLR_MASK)) {
|
||||
|
|
|
@ -197,6 +197,7 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret)
|
|||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
|
||||
tpmSts, 1); /* fatal error */
|
||||
}
|
||||
memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE);
|
||||
}
|
||||
|
||||
static enum TPMVersion tpm_crb_get_version(TPMIf *ti)
|
||||
|
|
|
@ -50,7 +50,12 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
|
|||
|
||||
static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
|
||||
{
|
||||
return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
|
||||
uint8_t locty;
|
||||
|
||||
locty = (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
|
||||
assert(TPM_TIS_IS_VALID_LOCTY(locty));
|
||||
|
||||
return locty;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1145,7 +1145,15 @@ static void vfio_listener_region_del(MemoryListener *listener,
|
|||
if (unlikely((section->offset_within_address_space &
|
||||
~qemu_real_host_page_mask()) !=
|
||||
(section->offset_within_region & ~qemu_real_host_page_mask()))) {
|
||||
error_report("%s received unaligned region", __func__);
|
||||
if (!vfio_known_safe_misalignment(section)) {
|
||||
error_report("%s received unaligned region %s iova=0x%"PRIx64
|
||||
" offset_within_region=0x%"PRIx64
|
||||
" qemu_real_host_page_size=0x%"PRIxPTR,
|
||||
__func__, memory_region_name(section->mr),
|
||||
section->offset_within_address_space,
|
||||
section->offset_within_region,
|
||||
qemu_real_host_page_size());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add
|
|||
vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d"
|
||||
vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64
|
||||
vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]"
|
||||
vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR ": cannot be mapped for DMA"
|
||||
vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR
|
||||
vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA"
|
||||
vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64
|
||||
vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64
|
||||
|
|
|
@ -241,6 +241,23 @@ enum bfd_architecture
|
|||
#define bfd_mach_cris_v32 32
|
||||
#define bfd_mach_cris_v10_v32 1032
|
||||
bfd_arch_microblaze, /* Xilinx MicroBlaze. */
|
||||
bfd_arch_e2k, /* MCST E2K. */
|
||||
/* It's crucial that the underlying `bfd_mach_e2k*' have the same values as */
|
||||
/* the corresponding `E_E2K_MACH_*'s!!! */
|
||||
#define bfd_mach_e2k_generic 0
|
||||
#define bfd_mach_e2k_ev1 1
|
||||
/* This is interpreted as the common subset of all Elbrus V2 iterations.
|
||||
Currently it is the same as the common subset of all elbrus-2c+. */
|
||||
#define bfd_mach_e2k_ev2 2
|
||||
#define bfd_mach_e2k_ev3 3
|
||||
#define bfd_mach_e2k_ev4 4
|
||||
#define bfd_mach_e2k_ev5 5
|
||||
#define bfd_mach_e2k_ev6 6
|
||||
/* Values 16, 17 and 18 used to be reserved for the first three iterations
|
||||
of `elbrus-v2'. See `include/elf/e2k.h' for why they can't be reused right
|
||||
now. */
|
||||
#define bfd_mach_e2k_8c 19
|
||||
#define bfd_mach_e2k_1cplus 20
|
||||
bfd_arch_moxie, /* The Moxie core. */
|
||||
bfd_arch_ia64, /* HP/Intel ia64 */
|
||||
#define bfd_mach_ia64_elf64 64
|
||||
|
@ -253,6 +270,7 @@ enum bfd_architecture
|
|||
#define bfd_mach_rx 0x75
|
||||
#define bfd_mach_rx_v2 0x76
|
||||
#define bfd_mach_rx_v3 0x77
|
||||
bfd_arch_loongarch,
|
||||
bfd_arch_last
|
||||
};
|
||||
#define bfd_mach_s390_31 31
|
||||
|
@ -407,6 +425,14 @@ typedef struct disassemble_info {
|
|||
int cap_mode;
|
||||
int cap_insn_unit;
|
||||
int cap_insn_split;
|
||||
|
||||
/* If non-zero then try not disassemble beyond this address, even if
|
||||
there are values left in the buffer. This address is the address
|
||||
of the nearest symbol forwards from the start of the disassembly,
|
||||
and it is assumed that it lies on the boundary between instructions.
|
||||
If an instruction spans this address then this is an error in the
|
||||
file being disassembled. */
|
||||
bfd_vma stop_vma;
|
||||
|
||||
} disassemble_info;
|
||||
|
||||
|
@ -458,6 +484,8 @@ int print_insn_riscv64 (bfd_vma, disassemble_info*);
|
|||
int print_insn_riscv128 (bfd_vma, disassemble_info*);
|
||||
int print_insn_rx(bfd_vma, disassemble_info *);
|
||||
int print_insn_hexagon(bfd_vma, disassemble_info *);
|
||||
int print_insn_loongarch(bfd_vma, disassemble_info *);
|
||||
int print_insn_e2k (bfd_vma, disassemble_info*);
|
||||
|
||||
#ifdef CONFIG_CAPSTONE
|
||||
bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size);
|
||||
|
|
|
@ -178,6 +178,9 @@ typedef struct mips_elf_abiflags_v0 {
|
|||
|
||||
#define EM_RX 173 /* Renesas RX family */
|
||||
|
||||
#define EM_MCST_ELBRUS 175 /* MCST Elbrus */
|
||||
#define EM_E2K_OLD 49 /* `e_machine' used in old binaries for E2K */
|
||||
|
||||
#define EM_RISCV 243 /* RISC-V */
|
||||
|
||||
#define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */
|
||||
|
@ -1419,6 +1422,82 @@ typedef struct {
|
|||
#define EF_RISCV_RVE 0x0008
|
||||
#define EF_RISCV_TSO 0x0010
|
||||
|
||||
/* E2k specific definitions. */
|
||||
|
||||
/* Values for Elf32/64_Ehdr.e_flags. */
|
||||
|
||||
#define EF_E2K_IPD 3
|
||||
#define EF_E2K_X86APP 4
|
||||
#define EF_E2K_4MB_PAGES 8
|
||||
#define EF_E2K_INCOMPAT 16
|
||||
#define EF_E2K_PM 32
|
||||
#define EF_E2K_BUG_75842 64
|
||||
|
||||
/* E2k relocs. */
|
||||
|
||||
#define R_E2K_32_ABS 0 /* Direct 32 bit */
|
||||
#define R_E2K_32_PC 2 /* PC relative 32 bit */
|
||||
#define R_E2K_32_JMP_SLOT 8 /* Create PLT entry */
|
||||
#define R_E2K_32_COPY 9 /* Copy relocation */
|
||||
#define R_E2K_32_RELATIVE 10 /* Adjust by program base */
|
||||
#define R_E2K_32_IRELATIVE 11
|
||||
#define R_E2K_32_SIZE 12
|
||||
|
||||
#define R_E2K_64_ABS 50 /* Direct 64 bit */
|
||||
#define R_E2K_64_ABS_LIT 51 /* Direct 64 bit for literal */
|
||||
#define R_E2K_64_PC_LIT 54 /* PC relative 64 bit for literal */
|
||||
#define R_E2K_64_JMP_SLOT 63 /* Create PLT entry */
|
||||
#define R_E2K_64_COPY 64 /* Copy relocation */
|
||||
#define R_E2K_64_RELATIVE 65 /* Adjust by program base */
|
||||
#define R_E2K_64_RELATIVE_LIT 66 /* Adjust by program base for literal */
|
||||
#define R_E2K_64_IRELATIVE 67
|
||||
#define R_E2K_64_SIZE 68
|
||||
#define R_E2K_64_GOTOFF 69
|
||||
|
||||
#define R_E2K_TLS_GDMOD 70
|
||||
#define R_E2K_TLS_GDREL 71
|
||||
#define R_E2K_TLS_IE 74
|
||||
#define R_E2K_32_TLS_LE 75
|
||||
#define R_E2K_64_TLS_LE 76
|
||||
#define R_E2K_TLS_32_DTPMOD 80 /* ID of module containing symbol */
|
||||
#define R_E2K_TLS_32_DTPREL 81
|
||||
#define R_E2K_TLS_64_DTPMOD 82 /* ID of module containing symbol */
|
||||
#define R_E2K_TLS_64_DTPREL 83
|
||||
#define R_E2K_TLS_32_TPREL 84
|
||||
#define R_E2K_TLS_64_TPREL 85
|
||||
|
||||
#define R_E2K_AP 100
|
||||
#define R_E2K_PL 101
|
||||
|
||||
#define R_E2K_GOT 108 /* 32 bit GOT entry */
|
||||
#define R_E2K_GOTOFF 109 /* 32 bit offset to GOT */
|
||||
#define R_E2K_DISP 110 /* PC relative 28 bit for DISP */
|
||||
#define R_E2K_PREF 111
|
||||
#define R_E2K_NONE 112 /* No reloc */
|
||||
|
||||
|
||||
/* Legal values for d_tag field of Elf32_Dyn. */
|
||||
|
||||
/* FIXME: find out whether old dynamic tags may be renamed and their names
|
||||
* be used by modern ones or new names should be customized for modern tags.
|
||||
* This concerns DT_E2K_LAZY renamed to DT_E2K_LAZY_DEFECTIVE. */
|
||||
#define DT_E2K_LAZY_DEFECTIVE (DT_LOPROC + 0)
|
||||
#define DT_E2K_LAZY (DT_LOPROC + 1)
|
||||
|
||||
/* This tag will be hopefully used for a limited period of time. `DT_LOPROC + 1'
|
||||
* has already been reserved in glibc-2.16 and binutils-2.23.1 to mark
|
||||
* non-defective lazy binding implementation without this awful Bug #75842 taken
|
||||
* into account. */
|
||||
#define DT_E2K_LAZY_BUG_75842 (DT_LOPROC + 2)
|
||||
#define DT_E2K_LAZY_GOT (DT_LOPROC + 3)
|
||||
|
||||
#define DT_E2K_INIT_GOT (DT_LOPROC + 0x101c)
|
||||
#define DT_E2K_EXPORT_PL (DT_LOPROC + 0x101d)
|
||||
#define DT_E2K_EXPORT_PLSZ (DT_LOPROC + 0x101e)
|
||||
#define DT_E2K_REAL_PLTGOT (DT_LOPROC + 0x101f)
|
||||
|
||||
#define DT_E2K_NUM 0x1020
|
||||
|
||||
typedef struct elf32_rel {
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
#pragma GCC poison TARGET_ARM
|
||||
#pragma GCC poison TARGET_CRIS
|
||||
#pragma GCC poison TARGET_HEXAGON
|
||||
#pragma GCC poison TARGET_E2K
|
||||
#pragma GCC poison TARGET_E2K32
|
||||
#pragma GCC poison TARGET_HPPA
|
||||
#pragma GCC poison TARGET_LOONGARCH64
|
||||
#pragma GCC poison TARGET_M68K
|
||||
#pragma GCC poison TARGET_MICROBLAZE
|
||||
#pragma GCC poison TARGET_MIPS
|
||||
|
@ -71,6 +74,7 @@
|
|||
#pragma GCC poison CONFIG_HPPA_DIS
|
||||
#pragma GCC poison CONFIG_I386_DIS
|
||||
#pragma GCC poison CONFIG_HEXAGON_DIS
|
||||
#pragma GCC poison CONFIG_LOONGARCH_DIS
|
||||
#pragma GCC poison CONFIG_M68K_DIS
|
||||
#pragma GCC poison CONFIG_MICROBLAZE_DIS
|
||||
#pragma GCC poison CONFIG_MIPS_DIS
|
||||
|
|
|
@ -35,14 +35,20 @@
|
|||
#include "hw/dma/xlnx_dpdma.h"
|
||||
#include "audio/audio.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#define AUD_CHBUF_MAX_DEPTH (32 * KiB)
|
||||
#define MAX_QEMU_BUFFER_SIZE (4 * KiB)
|
||||
|
||||
#define DP_CORE_REG_ARRAY_SIZE (0x3AF >> 2)
|
||||
#define DP_CORE_REG_OFFSET (0x0000)
|
||||
#define DP_CORE_REG_ARRAY_SIZE (0x3B0 >> 2)
|
||||
#define DP_AVBUF_REG_OFFSET (0xB000)
|
||||
#define DP_AVBUF_REG_ARRAY_SIZE (0x238 >> 2)
|
||||
#define DP_VBLEND_REG_ARRAY_SIZE (0x1DF >> 2)
|
||||
#define DP_VBLEND_REG_OFFSET (0xA000)
|
||||
#define DP_VBLEND_REG_ARRAY_SIZE (0x1E0 >> 2)
|
||||
#define DP_AUDIO_REG_OFFSET (0xC000)
|
||||
#define DP_AUDIO_REG_ARRAY_SIZE (0x50 >> 2)
|
||||
#define DP_CONTAINER_SIZE (0xC050)
|
||||
|
||||
struct PixmanPlane {
|
||||
pixman_format_code_t format;
|
||||
|
@ -102,6 +108,8 @@ struct XlnxDPState {
|
|||
*/
|
||||
DPCDState *dpcd;
|
||||
I2CDDCState *edid;
|
||||
|
||||
ptimer_state *vblank;
|
||||
};
|
||||
|
||||
#define TYPE_XLNX_DP "xlnx.v-dp"
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
|
||||
DriveInfo *hd0, DriveInfo *hd1);
|
||||
|
||||
/* ide-pci.c */
|
||||
int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux);
|
||||
|
||||
/* ide-mmio.c */
|
||||
void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1);
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch 3A5000 ext interrupt controller definitions
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
|
||||
#ifndef LOONGARCH_EXTIOI_H
|
||||
#define LOONGARCH_EXTIOI_H
|
||||
|
||||
#define LS3A_INTC_IP 8
|
||||
#define EXTIOI_IRQS (256)
|
||||
#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8)
|
||||
/* map to ipnum per 32 irqs */
|
||||
#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32)
|
||||
#define EXTIOI_IRQS_COREMAP_SIZE 256
|
||||
#define EXTIOI_IRQS_NODETYPE_COUNT 16
|
||||
#define EXTIOI_IRQS_GROUP_COUNT 8
|
||||
|
||||
#define APIC_OFFSET 0x400
|
||||
#define APIC_BASE (0x1000ULL + APIC_OFFSET)
|
||||
|
||||
#define EXTIOI_NODETYPE_START (0x4a0 - APIC_OFFSET)
|
||||
#define EXTIOI_NODETYPE_END (0x4c0 - APIC_OFFSET)
|
||||
#define EXTIOI_IPMAP_START (0x4c0 - APIC_OFFSET)
|
||||
#define EXTIOI_IPMAP_END (0x4c8 - APIC_OFFSET)
|
||||
#define EXTIOI_ENABLE_START (0x600 - APIC_OFFSET)
|
||||
#define EXTIOI_ENABLE_END (0x620 - APIC_OFFSET)
|
||||
#define EXTIOI_BOUNCE_START (0x680 - APIC_OFFSET)
|
||||
#define EXTIOI_BOUNCE_END (0x6a0 - APIC_OFFSET)
|
||||
#define EXTIOI_ISR_START (0x700 - APIC_OFFSET)
|
||||
#define EXTIOI_ISR_END (0x720 - APIC_OFFSET)
|
||||
#define EXTIOI_COREISR_START (0x800 - APIC_OFFSET)
|
||||
#define EXTIOI_COREISR_END (0xB20 - APIC_OFFSET)
|
||||
#define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET)
|
||||
#define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET)
|
||||
|
||||
#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
|
||||
struct LoongArchExtIOI {
|
||||
SysBusDevice parent_obj;
|
||||
/* hardware state */
|
||||
uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
|
||||
uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
|
||||
uint32_t isr[EXTIOI_IRQS / 32];
|
||||
uint32_t coreisr[LOONGARCH_MAX_VCPUS][EXTIOI_IRQS_GROUP_COUNT];
|
||||
uint32_t enable[EXTIOI_IRQS / 32];
|
||||
uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4];
|
||||
uint32_t coremap[EXTIOI_IRQS / 4];
|
||||
uint32_t sw_pending[EXTIOI_IRQS / 32];
|
||||
DECLARE_BITMAP(sw_isr[LOONGARCH_MAX_VCPUS][LS3A_INTC_IP], EXTIOI_IRQS);
|
||||
uint8_t sw_ipmap[EXTIOI_IRQS_IPMAP_SIZE];
|
||||
uint8_t sw_coremap[EXTIOI_IRQS];
|
||||
qemu_irq parent_irq[LOONGARCH_MAX_VCPUS][LS3A_INTC_IP];
|
||||
qemu_irq irq[EXTIOI_IRQS];
|
||||
MemoryRegion extioi_iocsr_mem[LOONGARCH_MAX_VCPUS];
|
||||
MemoryRegion extioi_system_mem;
|
||||
};
|
||||
#endif /* LOONGARCH_EXTIOI_H */
|
|
@ -0,0 +1,52 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch ipi interrupt header files
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef HW_LOONGARCH_IPI_H
|
||||
#define HW_LOONGARCH_IPI_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
/* Mainy used by iocsr read and write */
|
||||
#define SMP_IPI_MAILBOX 0x1000ULL
|
||||
#define CORE_STATUS_OFF 0x0
|
||||
#define CORE_EN_OFF 0x4
|
||||
#define CORE_SET_OFF 0x8
|
||||
#define CORE_CLEAR_OFF 0xc
|
||||
#define CORE_BUF_20 0x20
|
||||
#define CORE_BUF_28 0x28
|
||||
#define CORE_BUF_30 0x30
|
||||
#define CORE_BUF_38 0x38
|
||||
#define IOCSR_IPI_SEND 0x40
|
||||
#define IOCSR_MAIL_SEND 0x48
|
||||
#define IOCSR_ANY_SEND 0x158
|
||||
|
||||
/* IPI system memory address */
|
||||
#define IPI_SYSTEM_MEM 0x1fe01000
|
||||
|
||||
#define MAX_IPI_CORE_NUM 4
|
||||
#define MAX_IPI_MBX_NUM 4
|
||||
|
||||
#define TYPE_LOONGARCH_IPI "loongarch_ipi"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
|
||||
|
||||
typedef struct IPICore {
|
||||
uint32_t status;
|
||||
uint32_t en;
|
||||
uint32_t set;
|
||||
uint32_t clear;
|
||||
/* 64bit buf divide into 2 32bit buf */
|
||||
uint32_t buf[MAX_IPI_MBX_NUM * 2];
|
||||
qemu_irq irq;
|
||||
} IPICore;
|
||||
|
||||
struct LoongArchIPI {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion ipi_iocsr_mem[MAX_IPI_CORE_NUM];
|
||||
MemoryRegion ipi_system_mem[MAX_IPI_CORE_NUM];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch 7A1000 I/O interrupt controller definitions
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI)
|
||||
|
||||
/* Msi irq start start from 64 to 255 */
|
||||
#define PCH_MSI_IRQ_START 64
|
||||
#define PCH_MSI_IRQ_END 255
|
||||
#define PCH_MSI_IRQ_NUM 192
|
||||
|
||||
struct LoongArchPCHMSI {
|
||||
SysBusDevice parent_obj;
|
||||
qemu_irq pch_msi_irq[PCH_MSI_IRQ_NUM];
|
||||
MemoryRegion msi_mmio;
|
||||
};
|
|
@ -0,0 +1,69 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch 7A1000 I/O interrupt controller definitions
|
||||
*
|
||||
* Copyright (c) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
|
||||
#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
|
||||
|
||||
#define PCH_PIC_IRQ_START 0
|
||||
#define PCH_PIC_IRQ_END 63
|
||||
#define PCH_PIC_IRQ_NUM 64
|
||||
#define PCH_PIC_INT_ID_VAL 0x7000000UL
|
||||
#define PCH_PIC_INT_ID_NUM 0x3f0001UL
|
||||
|
||||
#define PCH_PIC_INT_ID_LO 0x00
|
||||
#define PCH_PIC_INT_ID_HI 0x04
|
||||
#define PCH_PIC_INT_MASK_LO 0x20
|
||||
#define PCH_PIC_INT_MASK_HI 0x24
|
||||
#define PCH_PIC_HTMSI_EN_LO 0x40
|
||||
#define PCH_PIC_HTMSI_EN_HI 0x44
|
||||
#define PCH_PIC_INT_EDGE_LO 0x60
|
||||
#define PCH_PIC_INT_EDGE_HI 0x64
|
||||
#define PCH_PIC_INT_CLEAR_LO 0x80
|
||||
#define PCH_PIC_INT_CLEAR_HI 0x84
|
||||
#define PCH_PIC_AUTO_CTRL0_LO 0xc0
|
||||
#define PCH_PIC_AUTO_CTRL0_HI 0xc4
|
||||
#define PCH_PIC_AUTO_CTRL1_LO 0xe0
|
||||
#define PCH_PIC_AUTO_CTRL1_HI 0xe4
|
||||
#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100
|
||||
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
|
||||
#define PCH_PIC_HTMSI_VEC_OFFSET 0x200
|
||||
#define PCH_PIC_HTMSI_VEC_END 0x23f
|
||||
#define PCH_PIC_INT_STATUS_LO 0x3a0
|
||||
#define PCH_PIC_INT_STATUS_HI 0x3a4
|
||||
#define PCH_PIC_INT_POL_LO 0x3e0
|
||||
#define PCH_PIC_INT_POL_HI 0x3e4
|
||||
|
||||
#define STATUS_LO_START 0
|
||||
#define STATUS_HI_START 0x4
|
||||
#define POL_LO_START 0x40
|
||||
#define POL_HI_START 0x44
|
||||
struct LoongArchPCHPIC {
|
||||
SysBusDevice parent_obj;
|
||||
qemu_irq parent_irq[64];
|
||||
uint64_t int_mask; /*0x020 interrupt mask register*/
|
||||
uint64_t htmsi_en; /*0x040 1=msi*/
|
||||
uint64_t intedge; /*0x060 edge=1 level =0*/
|
||||
uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
|
||||
uint64_t auto_crtl0; /*0x0c0*/
|
||||
uint64_t auto_crtl1; /*0x0e0*/
|
||||
uint64_t last_intirr; /* edge detection */
|
||||
uint64_t intirr; /* 0x380 interrupt request register */
|
||||
uint64_t intisr; /* 0x3a0 interrupt service register */
|
||||
/*
|
||||
* 0x3e0 interrupt level polarity selection
|
||||
* register 0 for high level trigger
|
||||
*/
|
||||
uint64_t int_polarity;
|
||||
|
||||
uint8_t route_entry[64]; /*0x100 - 0x138*/
|
||||
uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
|
||||
|
||||
MemoryRegion iomem32_low;
|
||||
MemoryRegion iomem32_high;
|
||||
MemoryRegion iomem8;
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Definitions for loongarch board emulation.
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef HW_LOONGARCH_H
|
||||
#define HW_LOONGARCH_H
|
||||
|
||||
#include "target/loongarch/cpu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "hw/intc/loongarch_ipi.h"
|
||||
|
||||
#define LOONGARCH_MAX_VCPUS 4
|
||||
|
||||
#define LOONGARCH_ISA_IO_BASE 0x18000000UL
|
||||
#define LOONGARCH_ISA_IO_SIZE 0x0004000
|
||||
|
||||
struct LoongArchMachineState {
|
||||
/*< private >*/
|
||||
MachineState parent_obj;
|
||||
|
||||
IPICore ipi_core[MAX_IPI_CORE_NUM];
|
||||
MemoryRegion lowmem;
|
||||
MemoryRegion highmem;
|
||||
MemoryRegion isa_io;
|
||||
};
|
||||
|
||||
#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt")
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE)
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QEMU LoongArch CPU
|
||||
*
|
||||
* Copyright (c) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef HW_LS7A_H
|
||||
#define HW_LS7A_H
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci-host/pam.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define LS7A_PCI_MEM_BASE 0x40000000UL
|
||||
#define LS7A_PCI_MEM_SIZE 0x40000000UL
|
||||
#define LS7A_PCI_IO_OFFSET 0x4000
|
||||
#define LS_PCIECFG_BASE 0x20000000
|
||||
#define LS_PCIECFG_SIZE 0x08000000
|
||||
#define LS7A_PCI_IO_BASE 0x18004000UL
|
||||
#define LS7A_PCI_IO_SIZE 0xC000
|
||||
|
||||
#define LS7A_PCH_REG_BASE 0x10000000UL
|
||||
#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE)
|
||||
#define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL
|
||||
|
||||
/*
|
||||
* According to the kernel pch irq start from 64 offset
|
||||
* 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs
|
||||
* used for pci device.
|
||||
*/
|
||||
#define PCH_PIC_IRQ_OFFSET 64
|
||||
#define LS7A_DEVICE_IRQS 16
|
||||
#define LS7A_PCI_IRQS 48
|
||||
#define LS7A_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2)
|
||||
#define LS7A_UART_BASE 0x1fe001e0
|
||||
#define LS7A_RTC_IRQ (PCH_PIC_IRQ_OFFSET + 3)
|
||||
#define LS7A_MISC_REG_BASE (LS7A_PCH_REG_BASE + 0x00080000)
|
||||
#define LS7A_RTC_REG_BASE (LS7A_MISC_REG_BASE + 0x00050100)
|
||||
#define LS7A_RTC_LEN 0x100
|
||||
#endif
|
|
@ -24,6 +24,8 @@ enum {
|
|||
QEMU_ARCH_RX = (1 << 20),
|
||||
QEMU_ARCH_AVR = (1 << 21),
|
||||
QEMU_ARCH_HEXAGON = (1 << 22),
|
||||
QEMU_ARCH_LOONGARCH = (1 << 23),
|
||||
QEMU_ARCH_E2K = (1 << 24),
|
||||
};
|
||||
|
||||
extern const uint32_t arch_type;
|
||||
|
|
|
@ -279,7 +279,7 @@ typedef struct TCGPool {
|
|||
|
||||
#define TCG_POOL_CHUNK_SIZE 32768
|
||||
|
||||
#define TCG_MAX_TEMPS 512
|
||||
#define TCG_MAX_TEMPS 1024
|
||||
#define TCG_MAX_INSNS 512
|
||||
|
||||
/* when the size of the arguments of a called function is smaller than
|
||||
|
|
|
@ -315,7 +315,7 @@ static int target_restore_sigframe(CPUARMState *env,
|
|||
|
||||
case TARGET_SVE_MAGIC:
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
|
||||
vq = (env->vfp.zcr_el[1] & 0xf) + 1;
|
||||
vq = sve_vq(env);
|
||||
sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
|
||||
if (!sve && size == sve_size) {
|
||||
sve = (struct target_sve_context *)ctx;
|
||||
|
@ -434,7 +434,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
|||
|
||||
/* SVE state needs saving only if it exists. */
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
|
||||
vq = (env->vfp.zcr_el[1] & 0xf) + 1;
|
||||
vq = sve_vq(env);
|
||||
sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
|
||||
sve_ofs = alloc_sigframe_space(sve_size, &layout);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ static abi_long do_prctl_get_vl(CPUArchState *env)
|
|||
{
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
if (cpu_isar_feature(aa64_sve, cpu)) {
|
||||
return ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 16;
|
||||
return sve_vq(env) * 16;
|
||||
}
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
@ -25,18 +25,24 @@ static abi_long do_prctl_set_vl(CPUArchState *env, abi_long arg2)
|
|||
*/
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(env))
|
||||
&& arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
uint32_t vq, old_vq;
|
||||
|
||||
old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
|
||||
vq = MAX(arg2 / 16, 1);
|
||||
vq = MIN(vq, cpu->sve_max_vq);
|
||||
old_vq = sve_vq(env);
|
||||
|
||||
/*
|
||||
* Bound the value of arg2, so that we know that it fits into
|
||||
* the 4-bit field in ZCR_EL1. Rely on the hflags rebuild to
|
||||
* sort out the length supported by the cpu.
|
||||
*/
|
||||
vq = MAX(arg2 / 16, 1);
|
||||
vq = MIN(vq, ARM_MAX_VQ);
|
||||
env->vfp.zcr_el[1] = vq - 1;
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
vq = sve_vq(env);
|
||||
if (vq < old_vq) {
|
||||
aarch64_sve_narrow_vq(env, vq);
|
||||
}
|
||||
env->vfp.zcr_el[1] = vq - 1;
|
||||
arm_rebuild_hflags(env);
|
||||
return vq * 16;
|
||||
}
|
||||
return -TARGET_EINVAL;
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* qemu user cpu loop
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/help-texts.h"
|
||||
#include "qemu.h"
|
||||
#include "user-internals.h"
|
||||
#include "signal-common.h"
|
||||
#include "user-mmap.h"
|
||||
#include "cpu_loop-common.h"
|
||||
#include "target_elf.h"
|
||||
|
||||
static void gen_signal(CPUE2KState *env, int signo, int code, abi_ulong addr)
|
||||
{
|
||||
target_siginfo_t info = {
|
||||
.si_signo = signo,
|
||||
.si_code = code,
|
||||
._sifields._sigfault._addr = addr,
|
||||
// TODO: ._sifields._sigfault._trapno = trapnr
|
||||
};
|
||||
|
||||
queue_signal(env, signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
|
||||
static void stack_expand(CPUE2KState *env, E2KPsp *s)
|
||||
{
|
||||
abi_ulong new_size, new_size_tag;
|
||||
abi_long new_base, new_base_tag = 0;
|
||||
|
||||
new_size = s->size * 2;
|
||||
new_size_tag = new_size / 8;
|
||||
new_base = target_mremap(s->base, s->size, new_size, MREMAP_MAYMOVE, 0);
|
||||
if (s->base_tag) {
|
||||
new_base_tag = target_mremap(s->base_tag, s->size / 8, new_size_tag,
|
||||
MREMAP_MAYMOVE, 0);
|
||||
}
|
||||
if (new_base == -1 || new_base_tag == -1) {
|
||||
gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->ip);
|
||||
return;
|
||||
}
|
||||
|
||||
s->base = new_base;
|
||||
s->base_tag = new_base_tag;
|
||||
s->size = new_size;
|
||||
}
|
||||
|
||||
void cpu_loop(CPUE2KState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr;
|
||||
|
||||
while (1) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
switch (trapnr) {
|
||||
case EXCP_SYSCALL: {
|
||||
abi_ullong args[E2K_SYSCALL_MAX_ARGS] = { 0 };
|
||||
int i, psize = MIN(E2K_SYSCALL_MAX_ARGS, env->wd.size);
|
||||
abi_ulong ret;
|
||||
|
||||
// TODO: check what happens if env->wd.size is zero
|
||||
for (i = 0; i < psize; i++) {
|
||||
args[i] = env->regs[i].lo;
|
||||
}
|
||||
|
||||
ret = do_syscall(env, args[0], args[1], args[2], args[3],
|
||||
args[4], args[5], args[6], args[7], args[8]);
|
||||
|
||||
if (ret == -QEMU_ERESTARTSYS) {
|
||||
/* do not set sysret address and syscall will be restarted */
|
||||
} else if (ret != -QEMU_ESIGRETURN && env->wd.psize > 0) {
|
||||
memset(env->tags, E2K_TAG_NON_NUMBER64,
|
||||
psize * sizeof(env->tags[0]));
|
||||
|
||||
env->regs[0].lo = ret;
|
||||
env->tags[0] = E2K_TAG_NUMBER64;
|
||||
env->ip = E2K_SYSRET_ADDR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXCP_ILLEGAL_OPCODE:
|
||||
case EXCP_PRIV_ACTION:
|
||||
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPC, env->ip);
|
||||
break;
|
||||
case EXCP_ILLEGAL_OPERAND:
|
||||
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPN, env->ip);
|
||||
break;
|
||||
case EXCP_CHAIN_STACK_BOUNDS:
|
||||
stack_expand(env, &env->pcsp);
|
||||
break;
|
||||
case EXCP_PROC_STACK_BOUNDS:
|
||||
stack_expand(env, &env->psp);
|
||||
break;
|
||||
case EXCP_WINDOW_BOUNDS:
|
||||
case EXCP_ARRAY_BOUNDS:
|
||||
case EXCP_DATA_PAGE:
|
||||
gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->ip);
|
||||
break;
|
||||
case EXCP_DIV:
|
||||
gen_signal(env, TARGET_SIGFPE, 0, env->ip);
|
||||
break;
|
||||
/* QEMU common interrupts */
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
env->is_bp = true;
|
||||
e2k_proc_call(env, env->wd.size, env->ip, true);
|
||||
gen_signal(env, TARGET_SIGTRAP, TARGET_TRAP_BRKPT, 0);
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
case EXCP_HLT:
|
||||
case EXCP_HALTED:
|
||||
case EXCP_YIELD:
|
||||
fprintf(stderr, "Unhandled QEMU trap: 0x%x\n", trapnr);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
process_pending_signals (env);
|
||||
}
|
||||
}
|
||||
|
||||
void target_cpu_copy_regs(CPUE2KState *env, struct target_pt_regs *regs)
|
||||
{
|
||||
CPUState *cpu = env_cpu(env);
|
||||
TaskState *ts = cpu->opaque;
|
||||
struct image_info *info = ts->info;
|
||||
uint32_t eflags = info->elf_flags;
|
||||
|
||||
env->psr = PSR_NMIE | PSR_SGE | PSR_IE;
|
||||
env->upsr = UPSR_NMIE | UPSR_IE | UPSR_FE;
|
||||
env->ip = regs->ip;
|
||||
env->pcsp = regs->pcsp;
|
||||
env->psp = regs->psp;
|
||||
env->usd.lo = regs->usd_lo;
|
||||
env->usd.hi = regs->usd_hi;
|
||||
env->sbr = regs->sbr;
|
||||
env->elf_flags = info->elf_flags;
|
||||
|
||||
// Save initial frame for gdb.
|
||||
env->is_bp = true;
|
||||
e2k_proc_call(env, env->wd.size, env->ip, true);
|
||||
|
||||
// TODO: set a chain info to return to kernel
|
||||
|
||||
if (eflags & E2K_ELF_PM) {
|
||||
fprintf(stderr, "Protected mode is unsupported\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (eflags & E2K_ELF_X86APP) {
|
||||
fprintf(stderr, "x86 recompiler is unsupported\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
const char *cpu_get_model(uint32_t eflags)
|
||||
{
|
||||
const char *name = "any";
|
||||
uint32_t machine = E2K_ELF_MACH(eflags);
|
||||
|
||||
/* TODO: can't check for EM_E2K_OLD flags because e_machine isn't saved anywhere... */
|
||||
switch(machine) {
|
||||
case E2K_MACH_EV2: name = "e2c+"; break;
|
||||
case E2K_MACH_EV3: name = "e2s"; break;
|
||||
case E2K_MACH_1CPLUS:
|
||||
case E2K_MACH_8C:
|
||||
case E2K_MACH_EV4: name = "e8c"; break;
|
||||
case E2K_MACH_EV5: name = "e8c2"; break;
|
||||
case E2K_MACH_EV6: name = "e16c"; break;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Emulation of Linux signals
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2020 Alibek Omarov
|
||||
* Copyright (c) 2021 Denis Drakhnya
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "user-internals.h"
|
||||
#include "signal-common.h"
|
||||
#include "linux-user/trace.h"
|
||||
#include "target/e2k/helper-tcg.h"
|
||||
|
||||
#define MAX_TC_SIZE 10
|
||||
|
||||
#define TIR_NUM 19
|
||||
#define DAM_ENTRIES_NUM 32
|
||||
#define SBBP_ENTRIES_NUM 32
|
||||
|
||||
/* from user.h !!! */
|
||||
#define MLT_NUM (16 * 3) /* common for E3M and E3S */
|
||||
|
||||
struct target_sigcontext {
|
||||
abi_ullong cr0_lo;
|
||||
abi_ullong cr0_hi;
|
||||
abi_ullong cr1_lo;
|
||||
abi_ullong cr1_hi;
|
||||
abi_ullong sbr; /* 21 Stack base register: top of */
|
||||
/* local data (user) stack */
|
||||
abi_ullong usd_lo; /* 22 Local data (user) stack */
|
||||
abi_ullong usd_hi; /* 23 descriptor: base & size */
|
||||
abi_ullong psp_lo; /* 24 Procedure stack pointer: */
|
||||
abi_ullong psp_hi; /* 25 base & index & size */
|
||||
abi_ullong pcsp_lo; /* 26 Procedure chain stack */
|
||||
abi_ullong pcsp_hi; /* 27 pointer: base & index & size */
|
||||
|
||||
/* additional part (for binary compiler) */
|
||||
abi_ullong rpr_hi;
|
||||
abi_ullong rpr_lo;
|
||||
|
||||
abi_ullong nr_TIRs;
|
||||
abi_ullong tir_lo[TIR_NUM];
|
||||
abi_ullong tir_hi[TIR_NUM];
|
||||
abi_ullong trap_cell_addr[MAX_TC_SIZE];
|
||||
abi_ullong trap_cell_val[MAX_TC_SIZE];
|
||||
uint8_t trap_cell_tag[MAX_TC_SIZE];
|
||||
abi_ullong trap_cell_info[MAX_TC_SIZE];
|
||||
|
||||
abi_ullong dam[DAM_ENTRIES_NUM];
|
||||
abi_ullong sbbp[SBBP_ENTRIES_NUM];
|
||||
abi_ullong mlt[MLT_NUM];
|
||||
abi_ullong upsr;
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure is used for compatibility
|
||||
* All new fields must be added in this structure
|
||||
*/
|
||||
struct target_extra_ucontext {
|
||||
abi_int sizeof_extra_uc; /* size of used fields(in bytes) */
|
||||
abi_int curr_cnt; /* current index into trap_celler */
|
||||
abi_int tc_count; /* trap_celler records count */
|
||||
|
||||
/*
|
||||
* For getcontext()
|
||||
*/
|
||||
abi_int fpcr;
|
||||
abi_int fpsr;
|
||||
abi_int pfpfr;
|
||||
|
||||
abi_ullong ctpr1;
|
||||
abi_ullong ctpr2;
|
||||
abi_ullong ctpr3;
|
||||
|
||||
abi_int sc_need_rstrt;
|
||||
};
|
||||
|
||||
struct target_ucontext {
|
||||
abi_ulong uc_flags;
|
||||
struct target_ucontext *uc_link;
|
||||
target_stack_t uc_stack;
|
||||
struct target_sigcontext uc_mcontext;
|
||||
union {
|
||||
target_sigset_t uc_sigmask; /* mask last for extensibility */
|
||||
abi_ullong pad[16];
|
||||
};
|
||||
struct target_extra_ucontext uc_extra; /* for compatibility */
|
||||
};
|
||||
|
||||
struct target_sigframe {
|
||||
target_siginfo_t info;
|
||||
union {
|
||||
struct target_ucontext uc;
|
||||
// TODO: ucontext_prot
|
||||
};
|
||||
|
||||
/* FIXME: move this data to TaskState? */
|
||||
E2KAauState aau;
|
||||
uint64_t lsr;
|
||||
uint64_t lsr_lcnt;
|
||||
uint32_t ilcr;
|
||||
uint64_t ilcr_lcnt;
|
||||
// FIXME: according to ABI only 16-31 must be saved
|
||||
E2KReg gregs[16];
|
||||
uint8_t gtags[16];
|
||||
};
|
||||
|
||||
#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
|
||||
|
||||
static abi_long setup_sigcontext(CPUE2KState *env,
|
||||
struct target_sigcontext *sc, struct target_extra_ucontext *extra)
|
||||
{
|
||||
E2KCrs crs;
|
||||
int i, ret;
|
||||
|
||||
// TODO: save binary compiler state (uspr, rpr, MLT)
|
||||
__put_user(env->upsr, &sc->upsr);
|
||||
|
||||
ret = e2k_copy_from_user_crs(&crs, env->pcsp.base + env->pcsp.index);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
__put_user(crs.cr0_lo, &sc->cr0_lo);
|
||||
__put_user(crs.cr0_hi, &sc->cr0_hi);
|
||||
__put_user(crs.cr1.lo, &sc->cr1_lo);
|
||||
__put_user(crs.cr1.hi, &sc->cr1_hi);
|
||||
|
||||
__put_user(env->sbr, &sc->sbr);
|
||||
__put_user(env->usd.lo, &sc->usd_lo);
|
||||
__put_user(env->usd.hi, &sc->usd_hi);
|
||||
__put_user(env->psp.lo, &sc->psp_lo);
|
||||
__put_user(env->psp.hi, &sc->psp_hi);
|
||||
__put_user(env->pcsp.lo, &sc->pcsp_lo);
|
||||
__put_user(env->pcsp.hi, &sc->pcsp_hi);
|
||||
|
||||
// TODO: save trap state
|
||||
__put_user(0, &sc->nr_TIRs);
|
||||
__put_user(0, &sc->tir_lo[0]);
|
||||
__put_user(0, &sc->tir_hi[0]);
|
||||
__put_user(-1, &extra->curr_cnt);
|
||||
__put_user(0, &extra->tc_count);
|
||||
|
||||
__put_user(sizeof(struct target_extra_ucontext) - sizeof(abi_int),
|
||||
&extra->sizeof_extra_uc);
|
||||
|
||||
__put_user(env->fpcr.raw, &extra->fpcr);
|
||||
__put_user(env->fpsr.raw, &extra->fpsr);
|
||||
__put_user(env->pfpfr.raw, &extra->pfpfr);
|
||||
|
||||
__put_user(env->ctprs[0].raw, &extra->ctpr1);
|
||||
__put_user(env->ctprs[1].raw, &extra->ctpr2);
|
||||
__put_user(env->ctprs[2].raw, &extra->ctpr3);
|
||||
|
||||
for (i = 0; i < DAM_ENTRIES_NUM; i++) {
|
||||
__put_user(env->dam[i].raw, &sc->dam[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long setup_ucontext(struct target_ucontext *uc, CPUE2KState *env)
|
||||
{
|
||||
__put_user(0, &uc->uc_flags);
|
||||
__put_user(0, &uc->uc_link);
|
||||
|
||||
target_save_altstack(&uc->uc_stack, env);
|
||||
return setup_sigcontext(env, &uc->uc_mcontext, &uc->uc_extra);
|
||||
}
|
||||
|
||||
static abi_ulong get_sigframe(struct target_sigaction *ka, CPUE2KState *env,
|
||||
size_t frame_size)
|
||||
{
|
||||
abi_ulong sp;
|
||||
|
||||
sp = target_sigsp(env->usd.base, ka);
|
||||
sp = (sp - frame_size) & ~15;
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
static void target_setup_frame(int sig, struct target_sigaction *ka,
|
||||
target_siginfo_t *info, target_sigset_t *set, CPUE2KState *env)
|
||||
{
|
||||
abi_ulong frame_addr;
|
||||
struct target_sigframe *frame;
|
||||
|
||||
if (env->is_bp) {
|
||||
/* numas13 FIXME: I am not sure that it is a good solution but
|
||||
* the way we handle breakpoints requires these steps.
|
||||
* Maybe we need to create more fake kernel frames for breakpoints? */
|
||||
e2k_proc_return(env, true);
|
||||
}
|
||||
|
||||
/* save current frame */
|
||||
e2k_proc_call(env, env->wd.size, env->ip, false);
|
||||
|
||||
frame_addr = get_sigframe(ka, env, sizeof(*frame));
|
||||
trace_user_setup_rt_frame(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
|
||||
force_sigsegv(sig);
|
||||
}
|
||||
if (setup_ucontext(&frame->uc, env)) {
|
||||
goto fail;
|
||||
}
|
||||
copy_to_user(frame_addr + offsetof(struct target_sigframe, uc.uc_sigmask),
|
||||
set, sizeof(*set));
|
||||
copy_to_user(frame_addr + offsetof(struct target_sigframe, aau),
|
||||
&env->aau, sizeof(env->aau));
|
||||
__put_user(env_lsr_get(env), &frame->lsr);
|
||||
__put_user(env->lsr_lcnt, &frame->lsr_lcnt);
|
||||
__put_user(env->ilcr, &frame->ilcr);
|
||||
__put_user(env->ilcr_lcnt, &frame->ilcr_lcnt);
|
||||
copy_to_user(frame_addr + offsetof(struct target_sigframe, gregs),
|
||||
&env->regs[E2K_NR_COUNT + 16], 16 * sizeof(E2KReg));
|
||||
copy_to_user(frame_addr + offsetof(struct target_sigframe, gtags),
|
||||
&env->tags[E2K_NR_COUNT + 16], 16);
|
||||
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
// TODO: sa_restorer?
|
||||
qemu_log_mask(LOG_UNIMP, "target_setup_frame sa_restorer +\n");
|
||||
} else {
|
||||
// TODO: ignore?
|
||||
}
|
||||
|
||||
/* fake kernel frame */
|
||||
env->wd.size = 0;
|
||||
env->wd.psize = 0;
|
||||
env->usd.size = env->sbr - frame_addr;
|
||||
env->usd.base = frame_addr;
|
||||
e2k_proc_call(env, 0, E2K_SIGRET_ADDR, false);
|
||||
|
||||
env->ip = ka->_sa_handler;
|
||||
env->regs[0].lo = sig;
|
||||
env->tags[0] = E2K_TAG_NUMBER64;
|
||||
env->wd.size = 8;
|
||||
|
||||
if (info && (ka->sa_flags & TARGET_SA_SIGINFO)) {
|
||||
tswap_siginfo(&frame->info, info);
|
||||
env->regs[1].lo = frame_addr + offsetof(struct target_sigframe, info);
|
||||
env->tags[1] = E2K_TAG_NUMBER64;
|
||||
env->regs[2].lo = frame_addr + offsetof(struct target_sigframe, uc);
|
||||
env->tags[2] = E2K_TAG_NUMBER64;
|
||||
}
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
return;
|
||||
|
||||
fail:
|
||||
unlock_user_struct(frame, frame_addr, 1);
|
||||
force_sigsegv(sig);
|
||||
}
|
||||
|
||||
static abi_long target_restore_sigframe(CPUE2KState *env,
|
||||
struct target_sigframe *frame)
|
||||
{
|
||||
target_ulong crs_addr = env->pcsp.base + env->pcsp.index;
|
||||
E2KCrs crs, *p;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, p, crs_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(crs.cr0_hi, &frame->uc.uc_mcontext.cr0_hi);
|
||||
__put_user(crs.cr0_hi, &p->cr0_hi);
|
||||
unlock_user_struct(p, crs_addr, 1);
|
||||
|
||||
__get_user(env->ctprs[0].raw, &frame->uc.uc_extra.ctpr1);
|
||||
__get_user(env->ctprs[1].raw, &frame->uc.uc_extra.ctpr2);
|
||||
__get_user(env->ctprs[2].raw, &frame->uc.uc_extra.ctpr3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setup_frame(int sig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUE2KState *env)
|
||||
{
|
||||
target_setup_frame(sig, ka, 0, set, env);
|
||||
}
|
||||
|
||||
void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
target_siginfo_t *info, target_sigset_t *set, CPUE2KState *env)
|
||||
{
|
||||
target_setup_frame(sig, ka, info, set, env);
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUE2KState *env)
|
||||
{
|
||||
return do_rt_sigreturn(env);
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUE2KState *env)
|
||||
{
|
||||
abi_ulong frame_addr;
|
||||
struct target_sigframe *frame;
|
||||
sigset_t set;
|
||||
|
||||
/* restore fake kernel frame */
|
||||
e2k_proc_return(env, false);
|
||||
frame_addr = env->usd.base;
|
||||
|
||||
trace_user_do_rt_sigreturn(env, frame_addr);
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset(&set, &frame->uc.uc_sigmask);
|
||||
set_sigmask(&set);
|
||||
|
||||
if (target_restore_sigframe(env, frame)) {
|
||||
goto badframe;
|
||||
}
|
||||
copy_from_user(&env->aau, frame_addr
|
||||
+ offsetof(struct target_sigframe, aau), sizeof(env->aau));
|
||||
__get_user(env->lsr, &frame->lsr);
|
||||
__get_user(env->lsr_lcnt, &frame->lsr_lcnt);
|
||||
__get_user(env->ilcr, &frame->ilcr);
|
||||
__get_user(env->ilcr_lcnt, &frame->ilcr_lcnt);
|
||||
copy_from_user(&env->regs[E2K_NR_COUNT + 16], frame_addr
|
||||
+ offsetof(struct target_sigframe, gregs), 16 * sizeof(E2KReg));
|
||||
copy_from_user(&env->tags[E2K_NR_COUNT + 16], frame_addr
|
||||
+ offsetof(struct target_sigframe, gtags), 16);
|
||||
|
||||
if (do_sigaltstack(frame_addr +
|
||||
offsetof(struct target_sigframe, uc.uc_stack),
|
||||
0, env) == -EFAULT)
|
||||
{
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
/* restore user */
|
||||
e2k_proc_return(env, false);
|
||||
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
return -QEMU_ESIGRETURN;
|
||||
|
||||
badframe:
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
return -QEMU_ESIGRETURN;
|
||||
}
|
||||
|
||||
abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
|
||||
abi_ulong unew_ctx, abi_long ctx_size)
|
||||
{
|
||||
// TODO: do_swapcontext
|
||||
qemu_log_mask(LOG_UNIMP, "do_swapcontext: not implemented\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include "../generic/sockbits.h"
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
#ifndef E2K_SYSCALL_NR_H
|
||||
#define E2K_SYSCALL_NR_H
|
||||
|
||||
#define TARGET_NR_restart_syscall 0
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread64 180
|
||||
#define TARGET_NR_pwrite64 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#define TARGET_NR_fcntl64 221
|
||||
#define TARGET_NR_core 222 /* for analys kernel core */
|
||||
#define TARGET_NR_macctl 223 /* MCST trust linux */
|
||||
#define TARGET_NR_newfstatat 224
|
||||
#define TARGET_NR_emergency 225
|
||||
#define TARGET_NR_e2k_sigsetjmp 226 /* setjmp e2k specific */
|
||||
#define TARGET_NR_e2k_longjmp 227 /* longjmp e2k specific */
|
||||
#define TARGET_NR_e2k_syswork 228 /* e2k_syswork */
|
||||
#define TARGET_NR_clone2 229
|
||||
#define TARGET_NR_e2k_longjmp2 230 /* Second Edition */
|
||||
#define TARGET_NR_soft_debug 231
|
||||
#define TARGET_NR_setxattr 232
|
||||
#define TARGET_NR_lsetxattr 233
|
||||
#define TARGET_NR_fsetxattr 234
|
||||
#define TARGET_NR_getxattr 235
|
||||
#define TARGET_NR_lgetxattr 236
|
||||
#define TARGET_NR_fgetxattr 237
|
||||
#define TARGET_NR_listxattr 238
|
||||
#define TARGET_NR_llistxattr 239
|
||||
#define TARGET_NR_flistxattr 240
|
||||
#define TARGET_NR_removexattr 241
|
||||
#define TARGET_NR_lremovexattr 242
|
||||
#define TARGET_NR_fremovexattr 243
|
||||
#define TARGET_NR_gettid 244
|
||||
#define TARGET_NR_readahead 245
|
||||
#define TARGET_NR_tkill 246
|
||||
#define TARGET_NR_sendfile64 247
|
||||
#define TARGET_NR_futex 248
|
||||
#define TARGET_NR_sched_setaffinity 249
|
||||
#define TARGET_NR_sched_getaffinity 250
|
||||
#define TARGET_NR_pipe2 251
|
||||
#define TARGET_NR_set_backtrace 252
|
||||
#define TARGET_NR_get_backtrace 253
|
||||
#define TARGET_NR_access_hw_stacks 254
|
||||
#define TARGET_NR_el_posix 255
|
||||
/*
|
||||
* reserved for update of kernel source codes
|
||||
*/
|
||||
#define TARGET_NR_reserved6 256
|
||||
#define TARGET_NR_reserved7 257
|
||||
#define TARGET_NR_reserved8 258
|
||||
|
||||
#define TARGET_NR_set_tid_address 259
|
||||
#define TARGET_NR_el_binary 260
|
||||
#define TARGET_NR_timer_create 261
|
||||
#define TARGET_NR_timer_settime 262
|
||||
#define TARGET_NR_timer_gettime 263
|
||||
#define TARGET_NR_timer_getoverrun 264
|
||||
#define TARGET_NR_timer_delete 265
|
||||
#define TARGET_NR_clock_settime 266
|
||||
#define TARGET_NR_clock_gettime 267
|
||||
#define TARGET_NR_clock_getres 268
|
||||
#define TARGET_NR_clock_nanosleep 269
|
||||
/*
|
||||
* reserved for update of kernel source codes
|
||||
*/
|
||||
#define TARGET_NR_reserved9 270
|
||||
#define TARGET_NR_reserved10 271
|
||||
#define TARGET_NR_reserved11 272
|
||||
#define TARGET_NR_reserved12 273
|
||||
#define TARGET_NR_reserved13 274
|
||||
#define TARGET_NR_reserved14 275
|
||||
#define TARGET_NR_reserved15 276
|
||||
#define TARGET_NR_reserved16 277
|
||||
#define TARGET_NR_reserved17 278
|
||||
#define TARGET_NR_reserved18 279
|
||||
#define TARGET_NR_reserved19 280
|
||||
#define TARGET_NR_reserved20 281
|
||||
#define TARGET_NR_reserved21 282
|
||||
#define TARGET_NR_reserved22 283
|
||||
#define TARGET_NR_reserved23 284
|
||||
#define TARGET_NR_reserved24 285
|
||||
#define TARGET_NR_reserved25 286
|
||||
|
||||
#define TARGET_NR_sched_setattr 287
|
||||
#define TARGET_NR_sched_getattr 288
|
||||
|
||||
#define TARGET_NR_ioprio_set 289
|
||||
#define TARGET_NR_ioprio_get 290
|
||||
#define TARGET_NR_inotify_init 291
|
||||
#define TARGET_NR_inotify_add_watch 292
|
||||
#define TARGET_NR_inotify_rm_watch 293
|
||||
|
||||
#define TARGET_NR_io_setup 294
|
||||
#define TARGET_NR_io_destroy 295
|
||||
#define TARGET_NR_io_getevents 296
|
||||
#define TARGET_NR_io_submit 297
|
||||
#define TARGET_NR_io_cancel 298
|
||||
#define TARGET_NR_fadvise64 299
|
||||
|
||||
#define TARGET_NR_exit_group 300
|
||||
#define TARGET_NR_lookup_dcookie 301
|
||||
#define TARGET_NR_epoll_create 302
|
||||
#define TARGET_NR_epoll_ctl 303
|
||||
#define TARGET_NR_epoll_wait 304
|
||||
#define TARGET_NR_remap_file_pages 305
|
||||
#define TARGET_NR_statfs64 306
|
||||
#define TARGET_NR_fstatfs64 307
|
||||
#define TARGET_NR_tgkill 308
|
||||
#define TARGET_NR_utimes 309
|
||||
#define TARGET_NR_fadvise64_64 310
|
||||
#define TARGET_NR_vserver 311
|
||||
#define TARGET_NR_mbind 312
|
||||
#define TARGET_NR_get_mempolicy 313
|
||||
#define TARGET_NR_set_mempolicy 314
|
||||
#define TARGET_NR_mq_open 315
|
||||
#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1)
|
||||
#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2)
|
||||
#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3)
|
||||
#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4)
|
||||
#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5)
|
||||
#define TARGET_NR_kexec_load 321
|
||||
#define TARGET_NR_waitid 322
|
||||
#define TARGET_NR_add_key 323
|
||||
#define TARGET_NR_request_key 324
|
||||
#define TARGET_NR_keyctl 325
|
||||
#define TARGET_NR_mcst_rt 326
|
||||
#define TARGET_NR_getcpu 327
|
||||
#define TARGET_NR_move_pages 328
|
||||
#define TARGET_NR_splice 329
|
||||
#define TARGET_NR_vmsplice 330
|
||||
#define TARGET_NR_tee 331
|
||||
#define TARGET_NR_migrate_pages 332
|
||||
#define TARGET_NR_utimensat 333
|
||||
#define TARGET_NR_rt_tgsigqueueinfo 334
|
||||
#define TARGET_NR_openat 335
|
||||
#define TARGET_NR_mkdirat 336
|
||||
#define TARGET_NR_mknodat 337
|
||||
#define TARGET_NR_fchownat 338
|
||||
#define TARGET_NR_unlinkat 339
|
||||
#define TARGET_NR_renameat 340
|
||||
#define TARGET_NR_linkat 341
|
||||
#define TARGET_NR_symlinkat 342
|
||||
#define TARGET_NR_readlinkat 343
|
||||
#define TARGET_NR_fchmodat 344
|
||||
#define TARGET_NR_faccessat 345
|
||||
#define TARGET_NR_epoll_pwait 346
|
||||
#define TARGET_NR_signalfd4 347
|
||||
#define TARGET_NR_eventfd2 348
|
||||
#define TARGET_NR_recvmmsg 349
|
||||
#define TARGET_NR_cnt_point 350
|
||||
#define TARGET_NR_timerfd_create 351
|
||||
#define TARGET_NR_timerfd_settime 352
|
||||
#define TARGET_NR_timerfd_gettime 353
|
||||
#define TARGET_NR_preadv 354
|
||||
#define TARGET_NR_pwritev 355
|
||||
#define TARGET_NR_fallocate 356
|
||||
#define TARGET_NR_sync_file_range 357
|
||||
#define TARGET_NR_dup3 358
|
||||
#define TARGET_NR_inotify_init1 359
|
||||
#define TARGET_NR_epoll_create1 360
|
||||
#define TARGET_NR_fstatat64 361
|
||||
#define TARGET_NR_futimesat 362
|
||||
#define TARGET_NR_perf_event_open 363
|
||||
#define TARGET_NR_unshare 364
|
||||
#define TARGET_NR_get_robust_list 365
|
||||
#define TARGET_NR_set_robust_list 366
|
||||
#define TARGET_NR_pselect6 367
|
||||
#define TARGET_NR_ppoll 368
|
||||
#define TARGET_NR_setcontext 369
|
||||
#define TARGET_NR_makecontext 370
|
||||
#define TARGET_NR_swapcontext 371
|
||||
#define TARGET_NR_freecontext 372
|
||||
#define TARGET_NR_fanotify_init 373
|
||||
#define TARGET_NR_fanotify_mark 374
|
||||
#define TARGET_NR_prlimit64 375
|
||||
#define TARGET_NR_clock_adjtime 376
|
||||
#define TARGET_NR_syncfs 377
|
||||
#define TARGET_NR_sendmmsg 378
|
||||
#define TARGET_NR_setns 379
|
||||
#define TARGET_NR_process_vm_readv 380
|
||||
#define TARGET_NR_process_vm_writev 381
|
||||
#define TARGET_NR_kcmp 382
|
||||
#define TARGET_NR_finit_module 383
|
||||
#define TARGET_NR_renameat2 384
|
||||
#define TARGET_NR_getrandom 385
|
||||
#define TARGET_NR_memfd_create 386
|
||||
#define TARGET_NR_bpf 387
|
||||
#define TARGET_NR_execveat 388
|
||||
#define TARGET_NR_userfaultfd 389
|
||||
#define TARGET_NR_membarrier 390
|
||||
#define TARGET_NR_mlock2 391
|
||||
#define TARGET_NR_seccomp 392
|
||||
#define TARGET_NR_shutdown 393
|
||||
#define TARGET_NR_copy_file_range 394
|
||||
#define TARGET_NR_preadv2 395
|
||||
#define TARGET_NR_pwritev2 396
|
||||
#define TARGET_NR_pkey_mprotect 397
|
||||
#define TARGET_NR_pkey_alloc 398
|
||||
#define TARGET_NR_pkey_free 399
|
||||
#define TARGET_NR_name_to_handle_at 400
|
||||
#define TARGET_NR_open_by_handle_at 401
|
||||
#define TARGET_NR_statx 402
|
||||
/* added for compatibility with x86_64 */
|
||||
#define TARGET_NR_socket 403
|
||||
#define TARGET_NR_connect 404
|
||||
#define TARGET_NR_accept 405
|
||||
#define TARGET_NR_sendto 406
|
||||
#define TARGET_NR_recvfrom 407
|
||||
#define TARGET_NR_sendmsg 408
|
||||
#define TARGET_NR_recvmsg 409
|
||||
#define TARGET_NR_bind 410
|
||||
#define TARGET_NR_listen 411
|
||||
#define TARGET_NR_getsockname 412
|
||||
#define TARGET_NR_getpeername 413
|
||||
#define TARGET_NR_socketpair 414
|
||||
#define TARGET_NR_setsockopt 415
|
||||
#define TARGET_NR_getsockopt 416
|
||||
/* free (unused) entries - reserve 417 - 418 */
|
||||
/* TODO: #define TARGET_NR_arch_prctl 419 */
|
||||
/* added for combability of protected system calls v1-v5 & v6 */
|
||||
#define TARGET_NR_newuselib 420
|
||||
#define TARGET_NR_rt_sigaction_ex 421
|
||||
/* protected Mode specific memory allocation syscall number */
|
||||
#define TARGET_NR_get_mem 422
|
||||
#define TARGET_NR_free_mem 423
|
||||
/* protected mode specific clean memory from old invalid descriptors */
|
||||
#define TARGET_NR_clean_descriptors 424
|
||||
/* protected mode specific unloading module from memory */
|
||||
#define TARGET_NR_unuselib 425
|
||||
#define TARGET_NR_clone3 426
|
||||
#define TARGET_NR_fsopen 427
|
||||
#define TARGET_NR_fsconfig 428
|
||||
#define TARGET_NR_fsmount 429
|
||||
#define TARGET_NR_fspick 430
|
||||
|
||||
#define TARGET_syscalls 431
|
||||
|
||||
#endif /* E2K_SYSCALL_NR_H */
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef E2K_TARGET_CPU_H
|
||||
#define E2K_TARGET_CPU_H
|
||||
|
||||
#include "qemu/log.h"
|
||||
|
||||
abi_long e2k_copy_from_user_crs(E2KCrs *crs, abi_ulong target_crs_addr);
|
||||
abi_long e2k_copy_to_user_crs(abi_ulong target_crs_addr, E2KCrs *crs);
|
||||
|
||||
static inline void cpu_clone_regs_child(CPUE2KState *env, target_ulong newsp,
|
||||
unsigned flags)
|
||||
{
|
||||
if (newsp) {
|
||||
// FIXME: what size must be?
|
||||
env->usd.size = 0x20000;
|
||||
env->usd.base = env->sbr = newsp & ~0xf;
|
||||
env->usd.read = 1;
|
||||
env->usd.write = 1;
|
||||
}
|
||||
|
||||
if (flags & CLONE_VM) {
|
||||
E2KPsp pcs = { 0 };
|
||||
E2KPsp ps = { 0 };
|
||||
E2KCrs crs = { 0 };
|
||||
uint64_t *ps_old, *ps_new;
|
||||
size_t frame_size;
|
||||
target_ulong pcsp = env->pcsp.base + env->pcsp.index;
|
||||
target_ulong ps_base = env->psp.base + env->psp.index;
|
||||
int i;
|
||||
|
||||
e2k_psp_new(&pcs, E2K_DEFAULT_PCS_SIZE, false);
|
||||
e2k_psp_new(&ps, E2K_DEFAULT_PS_SIZE, true);
|
||||
|
||||
// TODO: size checks and a way to report errors
|
||||
// TODO: set a chain info to return to kernel
|
||||
|
||||
pcs.index += sizeof(E2KCrs);
|
||||
if (e2k_copy_from_user_crs(&crs, pcsp)
|
||||
|| e2k_copy_to_user_crs(pcs.base + pcs.index, &crs))
|
||||
{
|
||||
qemu_log("qemu-e2k internal error: failed to copy parent frame\n");
|
||||
env->ip = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
frame_size = crs.cr1.wbs * (crs.cr1.wfx || E2K_FORCE_FX ? 32 : 16);
|
||||
ps_base -= frame_size;
|
||||
ps.index += frame_size;
|
||||
ps_old = lock_user(VERIFY_READ, ps_base, frame_size, 1);
|
||||
ps_new = lock_user(VERIFY_WRITE, ps.base, frame_size, 0);
|
||||
|
||||
for (i = 0; i < frame_size / 8; i++) {
|
||||
uint64_t tmp;
|
||||
__get_user(tmp, &ps_old[i]);
|
||||
__put_user(tmp, &ps_new[i]);
|
||||
}
|
||||
|
||||
unlock_user_struct(ps_new, ps.base, 1);
|
||||
unlock_user_struct(ps_old, ps_base, 0);
|
||||
|
||||
env->ip = E2K_SYSRET_ADDR;
|
||||
env->pcsp = pcs;
|
||||
env->psp = ps;
|
||||
env->regs[0].lo = 0;
|
||||
env->tags[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_clone_regs_parent(CPUE2KState *env, unsigned flags)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void cpu_set_tls(CPUE2KState *env, target_ulong newtls)
|
||||
{
|
||||
env->regs[E2K_TLS_REG].lo = newtls;
|
||||
}
|
||||
|
||||
static inline target_ulong cpu_get_tls(CPUE2KState *env)
|
||||
{
|
||||
return env->regs[E2K_TLS_REG].lo;
|
||||
}
|
||||
|
||||
static inline abi_ulong get_sp_from_cpustate(CPUE2KState *env)
|
||||
{
|
||||
return env->usd.base;
|
||||
}
|
||||
|
||||
#endif /* E2K_TARGET_CPU_H */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef E2K_TARGET_ELF_H
|
||||
#define E2K_TARGET_ELF_H
|
||||
|
||||
#define E2K_ELF_IPD_MASK ((1U << 1)|(1U << 0))
|
||||
#define E2K_ELF_X86APP (1U << 2)
|
||||
#define E2K_ELF_4MB_PAGES (1U << 3)
|
||||
#define E2K_ELF_INCOMPAT (1U << 4)
|
||||
#define E2K_ELF_PM (1U << 5)
|
||||
|
||||
#define E2K_ELF_OLD_MACH(x) (((x) >> 28) & 7)
|
||||
#define E2K_ELF_MACH(x) (((x) >> 24) & 255)
|
||||
|
||||
#define E2K_MACH_BASE 0
|
||||
#define E2K_MACH_EV1 1
|
||||
#define E2K_MACH_EV2 2
|
||||
#define E2K_MACH_EV3 3
|
||||
#define E2K_MACH_EV4 4
|
||||
#define E2K_MACH_EV5 5
|
||||
#define E2K_MACH_EV6 6
|
||||
|
||||
/* elbrus-v4 based processors */
|
||||
#define E2K_MACH_8C 19
|
||||
#define E2K_MACH_1CPLUS 20
|
||||
|
||||
const char *cpu_get_model(uint32_t eflags);
|
||||
|
||||
#endif /* E2K_TARGET_ELF_H */
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef E2K_TARGET_ERRNO_DEFS_H
|
||||
#define E2K_TARGET_ERRNO_DEFS_H
|
||||
|
||||
/* Target uses generic errno */
|
||||
#include "../generic/target_errno_defs.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef E2K_TARGET_FCNTL_H
|
||||
#define E2K_TARGET_FCNTL_H
|
||||
#include "../generic/fcntl.h"
|
||||
#endif
|
|
@ -0,0 +1 @@
|
|||
/* TODO */
|
|
@ -0,0 +1 @@
|
|||
#include "../generic/target_resource.h"
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef TARGET_SIGNAL_H
|
||||
#define TARGET_SIGNAL_H
|
||||
|
||||
/*
|
||||
* sigaltstack controls
|
||||
*/
|
||||
#define TARGET_SS_ONSTACK 1
|
||||
#define TARGET_SS_DISABLE 2
|
||||
|
||||
#define TARGET_MINSIGSTKSZ 4096
|
||||
#define TARGET_SIGSTKSZ 8192
|
||||
#define TARGET_MCL_CURRENT 1
|
||||
#define TARGET_MCL_FUTURE 2
|
||||
#define TARGET_MCL_ONFAULT 4
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
|
||||
|
||||
#include "generic/signal.h"
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef E2K_TARGET_STRUCTS_H
|
||||
#define E2K_TARGET_STRUCTS_H
|
||||
|
||||
struct target_ipc_perm {
|
||||
abi_int __key;
|
||||
abi_uint uid;
|
||||
abi_uint gid;
|
||||
abi_uint cuid;
|
||||
abi_uint cgid;
|
||||
abi_uint mode;
|
||||
abi_ushort __seq;
|
||||
};
|
||||
|
||||
struct target_shmid_ds {
|
||||
struct target_ipc_perm shm_perm;
|
||||
abi_int shm_segsz;
|
||||
abi_long shm_atime;
|
||||
abi_long shm_dtime;
|
||||
abi_long shm_ctime;
|
||||
abi_int shm_cpid;
|
||||
abi_int shm_lpid;
|
||||
abi_ushort shm_nattch;
|
||||
abi_ushort shm_unused;
|
||||
void *shm_unused2;
|
||||
void *shm_unused3;
|
||||
};
|
||||
|
||||
struct target_jmp_info {
|
||||
abi_ullong sigmask;
|
||||
abi_ullong cr0hi;
|
||||
abi_ullong cr1lo;
|
||||
abi_ullong pcsplo;
|
||||
abi_ullong pcsphi;
|
||||
abi_uint pcshtp;
|
||||
abi_uint br;
|
||||
abi_ullong usdlo;
|
||||
abi_ullong wd;
|
||||
abi_ullong reserv1;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef E2K_TARGET_SYSCALL_H
|
||||
#define E2K_TARGET_SYSCALL_H
|
||||
|
||||
#define UNAME_MACHINE "e2k"
|
||||
#define UNAME_MINIMUM_RELEASE "2.6.32"
|
||||
|
||||
#define E2K_MAXNR 128 /* The total number of */
|
||||
/* quad-NRs */
|
||||
#define E2K_MAXGR 16 /* The total number of global */
|
||||
/* quad-NRs */
|
||||
#define E2K_MAXSR (E2K_MAXNR - E2K_MAXGR) /* The total number of stack */
|
||||
/* quad-NRs */
|
||||
#define E2K_MAXNR_d (E2K_MAXNR * 2) /* The total number of */
|
||||
/* double-NRs */
|
||||
#define E2K_MAXGR_d (E2K_MAXGR * 2) /* The total number of global */
|
||||
/* double-NRs */
|
||||
#define E2K_MAXSR_d (E2K_MAXSR * 2) /* The total number of stack */
|
||||
/* double-NRs */
|
||||
|
||||
#define E2K_DEFAULT_PCS_SIZE (TARGET_PAGE_SIZE)
|
||||
#define E2K_DEFAULT_PS_SIZE (TARGET_PAGE_SIZE * 4)
|
||||
|
||||
typedef uint64_t e2k_greg_t; // double word
|
||||
|
||||
struct target_pt_regs {
|
||||
/* special registers */
|
||||
uint64_t wd; // Current window descriptor (WD)
|
||||
|
||||
uint64_t sbr; // User Stack Base Register (USBR/SBR)
|
||||
// SBR - contains the base (top) virtual address of the current User Stack area.
|
||||
|
||||
// uint64_t tr; // current type register
|
||||
|
||||
E2KPsp pcsp;
|
||||
E2KPsp psp;
|
||||
|
||||
uint32_t psr; // Processor State Register (PSR)
|
||||
uint32_t upsr; // User processor status register (UPSR)
|
||||
uint64_t ip; // instruction pointer
|
||||
uint64_t nip; // next instruction pointer
|
||||
|
||||
uint64_t ctpr1; // Control Transfer Preparation Register (CTPR)
|
||||
uint64_t ctpr2;
|
||||
uint64_t ctpr3;
|
||||
|
||||
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
|
||||
uint32_t fpcr; // Floating point control register (FPCR)
|
||||
uint32_t fpsr; // Floating point state register (FPSR)
|
||||
|
||||
// borrowed from Embox OS
|
||||
uint64_t lsr; // Loop status register (LSR)
|
||||
uint64_t ilcr; // Loop counter register (ILCR)
|
||||
|
||||
uint64_t dr0;
|
||||
|
||||
uint64_t cr0_hi;
|
||||
uint64_t cr1_lo;
|
||||
uint64_t cr1_hi;
|
||||
uint64_t pcsp_hi;
|
||||
uint64_t pcsp_lo;
|
||||
uint64_t usd_lo; // User data
|
||||
uint64_t usd_hi;
|
||||
|
||||
uint64_t gbase[32];
|
||||
uint16_t gext[32];
|
||||
};
|
||||
|
||||
// FIXME: Is it right place for these constants?
|
||||
#if TARGET_LONG_BITS == 64
|
||||
#define TARGET_PAGE_OFFSET 0x0000d00000000000UL
|
||||
#define TARGET_TASK_SIZE TARGET_PAGE_OFFSET
|
||||
#else
|
||||
#define TARGET_TASK_SIZE 0xe0000000UL
|
||||
#endif
|
||||
|
||||
/* modes for sys_access_hw_stacks */
|
||||
enum {
|
||||
READ_CHAIN_STACK,
|
||||
READ_PROCEDURE_STACK,
|
||||
WRITE_PROCEDURE_STACK,
|
||||
GET_CHAIN_STACK_OFFSET,
|
||||
GET_CHAIN_STACK_SIZE,
|
||||
GET_PROCEDURE_STACK_SIZE,
|
||||
READ_CHAIN_STACK_EX,
|
||||
READ_PROCEDURE_STACK_EX,
|
||||
WRITE_PROCEDURE_STACK_EX,
|
||||
WRITE_CHAIN_STACK_EX,
|
||||
};
|
||||
|
||||
#endif /* E2K_TARGET_SYSCALL_H */
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _E2K_TERMBITS_H_
|
||||
#define _E2K_TERMBITS_H_
|
||||
|
||||
#include "../generic/termbits.h"
|
||||
|
||||
#endif /* _E2K_TERMBITS_H_ */
|
|
@ -1603,6 +1603,73 @@ static inline void init_thread(struct target_pt_regs *regs,
|
|||
|
||||
#endif /* TARGET_HEXAGON */
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
|
||||
#define elf_check_arch(x) ((x) == EM_MCST_ELBRUS || (x) == EM_E2K_OLD)
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_ARCH EM_MCST_ELBRUS
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
#define ELF_NREG 256
|
||||
typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
||||
#define USE_ELF_CORE_DUMP
|
||||
|
||||
static abi_ulong e2k_mmap(abi_ulong size)
|
||||
{
|
||||
abi_ulong addr;
|
||||
abi_ulong guard = TARGET_PAGE_SIZE;
|
||||
|
||||
if (size < TARGET_PAGE_SIZE) {
|
||||
size = TARGET_PAGE_SIZE;
|
||||
}
|
||||
if (guard < qemu_real_host_page_size()) {
|
||||
guard = qemu_real_host_page_size();
|
||||
}
|
||||
|
||||
addr = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (addr == -1) {
|
||||
perror("mmap e2k stack");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
target_mprotect(addr + size, guard, PROT_NONE);
|
||||
return addr;
|
||||
}
|
||||
|
||||
void e2k_psp_new(E2KPsp *psp, unsigned int size, bool tags)
|
||||
{
|
||||
psp->is_readable = true;
|
||||
psp->is_writable = true;
|
||||
psp->index = 0;
|
||||
psp->size = size;
|
||||
psp->base = e2k_mmap(size);
|
||||
psp->base_tag = tags ? e2k_mmap(size / 8) : 0;
|
||||
}
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
abi_ulong start_stack = infop->start_stack & ~0xf;
|
||||
|
||||
regs->ip = infop->entry;
|
||||
|
||||
// FIXME: set real start stack address
|
||||
regs->sbr = infop->arg_strings & ~0xf;
|
||||
regs->usd_lo = (0x1800UL << 48) | start_stack;
|
||||
regs->usd_hi = (regs->sbr - start_stack) << 32;
|
||||
|
||||
e2k_psp_new(®s->pcsp, E2K_DEFAULT_PCS_SIZE, false);
|
||||
e2k_psp_new(®s->psp, E2K_DEFAULT_PS_SIZE, true);
|
||||
}
|
||||
|
||||
static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUE2KState *env)
|
||||
{
|
||||
/* TODO */
|
||||
qemu_log_mask(LOG_UNIMP, "elf_core_copy_regs: not implemented\n");
|
||||
}
|
||||
|
||||
#endif /* TARGET_E2K */
|
||||
|
||||
#ifndef ELF_PLATFORM
|
||||
#define ELF_PLATFORM (NULL)
|
||||
#endif
|
||||
|
|
|
@ -68,7 +68,9 @@ typedef struct target_sigaltstack {
|
|||
#define TARGET_SS_ONSTACK 1
|
||||
#define TARGET_SS_DISABLE 2
|
||||
|
||||
#ifndef TARGET_MINSIGSTKSZ
|
||||
#define TARGET_MINSIGSTKSZ 2048
|
||||
#endif
|
||||
|
||||
/* bit-flags */
|
||||
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
|
||||
|
|
|
@ -1414,6 +1414,22 @@ UNUSED static struct enums itimer_types[] = {
|
|||
ENUM_END,
|
||||
};
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
UNUSED static struct enums access_hw_stacks_reqs[] = {
|
||||
ENUM_GENERIC(READ_CHAIN_STACK),
|
||||
ENUM_GENERIC(READ_PROCEDURE_STACK),
|
||||
ENUM_GENERIC(WRITE_PROCEDURE_STACK),
|
||||
ENUM_GENERIC(GET_CHAIN_STACK_OFFSET),
|
||||
ENUM_GENERIC(GET_CHAIN_STACK_SIZE),
|
||||
ENUM_GENERIC(GET_PROCEDURE_STACK_SIZE),
|
||||
ENUM_GENERIC(READ_CHAIN_STACK_EX),
|
||||
ENUM_GENERIC(READ_PROCEDURE_STACK_EX),
|
||||
ENUM_GENERIC(WRITE_PROCEDURE_STACK_EX),
|
||||
ENUM_GENERIC(WRITE_CHAIN_STACK_EX),
|
||||
ENUM_END,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* print_xxx utility functions. These are used to print syscall
|
||||
* parameters in certain format. All of these have parameter
|
||||
|
@ -3761,6 +3777,22 @@ print_ioctl(CPUArchState *cpu_env, const struct syscallname *name,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_NR_access_hw_stacks
|
||||
static void
|
||||
print_access_hw_stacks(CPUArchState *cpu_env, const struct syscallname *name,
|
||||
abi_long arg0, abi_long arg1, abi_long arg2,
|
||||
abi_long arg3, abi_long arg4, abi_long arg5)
|
||||
{
|
||||
print_syscall_prologue(name);
|
||||
print_enums(access_hw_stacks_reqs, arg0, 0);
|
||||
print_pointer(arg1, 0);
|
||||
print_pointer(arg2, 0);
|
||||
print_raw_param("%d", arg3, 0);
|
||||
print_pointer(arg4, 1);
|
||||
print_syscall_epilogue(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* An array of all of the syscalls we know about
|
||||
*/
|
||||
|
|
|
@ -126,6 +126,19 @@
|
|||
#ifdef TARGET_NR_dup3
|
||||
{ TARGET_NR_dup3, "dup3" , "%s(%d,%d,%d)", NULL, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_e2k_longjmp2
|
||||
{ TARGET_NR_e2k_longjmp2, "e2k_longjmp2", "%s(%p, %d)", NULL, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_access_hw_stacks
|
||||
{ TARGET_NR_access_hw_stacks, "access_hw_stacks", NULL,
|
||||
print_access_hw_stacks, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_set_backtrace
|
||||
{ TARGET_NR_set_backtrace, "set_backtrace", "%s(%p,%lu,%lu,%lu)", NULL, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_get_backtrace
|
||||
{ TARGET_NR_get_backtrace, "get_backtrace", "%s(%p,%lu,%lu,%lu)", NULL, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_epoll_create
|
||||
{ TARGET_NR_epoll_create, "epoll_create", "%s(%d)", NULL, NULL },
|
||||
#endif
|
||||
|
|
|
@ -6987,6 +6987,526 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
static inline abi_long copy_from_user_jmp_info(struct target_jmp_info *ji,
|
||||
abi_ulong target_jmp_info_addr)
|
||||
{
|
||||
struct target_jmp_info *target_ji;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_ji, target_jmp_info_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(ji->sigmask, &target_ji->sigmask);
|
||||
__get_user(ji->cr0hi, &target_ji->cr0hi);
|
||||
__get_user(ji->cr1lo, &target_ji->cr1lo);
|
||||
__get_user(ji->pcsplo, &target_ji->pcsplo);
|
||||
__get_user(ji->pcsphi, &target_ji->pcsphi);
|
||||
__get_user(ji->pcshtp, &target_ji->pcshtp);
|
||||
__get_user(ji->br, &target_ji->br);
|
||||
__get_user(ji->usdlo, &target_ji->usdlo);
|
||||
__get_user(ji->wd, &target_ji->wd);
|
||||
__get_user(ji->reserv1, &target_ji->reserv1);
|
||||
unlock_user_struct(target_ji, target_jmp_info_addr, 0);
|
||||
if (ji->cr0hi > TARGET_TASK_SIZE) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long e2k_copy_from_user_crs(E2KCrs *crs, abi_ulong target_crs_addr)
|
||||
{
|
||||
E2KCrs *target_crs;
|
||||
|
||||
if (!lock_user_struct(VERIFY_READ, target_crs, target_crs_addr, 1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__get_user(crs->cr0_lo, &target_crs->cr0_lo);
|
||||
__get_user(crs->cr0_hi, &target_crs->cr0_hi);
|
||||
__get_user(crs->cr1.lo, &target_crs->cr1.lo);
|
||||
__get_user(crs->cr1.hi, &target_crs->cr1.hi);
|
||||
unlock_user_struct(target_crs, target_crs_addr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abi_long e2k_copy_to_user_crs(abi_ulong target_crs_addr, E2KCrs *crs)
|
||||
{
|
||||
E2KCrs *target_crs;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_crs, target_crs_addr, 0)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
__put_user(crs->cr0_lo, &target_crs->cr0_lo);
|
||||
__put_user(crs->cr0_hi, &target_crs->cr0_hi);
|
||||
__put_user(crs->cr1.lo, &target_crs->cr1.lo);
|
||||
__put_user(crs->cr1.hi, &target_crs->cr1.hi);
|
||||
unlock_user_struct(target_crs, target_crs_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long do_e2k_longjmp2(CPUE2KState *env, struct target_jmp_info *jmp_info)
|
||||
{
|
||||
E2KPsp jmp_pcsp;
|
||||
E2KCrs crs;
|
||||
int level; /* how many CRs need to restore */
|
||||
int ps_index = env->psp.index;
|
||||
int psize = env->wd.psize;
|
||||
int ret, i;
|
||||
target_ulong pcsp = env->pcsp.base + env->pcsp.index;
|
||||
|
||||
jmp_pcsp.lo = jmp_info->pcsplo;
|
||||
jmp_pcsp.hi = jmp_info->pcsphi;
|
||||
|
||||
level = (env->pcsp.index - jmp_pcsp.index) / CRS_SIZE;
|
||||
for (i = 0; i < level; i++) {
|
||||
ret = e2k_copy_from_user_crs(&crs, pcsp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
psize = crs.cr1.wpsz * 2;
|
||||
ps_index -= crs.cr1.wbs * E2K_REG_LEN *
|
||||
(crs.cr1.wfx || E2K_FORCE_FX ? 4 : 2);
|
||||
pcsp -= CRS_SIZE;
|
||||
}
|
||||
|
||||
ret = e2k_copy_from_user_crs(&crs, pcsp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
crs.cr0_hi = jmp_info->cr0hi;
|
||||
crs.cr1.lo = jmp_info->cr1lo;
|
||||
crs.cr1.br = jmp_info->br;
|
||||
crs.cr1.ussz = (env->sbr - extract64(jmp_info->usdlo, 0, 48)) >> 4;
|
||||
|
||||
ret = e2k_copy_to_user_crs(pcsp, &crs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
env->pcsp.index = pcsp - env->pcsp.base;
|
||||
env->psp.index = ps_index;
|
||||
env->wd.psize = psize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static abi_long copy_current_chain_stack(abi_ulong dst, abi_ulong src,
|
||||
abi_ulong size)
|
||||
{
|
||||
E2KCrs *from, *to;
|
||||
abi_long ret = 0;
|
||||
int i;
|
||||
|
||||
if (!QEMU_IS_ALIGNED(src, sizeof(*from)) ||
|
||||
!QEMU_IS_ALIGNED(size, sizeof(*from)))
|
||||
{
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
from = lock_user(VERIFY_READ, src, size, 1);
|
||||
to = lock_user(VERIFY_WRITE, dst, size, 0);
|
||||
if (!to || !from) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += sizeof(E2KCrs), to++, from++) {
|
||||
E2KCrs crs = *from;
|
||||
target_ulong ip;
|
||||
|
||||
memset(to, 0, sizeof(*to));
|
||||
|
||||
to->cr0_lo = from->cr0_lo;
|
||||
ip = crs.cr0_hi & ~7;
|
||||
if (ip < TARGET_TASK_SIZE) {
|
||||
to->cr0_hi = ip;
|
||||
to->cr1.ussz = from->cr1.ussz;
|
||||
}
|
||||
// FIXME: check what exactly needs to be copied
|
||||
to->cr1 = from->cr1;
|
||||
}
|
||||
|
||||
exit:
|
||||
unlock_user(from, src, size);
|
||||
unlock_user(to, dst, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static abi_long copy_procedure_stack(CPUE2KState *env, abi_ulong dst,
|
||||
abi_ulong dst_tag, abi_ulong src, abi_ulong size)
|
||||
{
|
||||
abi_ullong *from, *to;
|
||||
uint8_t *to_tag = NULL;
|
||||
abi_long ret = 0;
|
||||
|
||||
from = lock_user(VERIFY_READ, src, size, 1);
|
||||
to = lock_user(VERIFY_WRITE, dst, size, 0);
|
||||
if (!to || !from) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (dst_tag) {
|
||||
to_tag = lock_user(VERIFY_WRITE, dst_tag, size / 8, 0);
|
||||
if (!to_tag) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// TODO: what to do with tags?
|
||||
memset(to_tag, 0, size / 8);
|
||||
}
|
||||
|
||||
/* v5+ has different stack layout and we need to shuffle registers
|
||||
* for backward compatibility. */
|
||||
if (env->version >= 5) {
|
||||
int i, j;
|
||||
bool to_ps = dst >= env->psp.base
|
||||
&& dst < (env->psp.base + env->psp.size);
|
||||
|
||||
i = ((to_ps ? dst : src) - env->psp.base) / sizeof(abi_ullong);
|
||||
|
||||
if (to_ps) {
|
||||
for (j = 0; j < size / sizeof(abi_ullong); j++, i++) {
|
||||
to[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))] = from[j];
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < size / sizeof(abi_ullong); j++, i++) {
|
||||
to[j] = from[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
memcpy(to, from, size);
|
||||
}
|
||||
|
||||
exit:
|
||||
unlock_user(from, src, size);
|
||||
unlock_user(to_tag, dst_tag, size / 8);
|
||||
unlock_user(to, dst, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static abi_long do_e2k_access_hw_stacks(CPUState *cpu, abi_ulong arg2,
|
||||
abi_ulong arg3, abi_ulong arg4, abi_ulong arg5, abi_ulong arg6)
|
||||
{
|
||||
E2KCPU *e2k_cpu = E2K_CPU(cpu);
|
||||
CPUE2KState *env = &e2k_cpu->env;
|
||||
abi_ulong mode = arg2;
|
||||
abi_ulong frame_addr = arg3; // __user (abi_ullong *)
|
||||
abi_ulong buf_addr = arg4; // __user (char *)
|
||||
abi_ulong buf_size = arg5;
|
||||
abi_ulong size_addr = arg6; // __user (void *)
|
||||
int ret = 0;
|
||||
|
||||
switch (mode) {
|
||||
case GET_PROCEDURE_STACK_SIZE:
|
||||
ret = put_user(env->psp.index, size_addr, target_ulong);
|
||||
break;
|
||||
case GET_CHAIN_STACK_SIZE:
|
||||
ret = put_user(env->pcsp.index + sizeof(E2KCrs), size_addr, target_ulong);
|
||||
break;
|
||||
case GET_CHAIN_STACK_OFFSET:
|
||||
{
|
||||
abi_ullong frame, pcs_top;
|
||||
|
||||
ret = get_user(frame, frame_addr, abi_ullong);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
pcs_top = env->pcsp.base + env->pcsp.size;
|
||||
if (env->pcsp.base > frame || pcs_top <= frame) {
|
||||
return -TARGET_ESRCH;
|
||||
}
|
||||
ret = put_user(frame - env->pcsp.base, size_addr, target_ulong);
|
||||
break;
|
||||
}
|
||||
case READ_CHAIN_STACK:
|
||||
{
|
||||
abi_ullong frame, pcs_used_top;
|
||||
abi_ulong used_size;
|
||||
|
||||
ret = get_user(frame, frame_addr, abi_ullong);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
pcs_used_top = env->pcsp.base + env->pcsp.index;
|
||||
if (frame < env->pcsp.base || frame > pcs_used_top) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
used_size = frame - env->pcsp.base;
|
||||
if (size_addr) {
|
||||
ret = put_user(used_size, size_addr, target_ulong);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (used_size > buf_size) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
ret = copy_current_chain_stack(buf_addr, env->pcsp.base,
|
||||
used_size);
|
||||
break;
|
||||
}
|
||||
case READ_CHAIN_STACK_EX:
|
||||
case WRITE_CHAIN_STACK_EX:
|
||||
{
|
||||
abi_ullong frame;
|
||||
abi_ulong dst, src;
|
||||
|
||||
ret = get_user(frame, frame_addr, abi_ullong);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
if ((env->pcsp.index + sizeof(E2KCrs)) < (frame + buf_size)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (mode == READ_CHAIN_STACK_EX) {
|
||||
dst = buf_addr;
|
||||
src = env->pcsp.base + frame;
|
||||
} else {
|
||||
dst = env->pcsp.base + frame;
|
||||
src = buf_addr;
|
||||
}
|
||||
ret = copy_current_chain_stack(dst, src, buf_size);
|
||||
break;
|
||||
}
|
||||
case READ_PROCEDURE_STACK:
|
||||
case WRITE_PROCEDURE_STACK:
|
||||
{
|
||||
abi_ullong offset, ps_used_top;
|
||||
abi_ulong used_size, dst, dst_tag, src;
|
||||
|
||||
ret = get_user(offset, frame_addr, abi_ullong);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
ps_used_top = env->psp.base + env->psp.index;
|
||||
if (offset < env->psp.base || offset > ps_used_top) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
used_size = offset - env->psp.base;
|
||||
if (size_addr) {
|
||||
ret = put_user(used_size, size_addr, target_ulong);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (used_size > buf_size) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
if (mode == READ_PROCEDURE_STACK) {
|
||||
dst = buf_addr;
|
||||
dst_tag = 0;
|
||||
src = env->psp.base;
|
||||
} else {
|
||||
dst = env->psp.base;
|
||||
dst_tag = env->psp.base_tag;
|
||||
src = buf_addr;
|
||||
}
|
||||
ret = copy_procedure_stack(env, dst, dst_tag, src, used_size);
|
||||
break;
|
||||
}
|
||||
case READ_PROCEDURE_STACK_EX:
|
||||
case WRITE_PROCEDURE_STACK_EX:
|
||||
{
|
||||
abi_ullong offset;
|
||||
abi_ulong dst, dst_tag, src;
|
||||
|
||||
ret = get_user(offset, frame_addr, abi_ullong);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
if (env->psp.index < (offset + buf_size)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
if (mode == READ_PROCEDURE_STACK_EX) {
|
||||
dst = buf_addr;
|
||||
dst_tag = 0;
|
||||
src = env->psp.base + offset;
|
||||
} else {
|
||||
dst = env->psp.base + offset;
|
||||
dst_tag = env->psp.base_tag + offset / 8;
|
||||
src = buf_addr;
|
||||
}
|
||||
ret = copy_procedure_stack(env, dst, dst_tag, src, buf_size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool is_privileged_return(target_ulong ip)
|
||||
{
|
||||
return ip == E2K_SYSRET_BACKTRACE_ADDR;
|
||||
}
|
||||
|
||||
static abi_long do_e2k_set_backtrace(CPUState *cpu, abi_ulong buf_addr,
|
||||
abi_ulong count, abi_ulong skip, abi_ulong flags)
|
||||
{
|
||||
E2KCPU *e2k_cpu = E2K_CPU(cpu);
|
||||
CPUE2KState *env = &e2k_cpu->env;
|
||||
E2KCrs *pcs_base, *frame;
|
||||
target_ulong *buf;
|
||||
abi_long ret = 0;
|
||||
int nr_written = 0;
|
||||
uint64_t cr0_hi;
|
||||
E2KCr1 cr1;
|
||||
|
||||
if (flags) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
buf = lock_user(VERIFY_READ, buf_addr, count * sizeof(*buf), 1);
|
||||
pcs_base = lock_user(VERIFY_WRITE, env->pcsp.base, env->pcsp.index, 1);
|
||||
if (!buf || !pcs_base) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
frame = pcs_base + env->pcsp.index / sizeof(*frame);
|
||||
|
||||
while (nr_written < count) {
|
||||
target_ulong prev_ip, ip;
|
||||
|
||||
frame -= 1;
|
||||
if (frame < pcs_base) {
|
||||
/* Not an error: we will just return the size */
|
||||
break;
|
||||
}
|
||||
|
||||
__get_user(ip, buf);
|
||||
__get_user(cr0_hi, &frame->cr0_hi);
|
||||
__get_user(cr1.lo, &frame->cr1.lo);
|
||||
|
||||
if (ip == -1) {
|
||||
ip = E2K_SYSRET_BACKTRACE_ADDR;
|
||||
}
|
||||
|
||||
prev_ip = cr0_hi & ~7;
|
||||
|
||||
/* skip fake kernel frames */
|
||||
if (prev_ip >= TARGET_TASK_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip the requested number of frames */
|
||||
if (skip) {
|
||||
--skip;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_privileged_return(ip) && !access_ok(cpu, VERIFY_READ, ip, 8)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Forbid changing of special return value into normal
|
||||
* one - to avoid cases when user changes to special and
|
||||
* back to normal function to avoid security checks. */
|
||||
if (is_privileged_return(prev_ip) && !is_privileged_return(ip)) {
|
||||
ret = -TARGET_EPERM;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: ip/prev_ip page flags checks
|
||||
|
||||
cr0_hi = ip & ~7;
|
||||
|
||||
__put_user(cr0_hi, &frame->cr0_hi);
|
||||
if (is_privileged_return(ip)) {
|
||||
cr1.pm = 1;
|
||||
cr1.ic = 0;
|
||||
__put_user(cr1.lo, &frame->cr1.lo);
|
||||
}
|
||||
|
||||
buf += 1;
|
||||
nr_written += 1;
|
||||
}
|
||||
|
||||
if (nr_written) {
|
||||
ret = nr_written;
|
||||
}
|
||||
|
||||
exit:
|
||||
unlock_user(pcs_base, env->pcsp.base, env->pcsp.index);
|
||||
unlock_user(buf, buf_addr, count * sizeof(buf));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static abi_long do_e2k_get_backtrace(CPUState *cpu, abi_ulong buf_addr,
|
||||
abi_ulong count, abi_ulong skip, abi_ulong flags)
|
||||
{
|
||||
E2KCPU *e2k_cpu = E2K_CPU(cpu);
|
||||
CPUE2KState *env = &e2k_cpu->env;
|
||||
E2KCrs *pcs_base, *frame;
|
||||
target_ulong *buf;
|
||||
abi_long ret = 0;
|
||||
int nr_read = 0;
|
||||
uint64_t cr0_hi;
|
||||
|
||||
if (flags) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
buf = lock_user(VERIFY_WRITE, buf_addr, count * sizeof(*buf), 0);
|
||||
pcs_base = lock_user(VERIFY_READ, env->pcsp.base, env->pcsp.index, 1);
|
||||
if (!buf || !pcs_base) {
|
||||
ret = -TARGET_EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
frame = pcs_base + env->pcsp.index / sizeof(*frame);
|
||||
|
||||
while (nr_read < count) {
|
||||
target_ulong ip;
|
||||
|
||||
frame -= 1;
|
||||
if (frame < pcs_base) {
|
||||
/* Not an error: we will just return the size */
|
||||
break;
|
||||
}
|
||||
|
||||
__get_user(cr0_hi, &frame->cr0_hi);
|
||||
ip = cr0_hi & ~7;
|
||||
|
||||
/* skip fake kernel frames */
|
||||
if (!is_privileged_return(ip) && ip >= TARGET_TASK_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip the requested number of frames */
|
||||
if (skip) {
|
||||
--skip;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_privileged_return(ip) && !access_ok(cpu, VERIFY_READ, ip, 8)) {
|
||||
ret = -TARGET_EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Special case of "just return" function */
|
||||
if (is_privileged_return(ip)) {
|
||||
ip = -1;
|
||||
}
|
||||
|
||||
__put_user(ip, buf);
|
||||
|
||||
buf += 1;
|
||||
nr_read += 1;
|
||||
}
|
||||
|
||||
if (nr_read) {
|
||||
ret = nr_read;
|
||||
}
|
||||
|
||||
exit:
|
||||
unlock_user(pcs_base, env->pcsp.base, env->pcsp.index);
|
||||
unlock_user(buf, buf_addr, count * sizeof(buf));
|
||||
return ret;
|
||||
}
|
||||
#endif /* end of TARGET_E2K */
|
||||
|
||||
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
|
||||
{
|
||||
struct flock64 fl64;
|
||||
|
@ -11885,6 +12405,35 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||
#endif
|
||||
return ret;
|
||||
#endif
|
||||
#ifdef TARGET_NR_e2k_longjmp2
|
||||
case TARGET_NR_e2k_longjmp2:
|
||||
{
|
||||
E2KCPU *e2k_cpu = E2K_CPU(cpu);
|
||||
CPUE2KState *env = &e2k_cpu->env;
|
||||
struct target_jmp_info ji;
|
||||
ret = copy_from_user_jmp_info(&ji, arg1);
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
ret = do_e2k_longjmp2(env, &ji);
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
return arg2;
|
||||
}
|
||||
#endif
|
||||
#ifdef TARGET_NR_access_hw_stacks
|
||||
case TARGET_NR_access_hw_stacks:
|
||||
return do_e2k_access_hw_stacks(cpu, arg1, arg2, arg3, arg4, arg5);
|
||||
#endif
|
||||
#ifdef TARGET_NR_set_backtrace
|
||||
case TARGET_NR_set_backtrace:
|
||||
return do_e2k_set_backtrace(cpu, arg1, arg2, arg3, arg4);
|
||||
#endif
|
||||
#ifdef TARGET_NR_get_backtrace
|
||||
case TARGET_NR_get_backtrace:
|
||||
return do_e2k_get_backtrace(cpu, arg1, arg2, arg3, arg4);
|
||||
#endif
|
||||
#ifdef CONFIG_ATTR
|
||||
#ifdef TARGET_NR_setxattr
|
||||
case TARGET_NR_listxattr:
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
|| defined(TARGET_M68K) || defined(TARGET_CRIS) \
|
||||
|| defined(TARGET_S390X) || defined(TARGET_OPENRISC) \
|
||||
|| defined(TARGET_NIOS2) || defined(TARGET_RISCV) \
|
||||
|| defined(TARGET_XTENSA)
|
||||
|| defined(TARGET_XTENSA) || defined(TARGET_E2K)
|
||||
|
||||
#define TARGET_IOC_SIZEBITS 14
|
||||
#define TARGET_IOC_DIRBITS 2
|
||||
|
@ -1327,6 +1327,25 @@ struct target_winsize {
|
|||
#define TARGET_MAP_NONBLOCK 0x20000 /* do not block on IO */
|
||||
#define TARGET_MAP_STACK 0x40000
|
||||
#define TARGET_MAP_HUGETLB 0x80000 /* create a huge page mapping */
|
||||
#elif defined(TARGET_E2K)
|
||||
#define TARGET_MAP_ANONYMOUS 0x000010 /* don't use a file */
|
||||
#define TARGET_MAP_FIXED 0x000100 /* Interpret addr exactly */
|
||||
#define TARGET_MAP_DENYWRITE 0x000800 /* ETXTBSY */
|
||||
#define TARGET_MAP_GROWSDOWN 0x001000 /* stack-like segment */
|
||||
#define TARGET_MAP_GROWSUP 0x002000 /* register stack-like segment */
|
||||
#define TARGET_MAP_EXECUTABLE 0x004000 /* mark it as an executable */
|
||||
#define TARGET_MAP_LOCKED 0x008000 /* pages are locked */
|
||||
#define TARGET_MAP_NORESERVE 0x010000 /* don't check for reservations */
|
||||
#define TARGET_MAP_POPULATE 0x020000 /* populate (prefault) pagetables */
|
||||
#define TARGET_MAP_NONBLOCK 0x040000 /* do not block on IO */
|
||||
#define TARGET_MAP_FIRST32 0x080000 /* in protected mode map in */
|
||||
/* first 2 ** 32 area */
|
||||
#define TARGET_MAP_WRITECOMBINED 0x100000 /* Write combine */
|
||||
#define TARGET_MAP_HUGETLB 0x200000 /* create a huge page mapping */
|
||||
#define TARGET_MAP_FIXED_NOREPLACE 0x400000 /* MAP_FIXED which doesn't unmap */
|
||||
/* underlying mapping */
|
||||
#define TARGET_MAP_STACK TARGET_MAP_GROWSDOWN
|
||||
|
||||
#else
|
||||
#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */
|
||||
#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */
|
||||
|
@ -1552,6 +1571,57 @@ struct target_stat64 {
|
|||
unsigned int __unused2;
|
||||
};
|
||||
|
||||
#elif defined(TARGET_E2K)
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
struct target_stat {
|
||||
abi_uint st_dev;
|
||||
abi_ulong st_ino;
|
||||
abi_uint st_mode;
|
||||
abi_uint st_nlink;
|
||||
abi_uint st_uid;
|
||||
abi_uint st_gid;
|
||||
abi_uint st_rdev;
|
||||
abi_long st_size;
|
||||
abi_long st_blksize;
|
||||
abi_long st_blocks;
|
||||
abi_long target_st_atime;
|
||||
abi_ulong target_st_atime_nsec;
|
||||
abi_long target_st_mtime;
|
||||
abi_ulong target_st_mtime_nsec;
|
||||
abi_long target_st_ctime;
|
||||
abi_ulong target_st_ctime_nsec;
|
||||
};
|
||||
|
||||
#define TARGET_HAS_STRUCT_STAT64
|
||||
struct target_stat64 {
|
||||
abi_ullong st_dev;
|
||||
abi_ullong st_ino;
|
||||
abi_uint st_mode;
|
||||
abi_uint st_nlink;
|
||||
abi_uint st_uid;
|
||||
abi_uint st_gid;
|
||||
abi_ullong st_rdev;
|
||||
abi_ullong st_size;
|
||||
abi_uint st_blksize;
|
||||
abi_uint __unused1;
|
||||
abi_ullong st_blocks;
|
||||
#if 0
|
||||
abi_int target_st_atime;
|
||||
abi_uint target_st_atime_nsec;
|
||||
abi_int target_st_mtime;
|
||||
abi_uint target_st_mtime_nsec;
|
||||
abi_int target_st_ctime;
|
||||
abi_uint target_st_ctime_nsec;
|
||||
#else
|
||||
abi_long target_st_atime;
|
||||
abi_ulong target_st_atime_nsec;
|
||||
abi_long target_st_mtime;
|
||||
abi_ulong target_st_mtime_nsec;
|
||||
abi_long target_st_ctime;
|
||||
abi_ulong target_st_ctime_nsec;
|
||||
#endif
|
||||
};
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
|
@ -2319,6 +2389,36 @@ struct target_statfs64 {
|
|||
int32_t f_flags;
|
||||
int32_t f_spare[4];
|
||||
};
|
||||
#elif defined(TARGET_E2K)
|
||||
struct target_statfs {
|
||||
abi_long f_type;
|
||||
abi_long f_bsize;
|
||||
abi_ulong f_blocks;
|
||||
abi_ulong f_bfree;
|
||||
abi_ulong f_bavail;
|
||||
abi_ulong f_files;
|
||||
abi_ulong f_ffree;
|
||||
target_fsid_t f_fsid;
|
||||
abi_long f_namelen;
|
||||
abi_long f_frsize;
|
||||
abi_long f_flags;
|
||||
abi_long f_spare[4];
|
||||
};
|
||||
|
||||
struct target_statfs64 {
|
||||
abi_long f_type;
|
||||
abi_long f_bsize;
|
||||
abi_ullong f_blocks;
|
||||
abi_ullong f_bfree;
|
||||
abi_ullong f_bavail;
|
||||
abi_ullong f_files;
|
||||
abi_ullong f_ffree;
|
||||
target_fsid_t f_fsid;
|
||||
abi_long f_namelen;
|
||||
abi_long f_frsize;
|
||||
abi_long f_flags;
|
||||
abi_long f_spare[4];
|
||||
};
|
||||
#else
|
||||
struct target_statfs {
|
||||
uint32_t f_type;
|
||||
|
|
|
@ -2334,6 +2334,7 @@ disassemblers = {
|
|||
'avr' : ['CONFIG_AVR_DIS'],
|
||||
'cris' : ['CONFIG_CRIS_DIS'],
|
||||
'hexagon' : ['CONFIG_HEXAGON_DIS'],
|
||||
'e2k' : ['CONFIG_E2K_DIS'],
|
||||
'hppa' : ['CONFIG_HPPA_DIS'],
|
||||
'i386' : ['CONFIG_I386_DIS'],
|
||||
'x86_64' : ['CONFIG_I386_DIS'],
|
||||
|
@ -2349,6 +2350,7 @@ disassemblers = {
|
|||
'sh4' : ['CONFIG_SH4_DIS'],
|
||||
'sparc' : ['CONFIG_SPARC_DIS'],
|
||||
'xtensa' : ['CONFIG_XTENSA_DIS'],
|
||||
'loongarch' : ['CONFIG_LOONGARCH_DIS'],
|
||||
}
|
||||
if link_language == 'cpp'
|
||||
disassemblers += {
|
||||
|
|
|
@ -495,7 +495,7 @@ class QEMUMachine:
|
|||
"""
|
||||
# If we keep the console socket open, we may deadlock waiting
|
||||
# for QEMU to exit, while QEMU is waiting for the socket to
|
||||
# become writeable.
|
||||
# become writable.
|
||||
if self._console_socket is not None:
|
||||
self._console_socket.close()
|
||||
self._console_socket = None
|
||||
|
|
|
@ -323,7 +323,8 @@
|
|||
'TARGET_ARM',
|
||||
'TARGET_I386',
|
||||
'TARGET_S390X',
|
||||
'TARGET_MIPS' ] } }
|
||||
'TARGET_MIPS',
|
||||
'TARGET_LOONGARCH64' ] } }
|
||||
|
||||
##
|
||||
# @query-cpu-definitions:
|
||||
|
@ -339,4 +340,5 @@
|
|||
'TARGET_ARM',
|
||||
'TARGET_I386',
|
||||
'TARGET_S390X',
|
||||
'TARGET_MIPS' ] } }
|
||||
'TARGET_MIPS',
|
||||
'TARGET_LOONGARCH64' ] } }
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
##
|
||||
{ 'enum' : 'SysEmuTarget',
|
||||
'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
|
||||
'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
|
||||
'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
|
||||
'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
|
||||
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
|
||||
'sh4eb', 'sparc', 'sparc64', 'tricore',
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
qemu_target_list="i386 i486 alpha arm armeb sparc sparc32plus sparc64 \
|
||||
ppc ppc64 ppc64le m68k mips mipsel mipsn32 mipsn32el mips64 mips64el \
|
||||
sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \
|
||||
microblaze microblazeel or1k x86_64 hexagon"
|
||||
microblaze microblazeel or1k x86_64 hexagon e2k e2k_old e2k32 e2k32_old"
|
||||
|
||||
i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
|
||||
i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
|
@ -140,6 +140,22 @@ hexagon_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x
|
|||
hexagon_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
hexagon_family=hexagon
|
||||
|
||||
e2k_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xaf\x00'
|
||||
e2k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
e2k_family=e2k
|
||||
|
||||
e2k_old_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x31\x00'
|
||||
e2k_old_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
e2k_old_family=e2k
|
||||
|
||||
e2k32_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xaf\x00'
|
||||
e2k32_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
e2k32_family=e2k
|
||||
|
||||
e2k32_old_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x31\x00'
|
||||
e2k32_old_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
e2k32_old_family=e2k
|
||||
|
||||
qemu_get_family() {
|
||||
cpu=${HOST_ARCH:-$(uname -m)}
|
||||
case "$cpu" in
|
||||
|
@ -316,10 +332,12 @@ qemu_set_binfmts() {
|
|||
continue
|
||||
fi
|
||||
|
||||
qemu="$QEMU_PATH/qemu-$cpu"
|
||||
if [ "$cpu" = "i486" ] ; then
|
||||
qemu="$QEMU_PATH/qemu-i386"
|
||||
fi
|
||||
case "$cpu" in
|
||||
"i486" ) qemu="$QEMU_PATH/qemu-i386";;
|
||||
"e2k_old" ) qemu="$QEMU_PATH/qemu-e2k";;
|
||||
"e2k32_old" ) qemu="$QEMU_PATH/qemu-e2k32";;
|
||||
* ) qemu="$QEMU_PATH/qemu-$cpu";;
|
||||
esac
|
||||
|
||||
qemu="$qemu$QEMU_SUFFIX"
|
||||
if [ "$host_family" != "$family" ] ; then
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue