Merge remote-tracking branch 'elbrus/e2k' into e2k-bsd-user

This commit is contained in:
Gleb Popov 2022-06-18 13:11:44 +03:00
commit 22dbdd7c74
192 changed files with 51268 additions and 3100 deletions

View File

@ -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

View File

@ -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)) {
/*

View File

@ -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

View File

@ -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.

View File

@ -0,0 +1,3 @@
# Default configuration for loongarch64-softmmu
CONFIG_LOONGARCH_VIRT=y

View File

@ -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

View File

@ -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

View File

@ -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

3
configure vendored
View File

@ -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

View File

@ -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
}

14902
disas/e2k-opc.h Normal file

File diff suppressed because it is too large Load Diff

2730
disas/e2k.c Normal file

File diff suppressed because it is too large Load Diff

556
disas/e2k.h Normal file
View File

@ -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;

View File

@ -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'))

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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;

2464
gdb-xml/e2k-v1.xml Normal file

File diff suppressed because it is too large Load Diff

6
gdb-xml/e2k-v2.xml Normal file
View File

@ -0,0 +1,6 @@
<feature name="org.mcst.gdb.elbrus-v2.linux">
<!-- 840 -->
<reg name="idr" bitsize="64" type="uint64"/>
</feature>

6
gdb-xml/e2k-v3.xml Normal file
View File

@ -0,0 +1,6 @@
<feature name="org.mcst.gdb.elbrus-v3.linux">
<!-- 841 -->
<reg name="core_mode" bitsize="64" type="uint64"/>
</feature>

86
gdb-xml/e2k-v5.xml Normal file
View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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[] = {

View File

@ -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

View File

@ -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)
*/

View File

@ -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

View File

@ -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)

View File

@ -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");

View File

@ -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:

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

312
hw/intc/loongarch_extioi.c Normal file
View File

@ -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)

242
hw/intc/loongarch_ipi.c Normal file
View File

@ -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)

View File

@ -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)

431
hw/intc/loongarch_pch_pic.c Normal file
View File

@ -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)

View File

@ -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'))

View File

@ -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);

View File

@ -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) &&

View File

@ -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

16
hw/loongarch/Kconfig Normal file
View File

@ -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

382
hw/loongarch/loongson3.c Normal file
View File

@ -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)

4
hw/loongarch/meson.build Normal file
View File

@ -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}

View File

@ -50,6 +50,7 @@ subdir('avr')
subdir('cris')
subdir('hppa')
subdir('i386')
subdir('loongarch')
subdir('m68k')
subdir('microblaze')
subdir('mips')

View File

@ -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;

View File

@ -27,3 +27,6 @@ config SUN4V_RTC
config GOLDFISH_RTC
bool
config LS7A_RTC
bool

528
hw/rtc/ls7a_rtc.c Normal file
View File

@ -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)

View File

@ -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'))

View File

@ -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

View File

@ -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;

View File

@ -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)) {

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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;

198
linux-user/e2k/cpu_loop.c Normal file
View File

@ -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;
}

362
linux-user/e2k/signal.c Normal file
View File

@ -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;
}

View File

@ -0,0 +1 @@
#include "../generic/sockbits.h"

457
linux-user/e2k/syscall_nr.h Normal file
View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -0,0 +1,4 @@
#ifndef E2K_TARGET_FCNTL_H
#define E2K_TARGET_FCNTL_H
#include "../generic/fcntl.h"
#endif

View File

@ -0,0 +1 @@
/* TODO */

View File

@ -0,0 +1 @@
#include "../generic/target_resource.h"

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -0,0 +1,6 @@
#ifndef _E2K_TERMBITS_H_
#define _E2K_TERMBITS_H_
#include "../generic/termbits.h"
#endif /* _E2K_TERMBITS_H_ */

View File

@ -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(&regs->pcsp, E2K_DEFAULT_PCS_SIZE, false);
e2k_psp_new(&regs->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

View File

@ -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 */

View File

@ -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
*/

View File

@ -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

View File

@ -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:

View File

@ -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;

View File

@ -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 += {

View File

@ -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

View File

@ -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' ] } }

View File

@ -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',

View File

@ -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