diff --git a/configs/devices/sw64-softmmu/default.mak b/configs/devices/sw64-softmmu/default.mak index 0b4d56b43e42c2afc75fd5662ce4a42b2ce1d604..f76bbf6fddce09645df888b60de9c379481dbd99 100644 --- a/configs/devices/sw64-softmmu/default.mak +++ b/configs/devices/sw64-softmmu/default.mak @@ -8,3 +8,12 @@ # Boards: # CONFIG_CORE3=y +CONFIG_CORE4=y +CONFIG_ACPI=y +CONFIG_ACPI_MEMORY_HOTPLUG=y +CONFIG_ACPI_CPU_HOTPLUG = y +CONFIG_ACPI_SW64_PM=y +CONFIG_ACPI_PCI=y +CONFIG_MEM_DEVICE=y +CONFIG_DIMM=y +CONFIG_PCI_EXPRESS_GENERIC_BRIDGE=y diff --git a/configs/targets/sw64-softmmu.mak b/configs/targets/sw64-softmmu.mak index 9cf002df8ca4568dadf69cc1ff5130c1872a7b3b..67351502572ee2829076c7656964799639aa1530 100644 --- a/configs/targets/sw64-softmmu.mak +++ b/configs/targets/sw64-softmmu.mak @@ -7,3 +7,4 @@ TARGET_BASE_ARCH=sw64 TARGET_ABI_DIR=sw64 TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/sw64-core.xml +TARGET_NEED_FDT=y diff --git a/configure b/configure index 991fe678863af95562cca6ae93863f760f54a554..9a69f121f025ea797f99175485e0476650ab9ceb 100755 --- a/configure +++ b/configure @@ -999,10 +999,18 @@ for opt do ;; --disable-crypto-afalg) crypto_afalg="no" ;; + --disable-vt-iommu) vt_iommu="no" + ;; + --enable-vt-iommu) vt_iommu="yes" + ;; --disable-vhost-net) vhost_net="no" ;; --enable-vhost-net) vhost_net="yes" ;; + --disable-vt-memhp) vt_memhp="no" + ;; + --enable-vt-memhp) vt_memhp="yes" + ;; --disable-vhost-crypto) vhost_crypto="no" ;; --enable-vhost-crypto) vhost_crypto="yes" @@ -1432,6 +1440,8 @@ cat << EOF membarrier membarrier system call (for Linux 4.14+ or Windows) rdma Enable RDMA-based migration pvrdma Enable PVRDMA support + vt-iommu vt-iommu device support + vt_memhp vt-memhp support vhost-net vhost-net kernel acceleration support vhost-vsock virtio sockets device support vhost-scsi vhost-scsi kernel target support @@ -3445,6 +3455,12 @@ if test "$xen" = "enabled" ; then echo "XEN_CFLAGS=$xen_cflags" >> $config_host_mak echo "XEN_LIBS=$xen_libs" >> $config_host_mak fi +if test "$vt_iommu" = "yes" ; then + echo "CONFIG_SW64_VT_IOMMU=y" >> $config_host_mak +fi +if test "$vt_memhp" = "yes" ; then + echo "CONFIG_VT_MEMHOTPLUG=y" >> $config_host_mak +fi if test "$vhost_scsi" = "yes" ; then echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak fi diff --git a/disas.c b/disas.c index 897de1d9a98d251de466c388177c50c0b63c20f0..adc76d72b48ed65d7f9b6f03869972f4c7595ad3 100644 --- a/disas.c +++ b/disas.c @@ -208,7 +208,7 @@ static void initialize_debug_host(CPUDebug *s) #elif defined(__hppa__) s->info.print_insn = print_insn_hppa; #elif defined(__sw_64__) - s->info.print_insn = print_insn_sw_64; + s->info.print_insn = print_insn_sw64; #endif } diff --git a/disas/sw64.c b/disas/sw64.c index 16504c673a948f075a13415bc9c820d2bdd5232c..5e67fecbd43e3bc4adee9baf35958cec63f4fadf 100755 --- a/disas/sw64.c +++ b/disas/sw64.c @@ -1,5 +1,8 @@ /* - * sw_64-dis.c -- Disassemble Sw_64 CORE3 instructions + * sw64-dis.c -- Disassemble SW64 instructions + * Copyright (C) 1996-2015 Free Software Foundation, Inc. + * Contributed by Richard Henderson , + * patterned after the PPC opcode handling written by Ian Lance Taylor. * * This file is part of libopcodes. * @@ -24,7 +27,7 @@ #undef MAX -struct sw_64_opcode { +struct sw64_opcode { /* The opcode name. */ const char *name; @@ -52,17 +55,18 @@ struct sw_64_opcode { /* The table itself is sorted by major opcode number, and is otherwise in the order in which the disassembler should consider instructions. */ -extern const struct sw_64_opcode sw_64_opcodes[]; -extern const unsigned sw_64_num_opcodes; +extern const struct sw64_opcode sw64_opcodes[]; +extern const unsigned sw64_num_opcodes; -/* Values defined for the flags field of a struct sw_64_opcode. */ +/* Values defined for the flags field of a struct sw64_opcode. */ /* CPU Availability */ -#define SW_OPCODE_BASE 0x0001 /* Base architecture insns. */ -#define SW_OPCODE_CORE3 0x0002 /* Core3 private insns. */ +#define SW_OPCODE_BASE 0x0001 /* Base architecture insns. */ +#define SW_OPCODE_CORE3 0x0002 /* Core3 private insns. */ +#define SW_OPCODE_CORE4 0x0004 /* Core4 private insns. */ #define SW_LITOP(i) (((i) >> 26) & 0x3D) -#define SW_OPCODE_NOHMCODE (~(SW_OPCODE_BASE|SW_OPCODE_CORE3)) +#define SW_OPCODE_NOHMCODE (~(SW_OPCODE_BASE|SW_OPCODE_CORE3|SW_OPCODE_CORE4)) /* A macro to extract the major opcode from an instruction. */ #define SW_OP(i) (((i) >> 26) & 0x3F) @@ -70,9 +74,9 @@ extern const unsigned sw_64_num_opcodes; /* The total number of major opcodes. */ #define SW_NOPS 0x40 -/* The operands table is an array of struct sw_64_operand. */ +/* The operands table is an array of struct sw64_operand. */ -struct sw_64_operand { +struct sw64_operand { /* The number of bits in the operand. */ unsigned int bits : 5; @@ -124,11 +128,11 @@ struct sw_64_operand { }; /* Elements in the table are retrieved by indexing with values from - the operands field of the sw_64_opcodes table. */ + the operands field of the sw64_opcodes table. */ -extern const struct sw_64_operand sw_64_operands[]; -extern const unsigned sw_64_num_operands; -/* Values defined for the flags field of a struct sw_64_operand. */ +extern const struct sw64_operand sw64_operands[]; +extern const unsigned sw64_num_operands; +/* Values defined for the flags field of a struct sw64_operand. */ /* Mask for selecting the type for typecheck purposes */ #define SW_OPERAND_TYPECHECK_MASK \ @@ -225,11 +229,6 @@ extern const unsigned sw_64_num_operands; #define SW_REG_SP 30 #define SW_REG_ZERO 31 -enum bfd_reloc_code_real { - BFD_RELOC_23_PCREL_S2, - BFD_RELOC_SW_64_HINT -}; - static unsigned insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED) { @@ -328,37 +327,37 @@ static int extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED) return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000); } -/* The hint field of a JMP/JSR insn. */ -/* sw use 16 bits hint disp. */ -static unsigned insert_jhint(unsigned insn, int value, const char **errmsg) +static unsigned +insert_bdisp26 (unsigned insn, int value, const char **errmsg) { if (errmsg != (const char **)NULL && (value & 3)) - *errmsg = "jump hint unaligned"; - return insn | ((value / 4) & 0xFFFF); + *errmsg = "branch operand unaligned"; + return insn | ((value / 4) & 0x3FFFFFF); } -static int extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +static int +extract_bdisp26 (unsigned insn, int *invalid ATTRIBUTE_UNUSED) { - return 4 * (((insn & 0xFFFF) ^ 0x8000) - 0x8000); + return 4 * (((insn & 0x3FFFFFF) ^ 0x2000000) - 0x2000000); } -/* The hint field of an CORE3 HW_JMP/JSR insn. */ - -static unsigned insert_sw4hwjhint(unsigned insn, int value, const char **errmsg) +/* The hint field of a JMP/JSR insn. */ +/* sw use 16 bits hint disp. */ +static unsigned insert_jhint(unsigned insn, int value, const char **errmsg) { if (errmsg != (const char **)NULL && (value & 3)) *errmsg = "jump hint unaligned"; - return insn | ((value / 4) & 0x1FFF); + return insn | ((value / 4) & 0xFFFF); } -static int extract_sw4hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) +static int extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED) { - return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000); + return 4 * (((insn & 0xFFFF) ^ 0x8000) - 0x8000); } /* The operands table. */ -const struct sw_64_operand sw_64_operands[] = { +const struct sw64_operand sw64_operands[] = { /* The fields are bits, shift, insert, extract, flags */ /* The zero index is used to indicate end-of-list */ #define UNUSED 0 @@ -439,7 +438,7 @@ const struct sw_64_operand sw_64_operands[] = { /* The signed "23-bit" aligned displacement of Branch format insns. */ #define BDISP (MDISP + 1) - { 21, 0, BFD_RELOC_23_PCREL_S2, + { 21, 0, -BDISP, SW_OPERAND_RELATIVE, insert_bdisp, extract_bdisp }, /* The 26-bit hmcode function for sys_call and sys_call / b. */ @@ -449,7 +448,7 @@ const struct sw_64_operand sw_64_operands[] = { /* sw jsr/ret insntructions has no function bits. */ /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint. */ #define JMPHINT (HMFN + 1) - { 16, 0, BFD_RELOC_SW_64_HINT, + { 16, 0, -JMPHINT, SW_OPERAND_RELATIVE | SW_OPERAND_DEFAULT_ZERO | SW_OPERAND_NOOVERFLOW, insert_jhint, extract_jhint }, @@ -467,8 +466,6 @@ const struct sw_64_operand sw_64_operands[] = { #define HWINDEX (HWDISP + 1) { 16, 0, -HWINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, - /* The 13-bit branch hint for the core3 hw_jmp/jsr (pal1e) insn. */ - /* for the third operand of ternary operands integer insn. */ #define R3 (HWINDEX + 1) { 5, 5, 0, SW_OPERAND_IR, 0, 0 }, @@ -477,14 +474,21 @@ const struct sw_64_operand sw_64_operands[] = { { 5, 5, 0, SW_OPERAND_FPR, 0, 0 }, /* sw simd settle instruction lit */ #define FMALIT (F3 + 1) - { 5, 5, -FMALIT, SW_OPERAND_UNSIGNED, 0, 0 }, //V1.1 + { 5, 5, -FMALIT, SW_OPERAND_UNSIGNED, 0, 0 }, #define RPIINDEX (FMALIT + 1) { 8, 0, -RPIINDEX, SW_OPERAND_UNSIGNED, 0, 0 }, #define ATMDISP (RPIINDEX + 1) { 12, 0, -ATMDISP, SW_OPERAND_SIGNED, 0, 0 }, +#define DISP13 (ATMDISP + 1) + { 13, 13, -DISP13, SW_OPERAND_SIGNED, 0, 0 }, +#define BDISP26 (DISP13 + 1) + { 26, 0, 222, + SW_OPERAND_RELATIVE, insert_bdisp26, extract_bdisp26 }, +#define DPFTH (BDISP26 + 1) + { 5, 21, -DPFTH, SW_OPERAND_UNSIGNED, 0, 0 } }; -const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_operands); +const unsigned sw64_num_operands = sizeof(sw64_operands) / sizeof(*sw64_operands); /* Macros used to form opcodes. */ @@ -574,6 +578,7 @@ const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_opera /* Abbreviations for instruction subsets. */ #define BASE SW_OPCODE_BASE #define CORE3 SW_OPCODE_CORE3 +#define CORE4 SW_OPCODE_CORE4 /* Common combinations of arguments. */ #define ARG_NONE { 0 } @@ -584,7 +589,7 @@ const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_opera #define ARG_MEM { RA, MDISP, PRB } #define ARG_FMEM { FA, MDISP, PRB } #define ARG_OPR { RA, RB, DRC1 } - +#define ARG_OPRCAS { RA, RB, RC } #define ARG_OPRL { RA, LIT, DRC1 } #define ARG_OPRZ1 { ZA, RB, DRC1 } #define ARG_OPRLZ1 { ZA, LIT, RC } @@ -598,6 +603,7 @@ const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_opera #define ARG_FMAL { FA,FB,FMALIT, DFC1 } #define ARG_ATMEM { RA, ATMDISP, PRB } #define ARG_VUAMEM { FA, ATMDISP, PRB } +#define ARG_DISP13 { DISP13, RC } /* The opcode table. @@ -623,7 +629,7 @@ const unsigned sw_64_num_operands = sizeof(sw_64_operands) / sizeof(*sw_64_opera Otherwise, it is sorted by major opcode and minor function code. */ -const struct sw_64_opcode sw_64_opcodes[] = { +const struct sw64_opcode sw64_opcodes[] = { { "sys_call/b", PCD(0x00,0x00), BASE, ARG_PCD }, { "sys_call", PCD(0x00,0x01), BASE, ARG_PCD }, @@ -636,15 +642,20 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "bsr", BRA(0x05), BASE, ARG_BRA }, { "memb", MFC(0x06,0x0000), BASE, ARG_NONE }, { "imemb", MFC(0x06,0x0001), BASE, ARG_NONE }, + { "wmemb", MFC(0x06,0x0002), CORE4, ARG_NONE }, { "rtc", MFC(0x06,0x0020), BASE, { RA, ZB } }, { "rtc", MFC(0x06,0x0020), BASE, { RA, RB } }, - { "rcid", MFC(0x06,0x0040), BASE, { RA , ZB} }, + { "rcid", MFC(0x06,0x0040), BASE, { RA, ZB} }, { "halt", MFC(0x06,0x0080), BASE, { ZA, ZB } }, { "rd_f", MFC(0x06,0x1000), CORE3, { RA, ZB } }, { "wr_f", MFC(0x06,0x1020), CORE3, { RA, ZB } }, { "rtid", MFC(0x06,0x1040), BASE, { RA } }, - { "pri_rcsr", CSR(0x06,0xFE), CORE3, { RA, RPIINDEX ,ZB } }, - { "pri_wcsr", CSR(0x06,0xFF), CORE3, { RA, RPIINDEX ,ZB } }, + { "pri_rcsr", CSR(0x06,0xFE), CORE3, { RA, RPIINDEX, ZB } }, + { "pri_wcsr", CSR(0x06,0xFF), CORE3, { RA, RPIINDEX, ZB } }, + { "csrrs", CSR(0x06,0xFC), CORE4, { RA, RPIINDEX, RB } }, + { "csrrc", CSR(0x06,0xFD), CORE4, { RA, RPIINDEX, RB } }, + { "csrr", CSR(0x06,0xFE), CORE4, { RA, RPIINDEX, ZB } }, + { "csrw", CSR(0x06,0xFF), CORE4, { RA, RPIINDEX, ZB } }, { "pri_ret", PRIRET(0x07,0x0), BASE, { RA } }, { "pri_ret/b", PRIRET(0x07,0x1), BASE, { RA } }, { "lldw", ATMEM(0x08,0x0), BASE, ARG_ATMEM }, @@ -697,12 +708,22 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "s8addl", OPRL(0x12,0x0C), BASE, ARG_OPRL }, { "s8subl", OPR(0x10,0x0D), BASE, ARG_OPR }, { "s8subl", OPRL(0x12,0x0D), BASE, ARG_OPRL }, - { "mulw", OPR(0x10,0x10), BASE, ARG_OPR }, - { "mulw", OPRL(0x12,0x10), BASE, ARG_OPRL }, - { "mull", OPR(0x10,0x18), BASE, ARG_OPR }, - { "mull", OPRL(0x12,0x18), BASE, ARG_OPRL }, - { "umulh", OPR(0x10,0x19), BASE, ARG_OPR }, - { "umulh", OPRL(0x12,0x19), BASE, ARG_OPRL }, + { "mulw", OPR(0x10,0x10), BASE, ARG_OPR }, + { "mulw", OPRL(0x12,0x10), BASE, ARG_OPRL }, + { "divw", OPR(0x10,0x11), CORE4, ARG_OPR }, + { "udivw", OPR(0x10,0x12), CORE4, ARG_OPR }, + { "remw", OPR(0x10,0x13), CORE4, ARG_OPR }, + { "uremw", OPR(0x10,0x14), CORE4, ARG_OPR }, + { "mull", OPR(0x10,0x18), BASE, ARG_OPR }, + { "mull", OPRL(0x12,0x18), BASE, ARG_OPRL }, + { "umulh", OPR(0x10,0x19), BASE, ARG_OPR }, + { "umulh", OPRL(0x12,0x19), BASE, ARG_OPRL }, + { "divl", OPR(0x10,0x1A), CORE4, ARG_OPR }, + { "udivl", OPR(0x10,0x1B), CORE4, ARG_OPR }, + { "reml", OPR(0x10,0x1C), CORE4, ARG_OPR }, + { "ureml", OPR(0x10,0x1D), CORE4, ARG_OPR }, + { "addpi", OPR(0x10,0x1E), CORE4, ARG_DISP13 }, + { "addpis", OPR(0x10,0x1F), CORE4, ARG_DISP13 }, { "cmpeq", OPR(0x10,0x28), BASE, ARG_OPR }, { "cmpeq", OPRL(0x12,0x28), BASE, ARG_OPRL }, { "cmplt", OPR(0x10,0x29), BASE, ARG_OPR }, @@ -713,7 +734,10 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "cmpult", OPRL(0x12,0x2B), BASE, ARG_OPRL }, { "cmpule", OPR(0x10,0x2C), BASE, ARG_OPR }, { "cmpule", OPRL(0x12,0x2C), BASE, ARG_OPRL }, - + { "sbt", OPR(0x10,0x2D), CORE4, ARG_OPR }, + { "sbt", OPRL(0x12,0x2D), CORE4, ARG_OPRL }, + { "cbt", OPR(0x10,0x2E), CORE4, ARG_OPR }, + { "cbt", OPRL(0x12,0x2E), CORE4, ARG_OPRL }, { "and", OPR(0x10,0x38), BASE, ARG_OPR }, { "and", OPRL(0x12,0x38),BASE, ARG_OPRL }, { "bic", OPR(0x10,0x39), BASE, ARG_OPR }, @@ -742,7 +766,22 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "inshw", OPRL(0x12,0x46),BASE, ARG_OPRL }, { "inshl", OPR(0x10,0x47), BASE, ARG_OPR }, { "inshl", OPRL(0x12,0x47),BASE, ARG_OPRL }, - + { "slll", OPR(0x10,0x48), CORE4, ARG_OPR }, + { "slll", OPRL(0x12,0x48),CORE4, ARG_OPRL }, + { "srll", OPR(0x10,0x49), CORE4, ARG_OPR }, + { "srll", OPRL(0x12,0x49),CORE4, ARG_OPRL }, + { "sral", OPR(0x10,0x4A), CORE4, ARG_OPR }, + { "sral", OPRL(0x12,0x4A),CORE4, ARG_OPRL }, + { "roll", OPR(0x10,0x4B), CORE4, ARG_OPR }, + { "roll", OPRL(0x12,0x4B),CORE4, ARG_OPRL }, + { "sllw", OPR(0x10,0x4C), CORE4, ARG_OPR }, + { "sllw", OPRL(0x12,0x4C),CORE4, ARG_OPRL }, + { "srlw", OPR(0x10,0x4D), CORE4, ARG_OPR }, + { "srlw", OPRL(0x12,0x4D),CORE4, ARG_OPRL }, + { "sraw", OPR(0x10,0x4E), CORE4, ARG_OPR }, + { "sraw", OPRL(0x12,0x4E),CORE4, ARG_OPRL }, + { "rolw", OPR(0x10,0x4F), CORE4, ARG_OPR }, + { "rolw", OPRL(0x12,0x4F),CORE4, ARG_OPRL }, { "sll", OPR(0x10,0x48), BASE, ARG_OPR }, { "sll", OPRL(0x12,0x48),BASE, ARG_OPRL }, { "srl", OPR(0x10,0x49), BASE, ARG_OPR }, @@ -768,6 +807,11 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "ctpop", OPR(0x10,0x58), BASE, ARG_OPRZ1 }, { "ctlz", OPR(0x10,0x59), BASE, ARG_OPRZ1 }, { "cttz", OPR(0x10,0x5A), BASE, ARG_OPRZ1 }, + { "revbh", OPR(0x10,0x5B), CORE4, ARG_OPRZ1 }, + { "revbw", OPR(0x10,0x5C), CORE4, ARG_OPRZ1 }, + { "revbl", OPR(0x10,0x5D), CORE4, ARG_OPRZ1 }, + { "casw", OPR(0x10,0x5E), CORE4, ARG_OPRCAS }, + { "casl", OPR(0x10,0x5F), CORE4, ARG_OPRCAS }, { "masklb", OPR(0x10,0x60), BASE, ARG_OPR }, { "masklb", OPRL(0x12,0x60),BASE, ARG_OPRL }, { "masklh", OPR(0x10,0x61), BASE, ARG_OPR }, @@ -851,6 +895,18 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "setfpec1", FP(0x18,0x55), BASE, ARG_NONE }, { "setfpec2", FP(0x18,0x56), BASE, ARG_NONE }, { "setfpec3", FP(0x18,0x57), BASE, ARG_NONE }, + { "frecs", FP(0x18,0x58), CORE4, ARG_FPZ1 }, + { "frecd", FP(0x18,0x59), CORE4, ARG_FPZ1 }, + { "fris", FP(0x18,0x5A), CORE4, ARG_FPZ1 }, + { "fris_g", FP(0x18,0x5B), CORE4, ARG_FPZ1 }, + { "fris_p", FP(0x18,0x5C), CORE4, ARG_FPZ1 }, + { "fris_z", FP(0x18,0x5D), CORE4, ARG_FPZ1 }, + { "fris_n", FP(0x18,0x5F), CORE4, ARG_FPZ1 }, + { "frid", FP(0x18,0x60), CORE4, ARG_FPZ1 }, + { "frid_g", FP(0x18,0x61), CORE4, ARG_FPZ1 }, + { "frid_p", FP(0x18,0x62), CORE4, ARG_FPZ1 }, + { "frid_z", FP(0x18,0x63), CORE4, ARG_FPZ1 }, + { "frid_n", FP(0x18,0x64), CORE4, ARG_FPZ1 }, { "fmas", FMA(0x19,0x00), BASE, ARG_FMA }, { "fmad", FMA(0x19,0x01), BASE, ARG_FMA }, { "fmss", FMA(0x19,0x02), BASE, ARG_FMA }, @@ -898,8 +954,34 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "vaddl", FP(0x1A,0x2E), BASE, ARG_FPL }, { "vsubl", FP(0x1A,0x0F), BASE, ARG_FP }, { "vsubl", FP(0x1A,0x2F), BASE, ARG_FPL }, + { "vsllb", FP(0x1A,0x10), CORE4, ARG_FP }, + { "vsllb", FP(0x1A,0x30), CORE4, ARG_FPL }, + { "vsrlb", FP(0x1A,0x11), CORE4, ARG_FP }, + { "vsrlb", FP(0x1A,0x31), CORE4, ARG_FPL }, + { "vsrab", FP(0x1A,0x12), CORE4, ARG_FP }, + { "vsrab", FP(0x1A,0x32), CORE4, ARG_FPL }, + { "vrolb", FP(0x1A,0x13), CORE4, ARG_FP }, + { "vrolb", FP(0x1A,0x33), CORE4, ARG_FPL }, + { "vsllh", FP(0x1A,0x14), CORE4, ARG_FP }, + { "vsllh", FP(0x1A,0x34), CORE4, ARG_FPL }, + { "vsrlh", FP(0x1A,0x15), CORE4, ARG_FP }, + { "vsrlh", FP(0x1A,0x35), CORE4, ARG_FPL }, + { "vsrah", FP(0x1A,0x16), CORE4, ARG_FP }, + { "vsrah", FP(0x1A,0x36), CORE4, ARG_FPL }, + { "vrolh", FP(0x1A,0x17), CORE4, ARG_FP }, + { "vrolh", FP(0x1A,0x37), CORE4, ARG_FPL }, { "ctpopow", FP(0x1A,0x18), BASE, { FA, ZB, DFC1 } }, { "ctlzow", FP(0x1A,0x19), BASE, { FA, ZB, DFC1 } }, + { "vslll", FP(0x1A,0x1A), CORE4, ARG_FP }, + { "vslll", FP(0x1A,0x3A), CORE4, ARG_FPL }, + { "vsrll", FP(0x1A,0x1B), CORE4, ARG_FP }, + { "vsrll", FP(0x1A,0x3B), CORE4, ARG_FPL }, + { "vsral", FP(0x1A,0x1C), CORE4, ARG_FP }, + { "vsral", FP(0x1A,0x3C), CORE4, ARG_FPL }, + { "vroll", FP(0x1A,0x1D), CORE4, ARG_FP }, + { "vroll", FP(0x1A,0x3D), CORE4, ARG_FPL }, + { "vmaxb", FP(0x1A,0x1E), CORE4, ARG_FP }, + { "vminb", FP(0x1A,0x1F), CORE4, ARG_FP }, { "vucaddw", FP(0x1A,0x40), BASE, ARG_FP }, { "vucaddw", FP(0x1A,0x60), BASE, ARG_FPL }, { "vucsubw", FP(0x1A,0x41), BASE, ARG_FP }, @@ -912,6 +994,32 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "vucaddb", FP(0x1A,0x64), BASE, ARG_FPL }, { "vucsubb", FP(0x1A,0x45), BASE, ARG_FP }, { "vucsubb", FP(0x1A,0x65), BASE, ARG_FPL }, + { "sraow", FP(0x1A,0x46), CORE4, ARG_FP }, + { "sraow", FP(0x1A,0x66), CORE4, ARG_FPL }, + { "vsumw", FP(0x1A,0x47), CORE4, ARG_FPZ1 }, + { "vsuml", FP(0x1A,0x48), CORE4, ARG_FPZ1 }, + { "vcmpueqb", FP(0x1A,0x4B), CORE4, ARG_FP }, + { "vcmpueqb", FP(0x1A,0x6B), CORE4, ARG_FPL }, + { "vcmpugtb", FP(0x1A,0x4C), CORE4, ARG_FP }, + { "vcmpugtb", FP(0x1A,0x6C), CORE4, ARG_FPL }, + { "vmaxh", FP(0x1A,0x50), CORE4, ARG_FP }, + { "vminh", FP(0x1A,0x51), CORE4, ARG_FP }, + { "vmaxw", FP(0x1A,0x52), CORE4, ARG_FP }, + { "vminw", FP(0x1A,0x53), CORE4, ARG_FP }, + { "vmaxl", FP(0x1A,0x54), CORE4, ARG_FP }, + { "vminl", FP(0x1A,0x55), CORE4, ARG_FP }, + { "vumaxb", FP(0x1A,0x56), CORE4, ARG_FP }, + { "vuminb", FP(0x1A,0x57), CORE4, ARG_FP }, + { "vumaxh", FP(0x1A,0x58), CORE4, ARG_FP }, + { "vuminh", FP(0x1A,0x59), CORE4, ARG_FP }, + { "vumaxw", FP(0x1A,0x5A), CORE4, ARG_FP }, + { "vuminw", FP(0x1A,0x5B), CORE4, ARG_FP }, + { "vumaxl", FP(0x1A,0x5C), CORE4, ARG_FP }, + { "vuminl", FP(0x1A,0x5D), CORE4, ARG_FP }, + { "vsm3msw", FP(0x1A,0x67), CORE4, ARG_FP }, + { "vsm4key", FP(0x1A,0x68), CORE4, ARG_FPL }, + { "vsm4r", FP(0x1A,0x69), CORE4, ARG_FP }, + { "vbinvw", FP(0x1A,0x6A), CORE4, ARG_FPZ1 }, { "vadds", FP(0x1A,0x80), BASE, ARG_FP }, { "vaddd", FP(0x1A,0x81), BASE, ARG_FP }, { "vsubs", FP(0x1A,0x82), BASE, ARG_FP }, @@ -929,6 +1037,33 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "vcpys", FP(0x1A,0x90), BASE, ARG_FP }, { "vcpyse", FP(0x1A,0x91), BASE, ARG_FP }, { "vcpysn", FP(0x1A,0x92), BASE, ARG_FP }, + { "vsums", FP(0x1A,0x93), CORE4, ARG_FPZ1 }, + { "vsumd", FP(0x1A,0x94), CORE4, ARG_FPZ1 }, + { "vfcvtsd", FP(0x1A,0x95), CORE4, ARG_FPZ1 }, + { "vfcvtds", FP(0x1A,0x96), CORE4, ARG_FPZ1 }, + { "vfcvtls", FP(0x1A,0x99), CORE4, ARG_FPZ1 }, + { "vfcvtld", FP(0x1A,0x9A), CORE4, ARG_FPZ1 }, + { "vfcvtdl", FP(0x1A,0x9B), CORE4, ARG_FPZ1 }, + { "vfcvtdl_g", FP(0x1A,0x9C), CORE4, ARG_FPZ1 }, + { "vfcvtdl_p", FP(0x1A,0x9D), CORE4, ARG_FPZ1 }, + { "vfcvtdl_z", FP(0x1A,0x9E), CORE4, ARG_FPZ1 }, + { "vfcvtdl_n", FP(0x1A,0x9F), CORE4, ARG_FPZ1 }, + { "vfris", FP(0x1A,0xA0), CORE4, ARG_FPZ1 }, + { "vfris_g", FP(0x1A,0xA1), CORE4, ARG_FPZ1 }, + { "vfris_p", FP(0x1A,0xA2), CORE4, ARG_FPZ1 }, + { "vfris_z", FP(0x1A,0xA3), CORE4, ARG_FPZ1 }, + { "vfris_n", FP(0x1A,0xA4), CORE4, ARG_FPZ1 }, + { "vfrid", FP(0x1A,0xA5), CORE4, ARG_FPZ1 }, + { "vfrid_g", FP(0x1A,0xA6), CORE4, ARG_FPZ1 }, + { "vfrid_p", FP(0x1A,0xA7), CORE4, ARG_FPZ1 }, + { "vfrid_z", FP(0x1A,0xA8), CORE4, ARG_FPZ1 }, + { "vfrid_n", FP(0x1A,0xA9), CORE4, ARG_FPZ1 }, + { "vfrecs", FP(0x1A,0xAA), CORE4, ARG_FPZ1 }, + { "vfrecd", FP(0x1A,0xAB), CORE4, ARG_FPZ1 }, + { "vmaxs", FP(0x1A,0xAC), CORE4, ARG_FP }, + { "vmins", FP(0x1A,0xAD), CORE4, ARG_FP }, + { "vmaxd", FP(0x1A,0xAE), CORE4, ARG_FP }, + { "vmind", FP(0x1A,0xAF), CORE4, ARG_FP }, { "vmas", FMA(0x1B,0x00), BASE, ARG_FMA }, { "vmad", FMA(0x1B,0x01), BASE, ARG_FMA }, { "vmss", FMA(0x1B,0x02), BASE, ARG_FMA }, @@ -958,6 +1093,19 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "vshfw", FMA(0x1B,0x27), BASE, ARG_FMA }, { "vcons", FMA(0x1B,0x28), BASE, ARG_FMA }, { "vcond", FMA(0x1B,0x29), BASE, ARG_FMA }, + { "vinsb", FMA(0x1B,0x2A), CORE4, ARG_FMAL }, + { "vinsh", FMA(0x1B,0x2B), CORE4, ARG_FMAL }, + { "vinsectlh", FMA(0x1B,0x2C), CORE4, ARG_FMA }, + { "vinsectlw", FMA(0x1B,0x2D), CORE4, ARG_FMA }, + { "vinsectll", FMA(0x1B,0x2E), CORE4, ARG_FMA }, + { "vinsectlb", FMA(0x1B,0x2F), CORE4, ARG_FMA }, + { "vshfq", FMA(0x1B,0x30), CORE4, ARG_FMAL }, + { "vshfqb", FMA(0x1B,0x31), CORE4, ARG_FMA }, + { "vcpyb", FMA(0x1B,0x32), CORE4, { FA, DFC1 }}, + { "vcpyh", FMA(0x1B,0x33), CORE4, { FA, DFC1 }}, + { "vsm3r", FMA(0x1B,0x34), CORE4, ARG_FMAL }, + { "vfcvtsh", FMA(0x1B,0x35), CORE4, ARG_FMAL }, + { "vfcvths", FMA(0x1B,0x36), CORE4, {FA, FMALIT, FC} }, { "vldw_u", ATMEM(0x1C,0x0), BASE, ARG_VUAMEM }, { "vstw_u", ATMEM(0x1C,0x1), BASE, ARG_VUAMEM }, { "vlds_u", ATMEM(0x1C,0x2), BASE, ARG_VUAMEM }, @@ -972,7 +1120,7 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "vstd_uh", ATMEM(0x1C,0xD), BASE, ARG_VUAMEM }, { "vldd_nc", ATMEM(0x1C,0xE), BASE, ARG_VUAMEM }, { "vstd_nc", ATMEM(0x1C,0xF), BASE, ARG_VUAMEM }, - + { "lbr", BRA(0x1D), CORE4, { BDISP26 }}, { "flushd", MEM(0x20), BASE, ARG_PREFETCH }, { "ldbu", MEM(0x20), BASE, ARG_MEM }, { "evictdg", MEM(0x21), BASE, ARG_PREFETCH }, @@ -1022,7 +1170,7 @@ const struct sw_64_opcode sw_64_opcodes[] = { { "ldih", MEM(0x3F), BASE, ARG_MEM }, }; -const unsigned sw_64_num_opcodes = sizeof(sw_64_opcodes) / sizeof(*sw_64_opcodes); +const unsigned sw64_num_opcodes = sizeof(sw64_opcodes) / sizeof(*sw64_opcodes); /* OSF register names. */ @@ -1050,19 +1198,19 @@ static const char * const vms_regnames[64] = { "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" }; -int print_insn_sw_64(bfd_vma memaddr, struct disassemble_info *info) +int print_insn_sw64(bfd_vma memaddr, struct disassemble_info *info) { - static const struct sw_64_opcode *opcode_index[SW_NOPS + 1]; + static const struct sw64_opcode *opcode_index[SW_NOPS + 1]; const char * const * regnames; - const struct sw_64_opcode *opcode, *opcode_end; + const struct sw64_opcode *opcode, *opcode_end; const unsigned char *opindex; unsigned insn, op, isa_mask; int need_comma; /* Initialize the majorop table the first time through */ if (!opcode_index[0]) { - opcode = sw_64_opcodes; - opcode_end = opcode + sw_64_num_opcodes; + opcode = sw64_opcodes; + opcode_end = opcode + sw64_num_opcodes; for (op = 0; op < SW_NOPS; ++op) { opcode_index[op] = opcode; @@ -1083,9 +1231,12 @@ int print_insn_sw_64(bfd_vma memaddr, struct disassemble_info *info) regnames = osf_regnames; isa_mask = SW_OPCODE_NOHMCODE; switch (info->mach) { - case bfd_mach_sw_64_core3: + case bfd_mach_sw64_core3: isa_mask |= SW_OPCODE_BASE | SW_OPCODE_CORE3; break; + case bfd_mach_sw64_core4: + isa_mask |= SW_OPCODE_BASE | SW_OPCODE_CORE4; + break; } /* Read the insn into a host word */ @@ -1122,7 +1273,7 @@ int print_insn_sw_64(bfd_vma memaddr, struct disassemble_info *info) { int invalid = 0; for (opindex = opcode->operands; *opindex != 0; opindex++) { - const struct sw_64_operand *operand = sw_64_operands + *opindex; + const struct sw64_operand *operand = sw64_operands + *opindex; if (operand->extract) (*operand->extract) (insn, &invalid); } @@ -1153,7 +1304,7 @@ found: { unsigned int truth; char tr[4]; - truth=(SW_OP(insn) & 3) << 6; + truth = (SW_OP(insn) & 3) << 6; truth = truth | ((insn & 0xFC00) >> 10); sprintf(tr,"%x",truth); (*info->fprintf_func) (info->stream, "%s", tr); @@ -1164,7 +1315,7 @@ found: /* Now extract and print the operands. */ need_comma = 0; for (opindex = opcode->operands; *opindex != 0; opindex++) { - const struct sw_64_operand *operand = sw_64_operands + *opindex; + const struct sw64_operand *operand = sw64_operands + *opindex; int value; /* Operands that are marked FAKE are simply ignored. We diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig index 245c5554df1e155a397aac6e62d6dfebed4b3c5b..ba9ab7896a1021b8cf5552caf191b23d3d7274e4 100644 --- a/hw/acpi/Kconfig +++ b/hw/acpi/Kconfig @@ -68,3 +68,11 @@ config ACPI_HW_REDUCED select ACPI select ACPI_MEMORY_HOTPLUG select ACPI_NVDIMM + +config ACPI_SW64_PM + bool + depends on ACPI + +config GPIO_SUNWAY + bool + depends on ACPI diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 39b8d807c09cbd5e83c2c835b9f46381af554964..f24bad8228dbcac6a0c2e004c226b28e4c7ae648 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1490,6 +1490,18 @@ Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, isa_ranges); } +Aml *aml_qword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, + AmlDecode dec, AmlISARanges isa_ranges, + uint64_t addr_gran, uint64_t addr_min, + uint64_t addr_max, uint64_t addr_trans, + uint64_t len) + +{ + return aml_qword_as_desc(AML_IO_RANGE, min_fixed, max_fixed, dec, + addr_gran, addr_min, addr_max, addr_trans, len, + isa_ranges); +} + /* * ACPI 1.0b: 6.4.3.5.4 ASL Macros for DWORD Address Space Descriptor * diff --git a/hw/acpi/gpio_sunway.c b/hw/acpi/gpio_sunway.c new file mode 100644 index 0000000000000000000000000000000000000000..70654f9b5ec8d9fc3a9690848500f1112db8e55b --- /dev/null +++ b/hw/acpi/gpio_sunway.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2024 Wxiat Corporation + * Written by Wuyacheng + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + */ + +// SPDX-License-Identifier: GPL-2.0+ + +#include "qemu/osdep.h" +#include "exec/address-spaces.h" +#include "migration/vmstate.h" +#include "hw/sw64/gpio.h" +#include "hw/irq.h" + +static void sw64_gpio_update_int(SW64GPIOState *s) +{ + qemu_set_irq(s->irq[0], 1); +} + +static void sw64_gpio_set(void *opaque, int line, int level) +{ + SW64GPIOState *s = SW64_GPIO(opaque); + + sw64_gpio_update_int(s); +} + +static void sw64_gpio_write(void *opaque, hwaddr offset, uint64_t reg_value, + unsigned size) +{ + SW64GPIOState *s = SW64_GPIO(opaque); + reg_value = (uint32_t)reg_value; + + switch (offset) { + case GPIO_SWPORTA_DR: + s->padr = reg_value; + break; + case GPIO_SWPORTA_DDR: + s->paddr = reg_value ; + break; + case GPIO_INTEN: + s->inter = reg_value; + break; + case GPIO_INTMASK: + s->intmr = reg_value; + break; + case GPIO_INTTYPE_LEVEL: + s->intlr = reg_value; + break; + case GPIO_INTTYPE_POLA: + s->intpr = reg_value; + break; + case GPIO_INTTYPE_STATUS: + s->intsr = reg_value; + break; + case GPIO_RAW_INTTYPE_STATUS: + s->rintsr = reg_value; + break; + case GPIO_DEB_ENABLE: + s->deber = reg_value; + break; + case GPIO_CLEAN_INT: + s->clintr = reg_value; + break; + case GPIO_EXT_PORTA: + s->expar = reg_value; + break; + case GPIO_SYNC_LEVEL: + s->synlr = reg_value; + break; + case GPIO_ID_CODE: + s->idcr = reg_value; + break; + case GPIO_VERSION: + s->versionr = reg_value; + break; + case GPIO_CONF_R1: + s->conf1r = reg_value; + break; + case GPIO_CONF_R2: + s->conf2r = reg_value; + break; + default: + printf("error: Bad register at offset 0x%lx\n", offset); + } + + return; +} + +static uint64_t sw64_gpio_read(void *opaque, hwaddr offset, unsigned size) +{ + SW64GPIOState *s = SW64_GPIO(opaque); + uint32_t reg_value = 0; + + switch (offset) { + case GPIO_SWPORTA_DR: + reg_value = s->padr; + break; + case GPIO_SWPORTA_DDR: + reg_value = s->paddr; + break; + case GPIO_INTEN: + reg_value = s->inter; + break; + case GPIO_INTMASK: + reg_value = s->intmr; + break; + case GPIO_INTTYPE_LEVEL: + reg_value = s->intlr; + break; + case GPIO_INTTYPE_POLA: + reg_value = s->intpr; + break; + case GPIO_INTTYPE_STATUS: + reg_value = s->intsr; + break; + case GPIO_RAW_INTTYPE_STATUS: + reg_value = s->rintsr; + break; + case GPIO_DEB_ENABLE: + reg_value = s->deber; + break; + case GPIO_CLEAN_INT: + reg_value = s->clintr; + break; + case GPIO_EXT_PORTA: + reg_value = s->expar; + break; + case GPIO_SYNC_LEVEL: + reg_value = s->synlr; + break; + case GPIO_ID_CODE: + reg_value = s->idcr; + break; + case GPIO_VERSION: + reg_value = s->versionr; + break; + case GPIO_CONF_R1: + reg_value = s->conf1r; + break; + case GPIO_CONF_R2: + reg_value = s->conf2r; + break; + default: + printf("error: Bad register at offset 0x%lx\n", offset); + return (uint64_t)0; + } + + return (uint64_t)reg_value; +} + +static const VMStateDescription vmstate_sw64_gpio = { + .name = TYPE_SW64_GPIO, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(padr, SW64GPIOState), + VMSTATE_UINT32(paddr, SW64GPIOState), + VMSTATE_UINT32(inter, SW64GPIOState), + VMSTATE_UINT32(intmr, SW64GPIOState), + VMSTATE_UINT32(intlr, SW64GPIOState), + VMSTATE_UINT32(intpr, SW64GPIOState), + VMSTATE_UINT32(intsr, SW64GPIOState), + VMSTATE_UINT32(rintsr, SW64GPIOState), + VMSTATE_UINT32(deber, SW64GPIOState), + VMSTATE_UINT32(clintr, SW64GPIOState), + VMSTATE_UINT32(expar, SW64GPIOState), + VMSTATE_UINT32(synlr, SW64GPIOState), + VMSTATE_UINT32(idcr, SW64GPIOState), + VMSTATE_UINT32(versionr, SW64GPIOState), + VMSTATE_UINT32(conf1r, SW64GPIOState), + VMSTATE_UINT32(conf2r, SW64GPIOState), + VMSTATE_END_OF_LIST() + } +}; + +static void sw64_gpio_reset(DeviceState *dev) +{ + SW64GPIOState *s = SW64_GPIO(dev); + + s->padr = 0; + s->paddr = 0; + s->inter = 0; + s->intmr = 0; + s->intlr = 0; + s->intpr = 0; + s->intsr = 0; + s->rintsr = 0; + s->deber = 0; + s->clintr = 0; + s->expar = 0; + s->synlr = 0; + s->idcr = 0; + s->versionr = 0; + s->conf1r = 0; + s->conf2r = 0; + + sw64_gpio_update_int(s); +} + +static const MemoryRegionOps sw64_gpio_ops = { + .read = sw64_gpio_read, + .write = sw64_gpio_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + + +static void sw64_gpio_realize(DeviceState *dev, Error **errp) +{ + SW64GPIOState *s = SW64_GPIO(dev); + MemoryRegion *sw64_gpio = g_new(MemoryRegion, 1); + memory_region_init_io(sw64_gpio, OBJECT(s), &sw64_gpio_ops, s, + TYPE_SW64_GPIO, SW64_GPIO_MEM_SIZE); + + qdev_init_gpio_in(DEVICE(s), sw64_gpio_set, SW64_GPIO_PIN_COUNT); + qdev_init_gpio_out(DEVICE(s), s->output, SW64_GPIO_PIN_COUNT); + s->irq[0] = qemu_allocate_irq(sw64_gpio_set_irq, s, 15); + memory_region_add_subregion(get_system_memory(), 0x804930000000ULL, + sw64_gpio); +} + +static void sw64_gpio_initfn(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + Error *errp; + sw64_gpio_realize(dev, &errp); +} + + +static void sw64_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sw64_gpio_realize; + dc->reset = sw64_gpio_reset; + dc->vmsd = &vmstate_sw64_gpio; + dc->desc = "SW64 GPIO controller"; +} + +static const TypeInfo sw64_gpio_info = { + .name = TYPE_SW64_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SW64GPIOState), + .instance_init = sw64_gpio_initfn, + .class_init = sw64_gpio_class_init, +}; + +static void sw64_gpio_register_types(void) +{ + type_register_static(&sw64_gpio_info); +} + +type_init(sw64_gpio_register_types) diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build index 4718d143fca582ab1d62867f6c7b37c521f20a78..4536e769914d6d24fd3b81a9dfcd39e8b71d1cf4 100644 --- a/hw/acpi/meson.build +++ b/hw/acpi/meson.build @@ -12,6 +12,8 @@ acpi_ss.add(when: 'CONFIG_ACPI_CPU_HOTPLUG', if_false: files('acpi-cpu-hotplug-s acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_true: files('memory_hotplug.c')) acpi_ss.add(when: 'CONFIG_ACPI_MEMORY_HOTPLUG', if_false: files('acpi-mem-hotplug-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_true: files('nvdimm.c')) +acpi_ss.add(when: 'CONFIG_ACPI_SW64_PM', if_true: files('sw64_pm_device.c')) +acpi_ss.add(when: 'CONFIG_GPIO_SUNWAY', if_true: files('gpio_sunway.c')) acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_false: files('acpi-nvdimm-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCI', if_true: files('pci.c')) acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c')) diff --git a/hw/acpi/sw64_pm_device.c b/hw/acpi/sw64_pm_device.c new file mode 100644 index 0000000000000000000000000000000000000000..6d7c01260d77ddde193406d09249e6071975adc0 --- /dev/null +++ b/hw/acpi/sw64_pm_device.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2022 Wxiat Corporation + * Written by Lufeifei, Min fanlei + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/acpi/acpi.h" +#include "hw/irq.h" +#include "hw/mem/pc-dimm.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "qemu/error-report.h" +#include "hw/sw64/pm.h" +#include "exec/address-spaces.h" +#include "hw/acpi/cpu.h" + +static void sw64_pm_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + SW64PMState *s = SW64_PM(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + PCDIMMDevice *dimm = PC_DIMM(dev); + s->addr = dimm->addr; + s->length = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP, NULL); + s->status = SUNWAY_MEMHOTPLUG_ADD; + s->slot = dimm->slot; + s->node = dimm->node; + + acpi_memory_plug_cb(hotplug_dev, &s->acpi_memory_hotplug, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + s->status = SUNWAY_CPUHOTPLUG_ADD; + s->cpuid = cpu_hot_id; + acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "virt: device plug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void sw64_pm_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + SW64PMState *s = SW64_PM(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + PCDIMMDevice *dimm = PC_DIMM(dev); + s->addr = dimm->addr; + s->slot = dimm->slot; + s->node = dimm->node; + s->length = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP, NULL); + s->status = SUNWAY_MEMHOTPLUG_REMOVE; + + acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + s->status = SUNWAY_CPUHOTPLUG_REMOVE; + s->cpuid = cpu_hot_id; + acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void sw64_pm_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + SW64PMState *s = SW64_PM(hotplug_dev); + + if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) { + acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void sw64_pm_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) +{ + SW64PMState *s = SW64_PM(adev); + + if (!(ev & ACPI_MEMORY_HOTPLUG_STATUS) && !(ev & ACPI_CPU_HOTPLUG_STATUS)) { + /* Unknown event. Return without generating interrupt. */ + warn_report("GED: Uns:upported event %d. No irq injected", ev); + return; + } + + /* Trigger the event by sending an interrupt to the guest. */ + qemu_irq_pulse(s->irq); +} + +static uint64_t pm_read(void *opaque, hwaddr addr, unsigned size) +{ + SW64PMState *s = (SW64PMState *)opaque; + uint64_t ret = 0; + + switch (addr) { + case OFFSET_START_ADDR: + ret = s->addr; + break; + case OFFSET_LENGTH: + ret = s->length; + break; + case OFFSET_STATUS: + ret = s->status; + break; + case OFFSET_SLOT: + ret = s->slot; + break; + case OFFSET_CPUID: + ret = s->cpuid; + break; + case OFFSET_NODE: + ret = s->node; + break; + default: + break; + } + + return ret; +} + +static void pm_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + SW64PMState *s = (SW64PMState *)opaque; + MemStatus *mdev; + AcpiCpuStatus *cdev = NULL; + DeviceState *dev = NULL; + HotplugHandler *hotplug_ctrl = NULL; + Error *local_err = NULL; + + switch (addr) { + case OFFSET_SLOT: + s->acpi_memory_hotplug.selector = val; + mdev = &s->acpi_memory_hotplug.devs[s->acpi_memory_hotplug.selector]; + dev = DEVICE(mdev->dimm); + hotplug_ctrl = qdev_get_hotplug_handler(dev); + /* call pc-dimm unplug cb */ + hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); + object_unparent(OBJECT(dev)); + break; + case OFFSET_CPUID: + s->cpuhp_state.selector = val; + int i; + for (i = 0; i < s->cpuhp_state.dev_count; i++) { + if (s->cpuhp_state.selector == s->cpuhp_state.devs[i].arch_id) { + cdev = &s->cpuhp_state.devs[i]; + } + } + dev = DEVICE(cdev->cpu); + hotplug_ctrl = qdev_get_hotplug_handler(dev); + hotplug_handler_unplug(hotplug_ctrl, dev, &local_err); + object_unparent(OBJECT(dev)); + break; + default: + break; + } +} + +const MemoryRegionOps sw64_pm_hotplug_ops = { + .read = pm_read, + .write = pm_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + + +void sw64_cpu_hotplug_hw_init(CPUHotplugState *state, hwaddr base_addr) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *id_list; + int i; + + assert(mc->possible_cpu_arch_ids); + id_list = mc->possible_cpu_arch_ids(machine); + state->dev_count = id_list->len; + state->devs = g_new0(typeof(*state->devs), state->dev_count); + for (i = 0; i < id_list->len; i++) { + state->devs[i].cpu = CPU(id_list->cpus[i].cpu); + state->devs[i].arch_id = id_list->cpus[i].arch_id; + } +} + +void sw64_acpi_switch_to_modern_cphp(CPUHotplugState *cpuhp_state, + uint16_t io_port) +{ + sw64_cpu_hotplug_hw_init(cpuhp_state, io_port); +} + +static void sw64_set_cpu_hotplug_legacy(Object *obj, bool value) +{ + DeviceState *dev = DEVICE(obj); + SW64PMState *s = SW64_PM(dev); + assert(!value); + if (s->cpu_hotplug_legacy && value == false) { + sw64_acpi_switch_to_modern_cphp(&s->cpuhp_state, 0); + } + s->cpu_hotplug_legacy = value; +} + +static void sw64_pm_initfn(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + SW64PMState *s = SW64_PM(dev); + MemoryRegion *pm_hotplug = g_new(MemoryRegion, 1); + + s->irq = qemu_allocate_irq(sw64_pm_set_irq, s, 13); + + memory_region_init_io(pm_hotplug, OBJECT(s), &sw64_pm_hotplug_ops, s, + "sw64_pm_hotplug", 4 * 1024 * 1024); + memory_region_add_subregion(get_system_memory(), 0x803600000000ULL, + pm_hotplug); + + if (s->acpi_memory_hotplug.is_enabled) { + MachineState *machine = MACHINE(qdev_get_machine()); + MemHotplugState *state = &s->acpi_memory_hotplug; + + state->dev_count = machine->ram_slots; + if (state->dev_count) { + state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); + } + } + + s->cpu_hotplug_legacy = true; + sw64_set_cpu_hotplug_legacy(obj, false); +} + +static Property sw64_pm_properties[] = { + DEFINE_PROP_BOOL("memory-hotplug-support", SW64PMState, + acpi_memory_hotplug.is_enabled, true), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sw64_pm_class_init(ObjectClass *class, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(class); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class); + AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class); + + dc->desc = "SW64 PM"; + device_class_set_props(dc, sw64_pm_properties); + + hc->plug = sw64_pm_device_plug_cb; + hc->unplug_request = sw64_pm_unplug_request_cb; + hc->unplug = sw64_pm_unplug_cb; + + adevc->send_event = sw64_pm_send_event; +} + +static const TypeInfo sw64_pm_info = { + .name = TYPE_SW64_PM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SW64PMState), + .instance_init = sw64_pm_initfn, + .class_init = sw64_pm_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { TYPE_ACPI_DEVICE_IF }, + { } + } +}; + +static void sw64_pm_register_types(void) +{ + type_register_static(&sw64_pm_info); +} + +type_init(sw64_pm_register_types) diff --git a/hw/sw64/Kconfig b/hw/sw64/Kconfig index 0dc49576a55b28e8f68d9aca2a96f86aa881b242..9895723fae01df9061f4b7e07d63056fe43abb99 100644 --- a/hw/sw64/Kconfig +++ b/hw/sw64/Kconfig @@ -5,10 +5,26 @@ config CORE3 imply E1000_PCI select PCI_EXPRESS select SUN4V_RTC + select SMBIOS select VIRTIO_MMIO select SERIAL - select VIRTIO_VGA - select IDE_CMD646 select ISA_BUS select PCKBD select MSI_NONBROKEN + +config CORE4 + bool + imply PCI_DEVICES + imply TEST_DEVICES + imply E1000_PCI + select PCI_EXPRESS + select SUN4V_RTC + select SMBIOS + select VIRTIO_MMIO + select SERIAL + select ISA_BUS + select PCKBD + select MSI_NONBROKEN + select ACPI_NVDIMM + select GPIO_SUNWAY + select ACPI_HW_REDUCED diff --git a/hw/sw64/Makefile.objs b/hw/sw64/Makefile.objs deleted file mode 100644 index 73add9a91d697bebe22dd577e158aca67543e452..0000000000000000000000000000000000000000 --- a/hw/sw64/Makefile.objs +++ /dev/null @@ -1 +0,0 @@ -obj-y += core3.o core3_board.o diff --git a/hw/sw64/core.h b/hw/sw64/core.h deleted file mode 100644 index 49233822299d5b310f9dcc2183f3eae4f692ec69..0000000000000000000000000000000000000000 --- a/hw/sw64/core.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef HW_SW64_SYS_H -#define HW_SW64_SYS_H - -typedef struct boot_params { - unsigned long initrd_size; /* size of initrd */ - unsigned long initrd_start; /* logical address of initrd */ - unsigned long dtb_start; /* logical address of dtb */ - unsigned long efi_systab; /* logical address of EFI system table */ - unsigned long efi_memmap; /* logical address of EFI memory map */ - unsigned long efi_memmap_size; /* size of EFI memory map */ - unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */ - unsigned long efi_memdesc_version; /* memory descriptor version */ - unsigned long cmdline; /* logical address of cmdline */ -} BOOT_PARAMS; - -void core3_board_init(SW64CPU *cpus[4], MemoryRegion *ram); -#endif - -#define MAX_CPUS 64 - -#ifdef CONFIG_KVM -#define MAX_CPUS_CORE3 64 -#else -#define MAX_CPUS_CORE3 32 -#endif diff --git a/hw/sw64/core3.c b/hw/sw64/core3.c index eceeb3bec3ba22740fdfaf76a966fc1bd42373db..1e62f108c1f6257e8faf67216c7732aff2d1e092 100644 --- a/hw/sw64/core3.c +++ b/hw/sw64/core3.c @@ -18,181 +18,84 @@ #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" -#include "hw/ide.h" #include "hw/char/serial.h" #include "qemu/cutils.h" #include "ui/console.h" -#include "core.h" -#include "hw/boards.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.h" #include "sysemu/numa.h" -#include "qemu/uuid.h" -#include "qemu/bswap.h" - -#define VMUUID 0xFF40 - -static uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) -{ - return addr &= ~0xffffffff80000000 ; -} - -static CpuInstanceProperties -sw64_cpu_index_to_props(MachineState *ms, unsigned cpu_index) -{ - MachineClass *mc = MACHINE_GET_CLASS(ms); - const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); - - assert(cpu_index < possible_cpus->len); - return possible_cpus->cpus[cpu_index].props; -} - -static int64_t sw64_get_default_cpu_node_id(const MachineState *ms, int idx) -{ - int nb_numa_nodes = ms->numa_state->num_nodes; - return idx % nb_numa_nodes; -} - -static const CPUArchIdList *sw64_possible_cpu_arch_ids(MachineState *ms) -{ - int i; - unsigned int max_cpus = ms->smp.max_cpus; - - if (ms->possible_cpus) { - /* - * make sure that max_cpus hasn't changed since the first use, i.e. - * -smp hasn't been parsed after it - */ - assert(ms->possible_cpus->len == max_cpus); - return ms->possible_cpus; - } - ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + - sizeof(CPUArchId) * max_cpus); - ms->possible_cpus->len = max_cpus; - for (i = 0; i < ms->possible_cpus->len; i++) { - ms->possible_cpus->cpus[i].type = ms->cpu_type; - ms->possible_cpus->cpus[i].vcpus_count = 1; - ms->possible_cpus->cpus[i].arch_id = i; - ms->possible_cpus->cpus[i].props.has_thread_id = true; - ms->possible_cpus->cpus[i].props.has_core_id = true; - ms->possible_cpus->cpus[i].props.core_id = i; - } - - return ms->possible_cpus; -} - -static void core3_cpu_reset(void *opaque) -{ - SW64CPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} +#define MAX_CPUS_CORE3 64 +#define C3_UEFI_BIOS_NAME "c3-uefi-bios-sw" static void core3_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; - ram_addr_t buf; - SW64CPU *cpus[machine->smp.max_cpus]; - long i, size; const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *hmcode_name = kvm_enabled() ? "core3-reset":"core3-hmcode"; + const char *bios_name = C3_UEFI_BIOS_NAME; + BOOT_PARAMS *sunway_boot_params = g_new0(BOOT_PARAMS, 1); char *hmcode_filename; - char *uefi_filename; - uint64_t hmcode_entry, hmcode_low, hmcode_high; - uint64_t kernel_entry, kernel_low, kernel_high; - BOOT_PARAMS *core3_boot_params = g_new0(BOOT_PARAMS, 1); - uint64_t param_offset; - QemuUUID uuid_out_put; - - memset(cpus, 0, sizeof(cpus)); + uint64_t hmcode_entry, kernel_entry; - for (i = 0; i < machine->smp.cpus; ++i) { - cpus[i] = SW64_CPU(cpu_create(machine->cpu_type)); - cpus[i]->env.csr[CID] = i; - qemu_register_reset(core3_cpu_reset, cpus[i]); - } - core3_board_init(cpus, machine->ram); if (kvm_enabled()) - buf = ram_size; - else - buf = ram_size | (1UL << 63); + sw64_set_clocksource(); - rom_add_blob_fixed("ram_size", (char *)&buf, 0x8, 0x2040); + core3_board_init(machine); - uuid_out_put = qemu_uuid; - uuid_out_put = qemu_uuid_bswap(uuid_out_put); - pstrcpy_targphys("vm-uuid", VMUUID, 0x12, (char *)&(uuid_out_put)); - param_offset = 0x90B000UL; - core3_boot_params->cmdline = param_offset | 0xfff0000000000000UL; - rom_add_blob_fixed("core3_boot_params", (core3_boot_params), 0x48, 0x90A100); + sw64_set_ram_size(ram_size); + sw64_clear_smp_rcb(); - hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, kvm_enabled() ? "core3-reset":"core3-hmcode"); + hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, hmcode_name); if (hmcode_filename == NULL) { - if (kvm_enabled()) - error_report("no core3-reset provided"); - else - error_report("no core3-hmcode provided"); + error_report("no '%s' provided", hmcode_name); exit(1); } - size = load_elf(hmcode_filename, NULL, cpu_sw64_virt_to_phys, NULL, - &hmcode_entry, &hmcode_low, &hmcode_high, NULL, 0, EM_SW64, 0, 0); - if (size < 0) { - if (kvm_enabled()) - error_report("could not load core3-reset: '%s'", hmcode_filename); - else - error_report("could not load core3-hmcode: '%s'", hmcode_filename); - exit(1); + sw64_load_hmcode(hmcode_filename, &hmcode_entry); + + if (!kvm_enabled()) { + CPUState *cpu; + SW64CPU *sw64_cpu; + CPU_FOREACH(cpu) { + sw64_cpu = SW64_CPU(cpu); + sw64_cpu->env.pc = hmcode_entry; + sw64_cpu->env.hm_entry = hmcode_entry; + sw64_cpu->env.csr[CID] = sw64_cpu->core_id; + qemu_register_reset(sw64_cpu_reset, sw64_cpu); + } } g_free(hmcode_filename); - /* Start all cpus at the hmcode RESET entry point. */ - for (i = 0; i < machine->smp.cpus; ++i) { - if (kvm_enabled()) - cpus[i]->env.pc = init_pc; - else - cpus[i]->env.pc = hmcode_entry; - cpus[i]->env.hm_entry = hmcode_entry; + if (!kernel_filename) + sw64_find_and_load_bios(bios_name); + else { + sw64_clear_uefi_bios(); + sw64_load_kernel(kernel_filename, &kernel_entry, kernel_cmdline); + + if (initrd_filename) { + sw64_load_initrd(initrd_filename, sunway_boot_params); + } } - if (!kernel_filename) { - uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "uefi-bios-sw"); - if (uefi_filename == NULL) { - error_report("no virtual bios provided"); - exit(1); - } - size = load_image_targphys(uefi_filename, 0x2f00000UL, -1); - if (size < 0) { - error_report("could not load virtual bios: '%s'", uefi_filename); - exit(1); - } - g_free(uefi_filename); - } else { - /* Load a kernel. */ - size = load_elf(kernel_filename, NULL, cpu_sw64_virt_to_phys, NULL, - &kernel_entry, &kernel_low, &kernel_high, NULL, 0, EM_SW64, 0, 0); - if (size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - cpus[0]->env.trap_arg1 = kernel_entry; - if (kernel_cmdline) - pstrcpy_targphys("cmdline", param_offset, 0x400, kernel_cmdline); + if (sw64_load_dtb(machine, sunway_boot_params) < 0) { + exit(1); } -} -static void board_reset(MachineState *state) -{ - qemu_devices_reset(); + rom_add_blob_fixed("sunway_boot_params", (sunway_boot_params), 0x48, 0x90A100); } -static void core3_machine_init(MachineClass *mc) +static void core3_machine_class_init(ObjectClass *oc, void *data) { - mc->desc = "core3 BOARD"; + MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "CORE3 BOARD"; mc->init = core3_init; - mc->block_default_type = IF_IDE; + mc->block_default_type = IF_VIRTIO; mc->max_cpus = MAX_CPUS_CORE3; + mc->no_cdrom = 1; mc->pci_allow_0_address = true; - mc->is_default = 0; - mc->reset = board_reset; + mc->reset = sw64_board_reset; mc->possible_cpu_arch_ids = sw64_possible_cpu_arch_ids; mc->cpu_index_to_instance_props = sw64_cpu_index_to_props; mc->default_cpu_type = SW64_CPU_TYPE_NAME("core3"); @@ -200,4 +103,15 @@ static void core3_machine_init(MachineClass *mc) mc->get_default_cpu_node_id = sw64_get_default_cpu_node_id; } -DEFINE_MACHINE("core3", core3_machine_init) +static const TypeInfo core3_machine_info = { + .name = TYPE_CORE3_MACHINE, + .parent = TYPE_MACHINE, + .class_init = core3_machine_class_init, + .instance_size = sizeof(CORE3MachineState), +}; + +static void core3_machine_init(void) +{ + type_register_static(&core3_machine_info); +} +type_init(core3_machine_init); diff --git a/hw/sw64/core3_board.c b/hw/sw64/core3_board.c index 7f623cf773bc39064a9587ee2cb5300d201eb8f3..92cd5cf4ef9eb5c879911d0d506b029246821c12 100644 --- a/hw/sw64/core3_board.c +++ b/hw/sw64/core3_board.c @@ -1,7 +1,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" -#include "core.h" +#include "hw/sw64/core.h" #include "hw/hw.h" #include "hw/boards.h" #include "sysemu/sysemu.h" @@ -12,19 +12,17 @@ #include "hw/irq.h" #include "net/net.h" #include "hw/usb.h" -#include "hw/ide/pci.h" -#include "hw/ide/ahci.h" #include "sysemu/numa.h" #include "sysemu/kvm.h" #include "sysemu/cpus.h" #include "hw/pci/msi.h" #include "hw/sw64/sw64_iommu.h" +#include "hw/sw64/sunway.h" #include "hw/loader.h" #include "hw/nvram/fw_cfg.h" - -#define TYPE_SWBOARD_PCI_HOST_BRIDGE "core_board-pcihost" -#define SWBOARD_PCI_HOST_BRIDGE(obj) \ - OBJECT_CHECK(BoardState, (obj), TYPE_SWBOARD_PCI_HOST_BRIDGE) +#include "hw/firmware/smbios.h" +#include "sysemu/device_tree.h" +#include "qemu/datadir.h" #define CORE3_MAX_CPUS_MASK 0x3ff #define CORE3_CORES_SHIFT 10 @@ -32,67 +30,33 @@ #define CORE3_THREADS_SHIFT 20 #define CORE3_THREADS_MASK 0xfff -#define MAX_IDE_BUS 2 -#define SW_PIN_TO_IRQ 16 - -#define SW_FW_CFG_P_BASE (0x804920000000ULL) - -typedef struct SWBoard { - SW64CPU *cpu[MAX_CPUS_CORE3]; -} SWBoard; - -typedef struct BoardState { - PCIHostState parent_obj; - - SWBoard sboard; - uint64_t expire_time; -} BoardState; - -typedef struct TimerState { - void *opaque; - int order; -} TimerState; - -static void sw_create_fw_cfg(hwaddr addr) -{ - MachineState *ms = MACHINE(qdev_get_machine()); - uint16_t smp_cpus = ms->smp.cpus; - FWCfgState *fw_cfg; - fw_cfg = fw_cfg_init_mem_wide(addr + 8, addr, 8, addr + 16, &address_space_memory); - fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, smp_cpus); - rom_set_fw(fw_cfg); -} - -#ifndef CONFIG_KVM -static void swboard_alarm_timer(void *opaque) -{ - TimerState *ts = (TimerState *)((uintptr_t)opaque); - BoardState *bs = (BoardState *)((uintptr_t)ts->opaque); - - int cpu = ts->order; - cpu_interrupt(CPU(bs->sboard.cpu[cpu]), CPU_INTERRUPT_TIMER); -} -#endif - -static PCIINTxRoute sw_route_intx_pin_to_irq(void *opaque, int pin) -{ - PCIINTxRoute route; +static const MemMapEntry memmap[] = { + [VIRT_PCIE_MMIO] = { 0xe0000000, 0x20000000 }, + [VIRT_MSI] = { 0x8000fee00000, 0x100000 }, + [VIRT_INTPU] = { 0x802a00000000, 0x100000 }, + [VIRT_MCU] = { 0x803000000000, 0x1000000 }, + [VIRT_RTC] = { 0x804910000000, 0x8 }, + [VIRT_FW_CFG] = { 0x804920000000, 0x18 }, + [VIRT_PCIE_IO_BASE] = { 0x880000000000, 0x890000000000 }, + [VIRT_PCIE_PIO] = { 0x880100000000, 0x100000000 }, + [VIRT_UART] = { 0x8801000003f8, 0x10 }, + [VIRT_PCIE_CFG] = { 0x880600000000, 0x100000000 }, + [VIRT_HIGH_PCIE_MMIO] = { 0x888000000000, 0x8000000000 }, +}; - route.mode = PCI_INTX_ENABLED; - route.irq = SW_PIN_TO_IRQ; - return route; -} +static const int irqmap[] = { + [VIRT_UART] = 12, + [VIRT_SUNWAY_GED] = 13, +}; -static uint64_t convert_bit(int n) +static void core3_virt_build_smbios(CORE3MachineState *core3ms) { - uint64_t ret; + FWCfgState *fw_cfg = core3ms->fw_cfg; - if (n == 64) - ret = 0xffffffffffffffffUL; - else - ret = (1UL << n) - 1; + if (!fw_cfg) + return; - return ret; + sw64_virt_build_smbios(fw_cfg); } static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) @@ -104,46 +68,25 @@ static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) unsigned int max_cpus = ms->smp.max_cpus; uint64_t ret = 0; switch (addr) { - case 0x0000: - /* CG_ONLINE */ - { - int i; - for (i = 0; i < smp_cpus; i = i + 4) - ret |= (1UL << i); - } - break; case 0x0080: /* SMP_INFO */ - ret = (smp_threads & CORE3_THREADS_MASK) << CORE3_THREADS_SHIFT; - ret += (smp_cores & CORE3_CORES_MASK) << CORE3_CORES_SHIFT; - ret += max_cpus & CORE3_MAX_CPUS_MASK; + { + ret = (smp_threads & CORE3_THREADS_MASK) << CORE3_THREADS_SHIFT; + ret += (smp_cores & CORE3_CORES_MASK) << CORE3_CORES_SHIFT; + ret += max_cpus & CORE3_MAX_CPUS_MASK; + } break; - /*IO_START*/ - case 0x1300: - ret = 0x1; - break; - case 0x3780: - /* MC_ONLINE */ - ret = convert_bit(smp_cpus); - break; - case 0x0900: - /* CPUID */ - ret = 0; - break; - case 0x1180: - /* LONGTIME */ - ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 80; - break; - case 0x4900: - /* MC_CONFIG */ + case 0x0680: + /* INIT_CTL */ + ret = 0x3ae0000ddd9; break; case 0x0780: /* CORE_ONLINE */ ret = convert_bit(smp_cpus); break; - case 0x0680: - /* INIT_CTL */ - ret = 0x000003AE00000D28; + case 0x3780: + /* MC_ONLINE */ + ret = convert_bit(smp_cpus); break; default: fprintf(stderr, "Unsupported MCU addr: 0x%04lx\n", addr); @@ -154,12 +97,14 @@ static uint64_t mcu_read(void *opaque, hwaddr addr, unsigned size) static void mcu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { -#ifndef CONFIG_KVM #ifdef CONFIG_DUMP_PRINTK uint64_t print_addr; uint32_t len; int i; + if (kvm_enabled()) + return; + if (addr == 0x40000) { print_addr = val & 0x7fffffff; len = (uint32_t)(val >> 32); @@ -174,7 +119,6 @@ static void mcu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) return; } #endif -#endif } static const MemoryRegionOps mcu_ops = { @@ -196,35 +140,36 @@ static const MemoryRegionOps mcu_ops = { static uint64_t intpu_read(void *opaque, hwaddr addr, unsigned size) { uint64_t ret = 0; -#ifndef CONFIG_KVM + + if (kvm_enabled()) + return ret; + switch (addr) { case 0x180: /* LONGTIME */ ret = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 32; break; } -#endif return ret; } static void intpu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { -#ifndef CONFIG_KVM - BoardState *bs = (BoardState *)opaque; - SW64CPU *cpu; + SW64CPU *cpu_current = SW64_CPU(current_cpu); + + if (kvm_enabled()) + return; + switch (addr) { case 0x00: - val &= 0x1f; - cpu = bs->sboard.cpu[val]; - cpu->env.csr[II_REQ] = 0x100000; - cpu_interrupt(CPU(cpu),CPU_INTERRUPT_II0); - break; + cpu_interrupt(qemu_get_cpu(val & 0x3f), CPU_INTERRUPT_II0); + cpu_current->env.csr[II_REQ] &= ~(1 << 20); + break; default: fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); break; } -#endif } static const MemoryRegionOps intpu_ops = { @@ -243,309 +188,227 @@ static const MemoryRegionOps intpu_ops = { }, }; -static MemTxResult msi_read(void *opaque, hwaddr addr, - uint64_t *data, unsigned size, - MemTxAttrs attrs) +static void create_fdt_misc_platform(CORE3MachineState *c3ms) { - return MEMTX_OK; + char *nodename; + MachineState *ms = MACHINE(c3ms); + + nodename = g_strdup_printf("/soc/misc_platform@0"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "sunway,misc-platform"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", 0); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,spbu_base", + 2, c3ms->memmap[VIRT_MCU].base); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,intpu_base", + 2, c3ms->memmap[VIRT_INTPU].base); + g_free(nodename); } -MemTxResult msi_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size, - MemTxAttrs attrs) +static void core3_create_fdt(CORE3MachineState *c3ms) { -#ifdef CONFIG_KVM - int ret = 0; - MSIMessage msg = {}; + uint32_t intc_phandle; + MachineState *ms = MACHINE(c3ms); - msg.address = (uint64_t) addr + 0x8000fee00000; - msg.data = (uint32_t) value; + if (ms->dtb) { + char *filename; - ret = kvm_irqchip_send_msi(kvm_state, msg); - if (ret < 0) { - fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n", - strerror(-ret)); - } -#endif - return MEMTX_OK; -} + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ms->dtb); + if (!filename) { + fprintf(stderr, "Couldn't open dtb file %s\n", ms->dtb); + exit(1); + } -static const MemoryRegionOps msi_ops = { - .read_with_attrs = msi_read, - .write_with_attrs = msi_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = - { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = - { - .min_access_size = 1, - .max_access_size = 8, - }, -}; + ms->fdt = load_device_tree(ms->dtb, &c3ms->fdt_size); + if (!ms->fdt) { + error_report("load_device_tree() failed"); + exit(1); + } + } else { + ms->fdt = create_device_tree(&c3ms->fdt_size); + if (!ms->fdt) { + error_report("create_device_tree() failed"); + exit(1); + } -static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size) -{ - uint64_t val = get_clock_realtime() / NANOSECONDS_PER_SECOND; - return val; + qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "sunway,chip3"); + qemu_fdt_setprop_string(ms->fdt, "/", "model", "chip3"); + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + + qemu_fdt_add_subnode(ms->fdt, "/chosen"); + + qemu_fdt_add_subnode(ms->fdt, "/soc"); + qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus"); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2); + qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0); + + intc_phandle = qemu_fdt_alloc_phandle(ms->fdt); + qemu_fdt_add_subnode(ms->fdt, "/soc/interrupt-controller"); + qemu_fdt_setprop_string(ms->fdt, "/soc/interrupt-controller", + "compatible", "sw64,pintc_vt"); + qemu_fdt_setprop(ms->fdt, "/soc/interrupt-controller", + "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,node", 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,irq-num", 16); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,ver", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "#interrupt-cells", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "phandle", intc_phandle); + + qemu_fdt_add_subnode(ms->fdt, "/soc/serial0@8801"); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#size-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "compatible", "ns16550a"); + qemu_fdt_setprop_sized_cells(ms->fdt, "/soc/serial0@8801", "reg", + 2, c3ms->memmap[VIRT_UART].base, + 2, c3ms->memmap[VIRT_UART].size); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupt-parent", intc_phandle); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupts", c3ms->irqmap[VIRT_UART]); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", "reg-shift", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "reg-io-width", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "clock-frequency", 24000000); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "status", "okay"); + } + create_fdt_misc_platform(c3ms); } -static void rtc_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) +static void core3_cpus_init(MachineState *ms) { -} - -static const MemoryRegionOps rtc_ops = { - .read = rtc_read, - .write = rtc_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = - { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = - { - .min_access_size = 1, - .max_access_size = 8, - }, -}; + int i; + const CPUArchIdList *possible_cpus; + MachineClass *mc = MACHINE_GET_CLASS(ms); -static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) -{ - return 1; + possible_cpus = mc->possible_cpu_arch_ids(ms); + for (i = 0; i < ms->smp.cpus; i++) { + sw64_new_cpu("core3-sw64-cpu", possible_cpus->cpus[i].arch_id, &error_fatal); + } } -static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) +void core3_board_init(MachineState *ms) { -} - -const MemoryRegionOps core3_pci_ignore_ops = { - .read = ignore_read, - .write = ignore_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = - { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = - { - .min_access_size = 1, - .max_access_size = 8, - }, -}; + CORE3MachineState *core3ms = CORE3_MACHINE(ms); + DeviceState *dev = qdev_new(TYPE_CORE3_BOARD); + BoardState *bs = CORE3_BOARD(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(dev); + PCIBus *b; -static uint64_t config_read(void *opaque, hwaddr addr, unsigned size) -{ - PCIBus *b = opaque; - uint32_t trans_addr = 0; - trans_addr |= ((addr >> 16) & 0xffff) << 8; - trans_addr |= (addr & 0xff); - return pci_data_read(b, trans_addr, size); -} + core3ms->memmap = memmap; + core3ms->irqmap = irqmap; -static void config_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - PCIBus *b = opaque; - uint32_t trans_addr = 0; - trans_addr |= ((addr >> 16) & 0xffff) << 8; - trans_addr |= (addr & 0xff); - pci_data_write(b, trans_addr, val, size); -} + /* Create device tree */ + core3_create_fdt(core3ms); -const MemoryRegionOps core3_pci_config_ops = { - .read = config_read, - .write = config_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = - { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = - { - .min_access_size = 1, - .max_access_size = 8, - }, -}; + core3_cpus_init(ms); -static void cpu_irq_change(SW64CPU *cpu, uint64_t req) -{ - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - if (req) - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + if (kvm_enabled()) { + if (kvm_has_gsi_routing()) + msi_nonbroken = true; } -} + else + sw64_create_alarm_timer(ms, bs); + + memory_region_add_subregion(get_system_memory(), 0, ms->ram); + + memory_region_init_io(&bs->io_mcu, NULL, &mcu_ops, bs, "io_mcu", + memmap[VIRT_MCU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_MCU].base, + &bs->io_mcu); + + memory_region_init_io(&bs->io_intpu, NULL, &intpu_ops, bs, "io_intpu", + memmap[VIRT_INTPU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_INTPU].base, + &bs->io_intpu); + + memory_region_init_io(&bs->msi_ep, NULL, &msi_ops, bs, "msi_ep", + memmap[VIRT_MSI].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_MSI].base, + &bs->msi_ep); + + memory_region_init(&bs->mem_ep, OBJECT(bs), "pci0-mem", + memmap[VIRT_PCIE_IO_BASE].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_IO_BASE].base, &bs->mem_ep); + + memory_region_init_alias(&bs->mem_ep64, NULL, "mem_ep64", &bs->mem_ep, + memmap[VIRT_HIGH_PCIE_MMIO].base, + memmap[VIRT_HIGH_PCIE_MMIO].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_HIGH_PCIE_MMIO].base, &bs->mem_ep64); + + memory_region_init_io(&bs->io_ep, OBJECT(bs), &sw64_pci_ignore_ops, NULL, + "pci0-io-ep", memmap[VIRT_PCIE_PIO].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_PCIE_PIO].base, + &bs->io_ep); + + b = pci_register_root_bus(dev, "pcie.0", sw64_board_set_irq, + sw64_board_map_irq, bs, + &bs->mem_ep, &bs->io_ep, 0, 537, TYPE_PCIE_BUS); + phb->bus = b; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + pci_bus_set_route_irq_fn(b, sw64_route_intx_pin_to_irq); + memory_region_init_io(&bs->conf_piu0, OBJECT(bs), &sw64_pci_config_ops, b, + "pci0-ep-conf-io", memmap[VIRT_PCIE_CFG].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_PCIE_CFG].base, + &bs->conf_piu0); + sw64_init_rtc_base_info(); + memory_region_init_io(&bs->io_rtc, OBJECT(bs), &rtc_ops, b, + "sw64-rtc", memmap[VIRT_RTC].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_RTC].base, + &bs->io_rtc); + object_property_add_tm(OBJECT(core3ms), "rtc-time", rtc_get_time); +#ifdef CONFIG_SW64_VT_IOMMU + sw64_vt_iommu_init(b); +#endif -static void swboard_set_irq(void *opaque, int irq, int level) -{ - BoardState *bs = opaque; - SW64CPU *cpu; - int i; + sw64_create_pcie(bs, b, phb); - if (kvm_enabled()) { - if (level == 0) - return; - kvm_set_irq(kvm_state, irq, level); - return; - } + core3ms->fw_cfg = sw64_create_fw_cfg(memmap[VIRT_FW_CFG].base, + memmap[VIRT_FW_CFG].size); + rom_set_fw(core3ms->fw_cfg); - for (i = 0; i < 1; i++) { - cpu = bs->sboard.cpu[i]; - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - if (level) - cpu_interrupt(cs, CPU_INTERRUPT_PCIE); - else - cpu_reset_interrupt(cs, CPU_INTERRUPT_PCIE); - } - } + core3_virt_build_smbios(core3ms); } -static int swboard_map_irq(PCIDevice *d, int irq_num) -{ - /* In fact,the return value is the interrupt type passed to kernel, - * so it must keep same with the type in do_entInt in kernel. - */ - return 16; -} +static Property core3_main_pci_host_props[] = { + DEFINE_PROP_UINT32("ofw-addr", BoardState, ofw_addr, 0), + DEFINE_PROP_END_OF_LIST() +}; -static void serial_set_irq(void *opaque, int irq, int level) +static char *core3_main_ofw_unit_address(const SysBusDevice *dev) { - BoardState *bs = (BoardState *)opaque; - MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cpus = ms->smp.cpus; - int i; - if (level == 0) - return; - if (kvm_enabled()) { - kvm_set_irq(kvm_state, irq, level); - return; - } - for (i = 0; i < smp_cpus; i++) { - if (bs->sboard.cpu[i]) - cpu_irq_change(bs->sboard.cpu[i], 1); - } + BoardState *s = CORE3_BOARD(dev); + return g_strdup_printf("%x", s->ofw_addr); } -void core3_board_init(SW64CPU *cpus[MAX_CPUS], MemoryRegion *ram) +static void core3_board_pcihost_class_init(ObjectClass *obj, void *data) { - DeviceState *dev; - BoardState *bs; -#ifndef CONFIG_KVM - TimerState *ts; -#endif - MemoryRegion *io_mcu = g_new(MemoryRegion, 1); - MemoryRegion *io_intpu = g_new(MemoryRegion, 1); - MemoryRegion *msi_ep = g_new(MemoryRegion, 1); - qemu_irq serial_irq; - uint64_t MB = 1024 * 1024; - MemoryRegion *mem_ep = g_new(MemoryRegion, 1); - MemoryRegion *mem_ep64 = g_new(MemoryRegion, 1); - MemoryRegion *conf_piu0 = g_new(MemoryRegion, 1); - MemoryRegion *io_ep = g_new(MemoryRegion, 1); - MemoryRegion *io_rtc = g_new(MemoryRegion, 1); - MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cpus = ms->smp.cpus; - - PCIBus *b; - PCIHostState *phb; - uint64_t GB = 1024 * MB; - - int i; - dev = qdev_new(TYPE_SWBOARD_PCI_HOST_BRIDGE); - phb = PCI_HOST_BRIDGE(dev); - bs = SWBOARD_PCI_HOST_BRIDGE(dev); - -#ifdef CONFIG_KVM - if (kvm_has_gsi_routing()) - msi_nonbroken = true; -#endif - - for (i = 0; i < smp_cpus; ++i) { - if (cpus[i] == NULL) - continue; - bs->sboard.cpu[i] = cpus[i]; -#ifndef CONFIG_KVM - ts = g_new(TimerState, 1); - ts->opaque = (void *) ((uintptr_t)bs); - ts->order = i; - cpus[i]->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &swboard_alarm_timer, ts); -#endif - } - memory_region_add_subregion(get_system_memory(), 0, ram); - - memory_region_init_io(io_mcu, NULL, &mcu_ops, bs, "io_mcu", 16 * MB); - memory_region_add_subregion(get_system_memory(), 0x803000000000ULL, io_mcu); - - memory_region_init_io(io_intpu, NULL, &intpu_ops, bs, "io_intpu", 1 * MB); - memory_region_add_subregion(get_system_memory(), 0x802a00000000ULL, - io_intpu); - - memory_region_init_io(msi_ep, NULL, &msi_ops, bs, "msi_ep", 1 * MB); - memory_region_add_subregion(get_system_memory(), 0x8000fee00000ULL, msi_ep); - - memory_region_init(mem_ep, OBJECT(bs), "pci0-mem", 0x890000000000ULL); - memory_region_add_subregion(get_system_memory(), 0x880000000000ULL, mem_ep); + DeviceClass *dc = DEVICE_CLASS(obj); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(obj); - memory_region_init_alias(mem_ep64, NULL, "mem_ep64", mem_ep, 0x888000000000ULL, 1ULL << 39); - memory_region_add_subregion(get_system_memory(), 0x888000000000ULL, mem_ep64); - - memory_region_init_io(io_ep, OBJECT(bs), &core3_pci_ignore_ops, NULL, - "pci0-io-ep", 4 * GB); - - memory_region_add_subregion(get_system_memory(), 0x880100000000ULL, io_ep); - b = pci_register_root_bus(dev, "pcie.0", swboard_set_irq, swboard_map_irq, bs, - mem_ep, io_ep, 0, 537, TYPE_PCIE_BUS); - phb->bus = b; - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - pci_bus_set_route_irq_fn(b, sw_route_intx_pin_to_irq); - memory_region_init_io(conf_piu0, OBJECT(bs), &core3_pci_config_ops, b, - "pci0-ep-conf-io", 4 * GB); - memory_region_add_subregion(get_system_memory(), 0x880600000000ULL, - conf_piu0); - memory_region_init_io(io_rtc, OBJECT(bs), &rtc_ops, b, - "sw64-rtc", 0x08ULL); - memory_region_add_subregion(get_system_memory(), 0x804910000000ULL, - io_rtc); -#ifdef SW64_VT_IOMMU - sw64_vt_iommu_init(b); -#endif - for (i = 0; i < nb_nics; i++) { - pci_nic_init_nofail(&nd_table[i], b, "e1000", NULL); - } - - pci_vga_init(b); -#define MAX_SATA_PORTS 6 - PCIDevice *ahci; - DriveInfo *hd[MAX_SATA_PORTS]; - ahci = pci_create_simple_multifunction(b, PCI_DEVFN(0x1f, 0), true, - TYPE_ICH9_AHCI); - g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci)); - ide_drive_get(hd, ahci_get_num_ports(ahci)); - ahci_ide_create_devs(ahci, hd); - - serial_irq = qemu_allocate_irq(serial_set_irq, bs, 12); - if (serial_hd(0)) { - serial_mm_init(get_system_memory(), 0x3F8 + 0x880100000000ULL, 0, - serial_irq, (1843200 >> 4), serial_hd(0), - DEVICE_LITTLE_ENDIAN); - } - pci_create_simple(phb->bus, -1, "nec-usb-xhci"); - sw_create_fw_cfg(SW_FW_CFG_P_BASE); + dc->props_ = core3_main_pci_host_props; + dc->fw_name = "pci"; + sbc->explicit_ofw_unit_address = core3_main_ofw_unit_address; } static const TypeInfo swboard_pcihost_info = { - .name = TYPE_SWBOARD_PCI_HOST_BRIDGE, + .name = TYPE_CORE3_BOARD, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(BoardState), + .class_init = core3_board_pcihost_class_init, }; static void swboard_register_types(void) diff --git a/hw/sw64/core4.c b/hw/sw64/core4.c new file mode 100644 index 0000000000000000000000000000000000000000..2206edc581c2069cdac390bc30d56ee16f4cc44b --- /dev/null +++ b/hw/sw64/core4.c @@ -0,0 +1,371 @@ +/* + * QEMU CORE4 hardware system emulator. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/datadir.h" +#include "cpu.h" +#include "hw/hw.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/boards.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "sysemu/reset.h" +#include "hw/char/serial.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.h" +#include "sysemu/numa.h" +#include "hw/mem/pc-dimm.h" +#include "qapi/error.h" +#include "sysemu/device_tree.h" +#include "hw/core/cpu.h" +#include "hw/qdev-core.h" + +#define C4_UEFI_BIOS_NAME "c4-uefi-bios-sw" + +static unsigned long cpu_masks[4]; +static int hot_cpu_num; +int cpu_hot_id; + +static void core4_init(MachineState *machine) +{ + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(machine); + assert(possible_cpus->len); + + ram_addr_t ram_size = machine->ram_size; + const char *kernel_filename = machine->kernel_filename; + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + const char *hmcode_name = kvm_enabled() ? "core4-reset":"core4-hmcode"; + const char *bios_name = C4_UEFI_BIOS_NAME; + BOOT_PARAMS *sunway_boot_params = g_new0(BOOT_PARAMS, 1); + char *hmcode_filename; + uint64_t hmcode_entry, kernel_entry; + + core4_board_init(machine); + + sw64_set_ram_size(ram_size); + sw64_clear_smp_rcb(); + sw64_clear_kernel_print(); + + hmcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, hmcode_name); + if (hmcode_filename == NULL) { + error_report("no '%s' provided", hmcode_name); + exit(1); + } + sw64_load_hmcode(hmcode_filename, &hmcode_entry); + + g_free(hmcode_filename); + + if (!kernel_filename) + sw64_find_and_load_bios(bios_name); + else { + sw64_clear_uefi_bios(); + sw64_load_kernel(kernel_filename, &kernel_entry, kernel_cmdline); + + if (initrd_filename) { + unsigned long initrd_end_va; + + sw64_load_initrd(initrd_filename, sunway_boot_params); + initrd_end_va = sunway_boot_params->initrd_start + + (sunway_boot_params->initrd_size & + (~0xfff0000000000000UL)); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-start", + sunway_boot_params->initrd_start); + qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", + initrd_end_va); + } + } + + if (sw64_load_dtb(machine, sunway_boot_params) < 0) { + exit(1); + } + + /* Retained for forward compatibility */ + rom_add_blob_fixed("sunway_boot_params", (sunway_boot_params), 0x48, 0x90A100); + + if (!kvm_enabled()) { + CPUState *cpu; + SW64CPU *sw64_cpu; + CPU_FOREACH(cpu) { + sw64_cpu = SW64_CPU(cpu); + sw64_cpu->env.pc = hmcode_entry; + sw64_cpu->env.hm_entry = hmcode_entry; + sw64_cpu->env.csr[CID] = sw64_cpu->core_id; + qemu_register_reset(sw64_cpu_reset, sw64_cpu); + if (sw64_cpu->core_id == 0) { + sw64_cpu->env.ir[16] = 0xA2024; + sw64_cpu->env.ir[17] = dtb_start_c4; + } + } + } +} + +static void set_on_cpumask(int cpu_num) +{ + set_bit(cpu_num, cpu_masks); +} + +static void set_off_cpumask(int cpu_num) +{ + clear_bit(cpu_num, cpu_masks); +} + +int get_state_cpumask(int cpu_num) +{ + return test_bit(cpu_num, cpu_masks); +} + +static HotplugHandler *sw64_get_hotplug_handler(MachineState *machine, + DeviceState *dev) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) + return HOTPLUG_HANDLER(machine); + + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + return HOTPLUG_HANDLER(machine); + } + + return NULL; +} + +static void core4_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) + pc_dimm_pre_plug(PC_DIMM(dev), ms, NULL, &local_err); + + return; +} + +static CPUArchId *sw64_find_cpu_slot(MachineState *ms, uint32_t id) +{ + if (id >= ms->possible_cpus->len) { + return NULL; + } + if (hot_cpu_num < ms->smp.cpus) { + ++hot_cpu_num; + } + set_on_cpumask(id); + return &ms->possible_cpus->cpus[id]; +} + +static void sw64_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + uint16_t smp_cpus = ms->smp.cpus; + CPUArchId *found_cpu; + HotplugHandlerClass *hhc; + Error *local_err = NULL; + CPUState *cs = NULL; + SW64CPU *cpu = NULL; + CORE4MachineState *pcms = CORE4_MACHINE(hotplug_dev); + + if (pcms->acpi_dev) { + if (get_state_cpumask(cpu_hot_id)) { + error_setg(&local_err, "error: Unable to add already online cpu!"); + return; + } + + hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev); + hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); + if (local_err) { + goto out; + } + } + + cs = CPU(dev); + cpu = SW64_CPU(dev); + if (hot_cpu_num < smp_cpus) { + cs->cpu_index = hot_cpu_num; + cpu->core_id = hot_cpu_num; + found_cpu = sw64_find_cpu_slot(MACHINE(pcms), hot_cpu_num); + } else { + hot_cpu_num = smp_cpus; + cs->cpu_index = cpu_hot_id; + cpu->core_id = cpu_hot_id; + found_cpu = sw64_find_cpu_slot(MACHINE(pcms), cpu_hot_id); + } + if (!found_cpu) { + error_setg(&local_err, "error: No slot found for new hot add cpu!"); + return; + } + found_cpu->cpu = OBJECT(dev); +out: + error_propagate(errp, local_err); +} + +static void sw64_qdev_unrealize(DeviceState *dev) +{ + Error *err = NULL; + object_property_set_bool(OBJECT(dev), "realized", false, &err); +} + + +static void sw64_cpu_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + Error *local_err = NULL; + SW64CPU *cpu = NULL; + CPUState *cs = NULL; + HotplugHandlerClass *hhc; + CORE4MachineState *pcms = CORE4_MACHINE(hotplug_dev); + + if (!pcms->acpi_dev) { + error_setg(&local_err, "CPU hot unplug not supported without ACPI"); + goto out; + } + + cpu = SW64_CPU(dev); + cpu_hot_id = cpu->core_id; + cs = CPU(dev); + cs->cpu_index = cpu_hot_id; + + if (!cpu_hot_id) { + error_setg(&local_err, "Boot CPU is unpluggable"); + goto out; + } + + if (!get_state_cpumask(cpu_hot_id) || !cpu_hot_id) { + error_setg(&local_err, "error:" + "Unable to delete already offline cpu and cpu 0 can not offline!"); + return; + } + + hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev); + hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); + +out: + error_propagate(errp, local_err); +} + +static void core4_machine_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(hotplug_dev); + CORE4MachineState *core4ms = CORE4_MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + pc_dimm_plug(PC_DIMM(dev), ms); + hotplug_handler_plug(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + } + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) + sw64_cpu_plug(hotplug_dev, dev, &local_err); +} + +static void core4_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + CORE4MachineState *core4ms = CORE4_MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + hotplug_handler_unplug_request(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + sw64_cpu_unplug_request(hotplug_dev, dev, &local_err); + } else { + error_setg(&local_err, "device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void core4_machine_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + MachineState *ms = MACHINE(hotplug_dev); + CORE4MachineState *core4ms = CORE4_MACHINE(hotplug_dev); + Error *local_err = NULL; + CPUArchId *found_cpu; + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + hotplug_handler_unplug(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + if (local_err) { + goto out; + } + pc_dimm_unplug(PC_DIMM(dev), MACHINE(ms)); + } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + hotplug_handler_unplug(HOTPLUG_HANDLER(core4ms->acpi_dev), + dev, &local_err); + if (local_err) { + goto out; + } + found_cpu = sw64_find_cpu_slot(MACHINE(core4ms), cpu_hot_id); + found_cpu->cpu = NULL; + sw64_qdev_unrealize(dev); + set_off_cpumask(cpu_hot_id); + } else { + error_setg(&local_err, "device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } + +out: + return; +} + +static void core4_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); + + mc->desc = "CORE4 BOARD"; + mc->init = core4_init; + mc->block_default_type = IF_VIRTIO; + mc->max_cpus = MAX_CPUS_CORE4; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; + mc->reset = sw64_board_reset; + mc->possible_cpu_arch_ids = sw64_possible_cpu_arch_ids; + mc->default_cpu_type = SW64_CPU_TYPE_NAME("core4"); + mc->default_ram_id = "ram"; + mc->cpu_index_to_instance_props = sw64_cpu_index_to_props; + mc->get_default_cpu_node_id = sw64_get_default_cpu_node_id; + mc->get_hotplug_handler = sw64_get_hotplug_handler; + mc->has_hotpluggable_cpus = true; + hc->pre_plug = core4_machine_device_pre_plug_cb; + hc->plug = core4_machine_device_plug_cb; + hc->unplug_request = core4_machine_device_unplug_request_cb; + hc->unplug = core4_machine_device_unplug_cb; + mc->auto_enable_numa = true; +} + +static void core4_machine_initfn(Object *obj) +{ + CORE4MachineState *c4ms = CORE4_MACHINE(obj); + + c4ms->oem_id = g_strndup(SW_ACPI_BUILD_APPNAME6, 6); + c4ms->oem_table_id = g_strndup(SW_ACPI_BUILD_APPNAME8, 8); +} + +static const TypeInfo core4_machine_info = { + .name = TYPE_CORE4_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(CORE4MachineState), + .class_size = sizeof(CORE4MachineClass), + .class_init = core4_machine_class_init, + .instance_init = core4_machine_initfn, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, +}; + +static void core4_machine_init(void) +{ + type_register_static(&core4_machine_info); +} + +type_init(core4_machine_init) diff --git a/hw/sw64/core4_board.c b/hw/sw64/core4_board.c new file mode 100644 index 0000000000000000000000000000000000000000..a6e6032cbf990c259bb5a8c435caf7206cd83057 --- /dev/null +++ b/hw/sw64/core4_board.c @@ -0,0 +1,777 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "sysemu/sysemu.h" +#include "exec/address-spaces.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pci.h" +#include "hw/char/serial.h" +#include "hw/irq.h" +#include "net/net.h" +#include "hw/usb.h" +#include "sysemu/numa.h" +#include "sysemu/kvm.h" +#include "hw/pci/msi.h" +#include "sysemu/device_tree.h" +#include "qemu/datadir.h" +#include "hw/sw64/gpio.h" + +#define CORE4_MAX_CPUS_MASK 0x3ff +#define CORE4_CORES_SHIFT 10 +#define CORE4_CORES_MASK 0x3ff +#define CORE4_THREADS_SHIFT 20 +#define CORE4_THREADS_MASK 0xfff + +#define DOMAIN_ID_SHIFT 12 +#define CORE_ID_SHIFT 0 + +static unsigned long coreonlines[4]; + +static const MemMapEntry memmap[] = { + [VIRT_BOOT_FLAG] = { 0x820000, 0x20 }, + [VIRT_PCIE_MMIO] = { 0xe0000000, 0x20000000 }, + [VIRT_MSI] = { 0x8000fee00000, 0x100000 }, + [VIRT_SPBU] = { 0x803000000000, 0x1000000 }, + [VIRT_SUNWAY_GED] = { 0x803600000000, 0x20 }, + [VIRT_INTPU] = { 0x803a00000000, 0x100000 }, + [VIRT_RTC] = { 0x804910000000, 0x8 }, + [VIRT_FW_CFG] = { 0x804920000000, 0x18 }, + [VIRT_GPIO] = { 0x804930000000, 0x0000008000 }, + [VIRT_PCIE_IO_BASE] = { 0x880000000000, 0x890000000000 }, + [VIRT_PCIE_PIO] = { 0x880100000000, 0x100000000 }, + [VIRT_UART] = { 0x8801000003f8, 0x10 }, + [VIRT_PCIE_CFG] = { 0x880600000000, 0x100000000 }, + [VIRT_HIGH_PCIE_MMIO] = { 0x888000000000, 0x8000000000 }, +}; + +static const int irqmap[] = { + [VIRT_UART] = 12, + [VIRT_SUNWAY_GED] = 13, + [VIRT_GPIO] = 15, +}; + +static void core4_virt_build_smbios(CORE4MachineState *core4ms) +{ + FWCfgState *fw_cfg = core4ms->fw_cfg; + + if (!fw_cfg) + return; + + sw64_virt_build_smbios(fw_cfg); +} + +static uint64_t spbu_read(void *opaque, hwaddr addr, unsigned size) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cpus = ms->smp.cpus; + unsigned int smp_threads = ms->smp.threads; + unsigned int smp_cores = ms->smp.cores; + unsigned int max_cpus = ms->smp.max_cpus; + uint64_t ret = 0; + switch (addr) { + case 0x0080: + /* SMP_INFO */ + { + ret = (smp_threads & CORE4_THREADS_MASK) << CORE4_THREADS_SHIFT; + ret += (smp_cores & CORE4_CORES_MASK) << CORE4_CORES_SHIFT; + ret += max_cpus & CORE4_MAX_CPUS_MASK; + } + break; + case 0x0100: + /* VT_ONLINE_CPU */ + ret = smp_cpus; + break; + case 0x3a00: + /* CLU_LV2_SEL_H */ + ret = 1; + break; + case 0x0680: + /* INIT_CTL */ + ret = 0x3ae0007802c; + break; + case 0x0780: + /* CORE_ONLINE */ + ret = convert_bit(max_cpus); + break; + case 0x3780: + /* MC_ONLINE */ + ret = convert_bit(smp_cpus); + break; + default: + fprintf(stderr, "Unsupported MCU addr: 0x%04lx\n", addr); + return -1; + } + return ret; +} + +static void spbu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ +#ifdef CONFIG_DUMP_PRINTK + uint64_t print_addr; + uint32_t len; + int i; + + if (kvm_enabled()) + return; + + if (addr == 0x40000) { + print_addr = val & 0x7fffffff; + len = (uint32_t)(val >> 32); + uint8_t *buf; + buf = malloc(len + 10); + memset(buf, 0, len + 10); + cpu_physical_memory_rw(print_addr, buf, len, 0); + for (i = 0; i < len; i++) + printf("%c", buf[i]); + + free(buf); + return; + } +#endif +} + +static const MemoryRegionOps spbu_ops = { + .read = spbu_read, + .write = spbu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 8, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + +static uint64_t intpu_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t ret = 0; + return ret; +} + +static void intpu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + SW64CPU *cpu_current = SW64_CPU(current_cpu); + + if (kvm_enabled()) + return; + + switch (addr) { + case 0x00: + if (((cpu_current->env.csr[II_REQ] >> 16) & 7) == 6) + cpu_interrupt(qemu_get_cpu(val & 0x3f), CPU_INTERRUPT_IINM); + else + cpu_interrupt(qemu_get_cpu(val & 0x3f), CPU_INTERRUPT_II0); + cpu_current->env.csr[II_REQ] &= ~(1 << 20); + break; + default: + fprintf(stderr, "Unsupported IPU addr: 0x%04lx\n", addr); + break; + } +} + +static const MemoryRegionOps intpu_ops = { + .read = intpu_read, + .write = intpu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 8, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 8, + .max_access_size = 8, + }, +}; + +static void create_fdt_clk(CORE4MachineState *c4ms) +{ + FILE *fp; + char buff[64]; + char *nodename; + unsigned long mclk_hz; + MachineState *ms = MACHINE(c4ms); + + fp = fopen("/sys/kernel/debug/sw64/mclk_hz", "rb"); + if (fp == NULL) { + fprintf(stderr, "%s: Failed to open file mclk_hz\n", __func__); + return; + } + + if (fgets(buff, 64, fp) == NULL) { + fprintf(stderr, "%s: Error in reading mclk_hz\n", __func__); + return; + } + + mclk_hz = atoi(buff); + fclose(fp); + + qemu_fdt_add_subnode(ms->fdt, "/soc/clocks"); + + nodename = g_strdup_printf("/soc/clocks/mclk"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "sw64,mclk"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", mclk_hz); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#clock-cells", 0x0); + qemu_fdt_setprop_string(ms->fdt, nodename, "clock-output-names", "mclk"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/clocks/extclk"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "sw64,extclk"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 0x0); + qemu_fdt_setprop_cell(ms->fdt, nodename, "#clock-cells", 0x0); + qemu_fdt_setprop_string(ms->fdt, nodename, "clock-output-names", "extclk"); + g_free(nodename); +} + +static void core4_set_coreonline(int cpuid) +{ + set_bit(cpuid, coreonlines); +} + +static int core4_get_stat_coreonline(int cpuid) +{ + int ret = test_bit(cpuid, coreonlines); + + clear_bit(cpuid, coreonlines); + return ret; +} + +static void core4_numa_set_coreonlines(MachineState *ms, int node, + unsigned int *logical_core_id, int *coreid_idx) +{ + unsigned int max_cpus = ms->smp.max_cpus; + int i, cpu_node_id, shift = 0; + + for (i = 0; i < max_cpus; i++) { + cpu_node_id = ms->possible_cpus->cpus[i].props.node_id; + + if (cpu_node_id == node) { + core4_set_coreonline(shift); + logical_core_id[*coreid_idx] = i; + shift++; + (*coreid_idx)++; + } + } +} + +static void core4_get_cpu_to_rcid(MachineState *ms, + unsigned long *__cpu_to_rcid) +{ + int nb_numa_nodes = ms->numa_state->num_nodes; + unsigned long rcid[MAX_CPUS_CORE4]; + unsigned int logical_core_id[MAX_CPUS_CORE4]; + int i, j, coreid_idx = 0, cpuid = 0, idx = 0; + + for (i = 0; i < nb_numa_nodes; i++) { + core4_numa_set_coreonlines(ms, i, logical_core_id, &coreid_idx); + + for (j = 0; j < MAX_CPUS_CORE4; j++) { + if (core4_get_stat_coreonline(j)) { + rcid[idx] = (i << DOMAIN_ID_SHIFT) | (j << CORE_ID_SHIFT); + idx++; + } + } + } + + for (i = 0; i < ms->smp.max_cpus; i++) { + cpuid = logical_core_id[i]; + __cpu_to_rcid[cpuid] = rcid[i]; + } + + cpuid = ms->smp.max_cpus; + while (cpuid < MAX_CPUS_CORE4) { + __cpu_to_rcid[cpuid] = -1; + cpuid++; + } +} + +static int core4_fdt_add_memory_node(void *fdt, hwaddr mem_base, + hwaddr mem_len, int numa_node_id) +{ + char *nodename; + int ret; + + nodename = g_strdup_printf("/memory@%" PRIx64, mem_base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); + ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", 2, mem_base, + 2, mem_len); + if (ret < 0) { + goto out; + } + + /* only set the NUMA ID if it is specified */ + if (numa_node_id >= 0) { + ret = qemu_fdt_setprop_cell(fdt, nodename, + "numa-node-id", numa_node_id); + } +out: + g_free(nodename); + return ret; +} + +static void core4_add_memory_node(MachineState *ms) +{ + hwaddr mem_len, mem_start; + int nb_numa_nodes = ms->numa_state->num_nodes; + int i, rc; + + if (ms->numa_state != NULL && nb_numa_nodes > 0) { + for (i = 0; i < nb_numa_nodes; i++) { + mem_len = ms->numa_state->nodes[i].node_mem; + if (!mem_len) { + continue; + } + + if (!i) { + mem_start = 0x910000; + mem_len -= mem_start; + } + + rc = core4_fdt_add_memory_node(ms->fdt, mem_start, mem_len, i); + if (rc < 0) { + fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n", + mem_start); + } + mem_start += mem_len; + } + } +} + +static void core4_add_cpu_node(CORE4MachineState *c4ms) +{ + MachineState *ms = MACHINE(c4ms); + unsigned long __cpu_to_rcid[MAX_CPUS_CORE4]; + char *nodename; + int cpu; + + qemu_fdt_add_subnode(ms->fdt, "/cpus"); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 1); + qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); + + core4_get_cpu_to_rcid(ms, __cpu_to_rcid); + for (cpu = ms->smp.max_cpus - 1; cpu >= 0; cpu--) { + nodename = g_strdup_printf("/cpus/cpu@%d", cpu); + + qemu_fdt_add_subnode(ms->fdt, nodename); + if (ms->possible_cpus->cpus[cpu].props.has_node_id) { + qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", + ms->possible_cpus->cpus[cpu].props.node_id); + } + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sw64,boot_flag_address", + 1, 0x0, 1, c4ms->memmap[VIRT_BOOT_FLAG].base); + qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", __cpu_to_rcid[cpu]); + qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "sw64,junzhang"); + + if (cpu < ms->smp.cpus) { + qemu_fdt_setprop_cell(ms->fdt, nodename, "online-capable", 0); + qemu_fdt_setprop_string(ms->fdt, nodename, "status", "okay"); + } else { + qemu_fdt_setprop_cell(ms->fdt, nodename, "online-capable", 1); + qemu_fdt_setprop_string(ms->fdt, nodename, "status", "disable"); + } + + g_free(nodename); + } +} + +static void core4_add_distance_map_node(MachineState *ms) +{ + int size; + uint32_t *matrix; + int idx, i, j; + int nb_numa_nodes = ms->numa_state->num_nodes; + + if (nb_numa_nodes > 0 && ms->numa_state->have_numa_distance) { + size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); + matrix = g_malloc0(size); + + for (i = 0; i < nb_numa_nodes; i++) { + for (j = 0; j < nb_numa_nodes; j++) { + idx = (i * nb_numa_nodes + j) * 3; + matrix[idx + 0] = cpu_to_be32(i); + } + } + + qemu_fdt_add_subnode(ms->fdt, "/distance-map"); + qemu_fdt_setprop_string(ms->fdt, "/distance-map", "compatible", + "numa-distance-map-v1"); + qemu_fdt_setprop(ms->fdt, "/distance-map", "distance-matrix", + matrix, size); + g_free(matrix); + } +} +static void core4_create_numa_fdt(CORE4MachineState *c4ms) +{ + MachineState *ms = MACHINE(c4ms); + + /* Add memory node information */ + core4_add_memory_node(ms); + /* Add cpus node information */ + core4_add_cpu_node(c4ms); + /* Add distance-map node information */ + core4_add_distance_map_node(ms); +} + +static void create_fdt_misc_platform(CORE4MachineState *c4ms) +{ + char *nodename; + MachineState *ms = MACHINE(c4ms); + + nodename = g_strdup_printf("/soc/misc_platform@0"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "sunway,misc-platform"); + qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", 0); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,spbu_base", + 2, c4ms->memmap[VIRT_SPBU].base); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "sunway,intpu_base", + 2, c4ms->memmap[VIRT_INTPU].base); + g_free(nodename); +} + +static void core4_create_fdt(CORE4MachineState *c4ms) +{ + uint32_t intc_phandle; + MachineState *ms = MACHINE(c4ms); + + if (ms->dtb) { + char *filename; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ms->dtb); + if (!filename) { + fprintf(stderr, "Couldn't open dtb file %s\n", ms->dtb); + exit(1); + } + + ms->fdt = load_device_tree(ms->dtb, &c4ms->fdt_size); + if (!ms->fdt) { + error_report("load_device_tree() failed"); + exit(1); + } + goto update_bootargs; + } else { + ms->fdt = create_device_tree(&c4ms->fdt_size); + if (!ms->fdt) { + error_report("create_device_tree() failed"); + exit(1); + } + + qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "sunway,chip4"); + qemu_fdt_setprop_string(ms->fdt, "/", "model", "chip4"); + qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); + + qemu_fdt_add_subnode(ms->fdt, "/chosen"); + + qemu_fdt_add_subnode(ms->fdt, "/soc"); + qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus"); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2); + qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0); + + intc_phandle = qemu_fdt_alloc_phandle(ms->fdt); + qemu_fdt_add_subnode(ms->fdt, "/soc/interrupt-controller"); + qemu_fdt_setprop_string(ms->fdt, "/soc/interrupt-controller", + "compatible", "sw64,pintc_vt"); + qemu_fdt_setprop(ms->fdt, "/soc/interrupt-controller", + "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,node", 0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,irq-num", 16); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "sw64,ver", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "#interrupt-cells", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/interrupt-controller", + "phandle", intc_phandle); + + qemu_fdt_add_subnode(ms->fdt, "/soc/serial0@8801"); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "#size-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "compatible", "ns16550a"); + qemu_fdt_setprop_sized_cells(ms->fdt, "/soc/serial0@8801", "reg", + 2, c4ms->memmap[VIRT_UART].base, + 2, c4ms->memmap[VIRT_UART].size); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupt-parent", intc_phandle); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "interrupts", c4ms->irqmap[VIRT_UART]); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", "reg-shift", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "reg-io-width", 0x1); + qemu_fdt_setprop_cell(ms->fdt, "/soc/serial0@8801", + "clock-frequency", 20000000); + qemu_fdt_setprop_string(ms->fdt, "/soc/serial0@8801", + "status", "okay"); + + qemu_fdt_add_subnode(ms->fdt, "/soc/misc0@8036"); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "#address-cells", 0x2); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", "#size-cells", 0x2); + qemu_fdt_setprop_string(ms->fdt, "/soc/misc0@8036", + "compatible", "sw6,sunway-ged"); + qemu_fdt_setprop_sized_cells(ms->fdt, "/soc/misc0@8036", "reg", + 2, c4ms->memmap[VIRT_SUNWAY_GED].base, + 2, c4ms->memmap[VIRT_SUNWAY_GED].size); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "interrupt-parent", intc_phandle); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "interrupts", c4ms->irqmap[VIRT_SUNWAY_GED]); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", "reg-shift", 0x0); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", "reg-io-width", 0x8); + qemu_fdt_setprop_cell(ms->fdt, "/soc/misc0@8036", + "clock-frequency", 20000000); + qemu_fdt_setprop_string(ms->fdt, "/soc/misc0@8036", "status", "okay"); + + create_fdt_clk(c4ms); + core4_create_numa_fdt(c4ms); + create_fdt_misc_platform(c4ms); + } + +update_bootargs: + if (ms->kernel_filename) { + qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", ms->kernel_cmdline); + } else + qemu_fdt_setprop_string(ms->fdt, "/chosen", "bootargs", "pcie_ports=native"); + +} + +static void core4_cpus_init(MachineState *ms) +{ + int i; + const CPUArchIdList *possible_cpus; + + MachineClass *mc = MACHINE_GET_CLASS(ms); + possible_cpus = mc->possible_cpu_arch_ids(ms); + + for (i = 0; i < ms->smp.cpus; i++) { + sw64_new_cpu("core4-sw64-cpu", possible_cpus->cpus[i].arch_id, + &error_fatal); + } +} + +void sw64_pm_set_irq(void *opaque, int irq, int level) +{ + if (kvm_enabled()) { + if (level == 0) + return; + kvm_set_irq(kvm_state, irq, level); + return; + } +} + +void sw64_gpio_set_irq(void *opaque, int irq, int level) +{ + if (kvm_enabled()) { + if (level == 0) { + return; + } + kvm_set_irq(kvm_state, irq, level); + return; + } +} + +static inline DeviceState *create_sw64_pm(CORE4MachineState *c4ms) +{ + DeviceState *dev; + + dev = qdev_try_new(TYPE_SW64_PM); + + if (!dev) { + printf("failed to create sw64_pm,Unknown device TYPE_SW64_PM"); + } + return dev; +} + +static inline DeviceState *create_sw64_gpio(CORE4MachineState *c4ms) +{ + DeviceState *dev; + + dev = qdev_try_new(TYPE_SW64_GPIO); + + if (!dev) { + printf("failed to create sw64_gpio,Unknown device TYPE_SW64_GPIO\n"); + } + return dev; +} + +static void sw64_create_device_memory(MachineState *machine, BoardState *bs) +{ + ram_addr_t ram_size = machine->ram_size; + ram_addr_t device_mem_size; + + /* always allocate the device memory information */ + machine->device_memory = g_malloc0(sizeof(*machine->device_memory)); + + /* initialize device memory address space */ + if (machine->ram_size < machine->maxram_size) { + device_mem_size = machine->maxram_size - machine->ram_size; + + if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) { + printf("unsupported amount of memory slots: %"PRIu64, + machine->ram_slots); + exit(EXIT_FAILURE); + } + + if (QEMU_ALIGN_UP(machine->maxram_size, + TARGET_PAGE_SIZE) != machine->maxram_size) { + printf("maximum memory size must by aligned to multiple of " + "%d bytes", TARGET_PAGE_SIZE); + exit(EXIT_FAILURE); + } + + machine->device_memory->base = ram_size; + + memory_region_init(&machine->device_memory->mr, OBJECT(bs), + "device-memory", device_mem_size); + memory_region_add_subregion(get_system_memory(), machine->device_memory->base, + &machine->device_memory->mr); + } +} + +void core4_board_init(MachineState *ms) +{ + CORE4MachineState *core4ms = CORE4_MACHINE(ms); + DeviceState *dev = qdev_new(TYPE_CORE4_BOARD); + BoardState *bs = CORE4_BOARD(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(dev); + PCIBus *b; + + core4ms->memmap = memmap; + core4ms->irqmap = irqmap; + + /* Create device tree */ + core4_create_fdt(core4ms); + + core4ms->acpi_dev = create_sw64_pm(core4ms); + + core4_cpus_init(ms); + + if (kvm_enabled()) { + if (kvm_has_gsi_routing()) + msi_nonbroken = true; + } + else + sw64_create_alarm_timer(ms, bs); + + sw64_create_device_memory(ms, bs); + + memory_region_add_subregion(get_system_memory(), 0, ms->ram); + + memory_region_init_io(&bs->io_spbu, NULL, &spbu_ops, bs, "io_spbu", + memmap[VIRT_SPBU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_SPBU].base, + &bs->io_spbu); + + memory_region_init_io(&bs->io_intpu, NULL, &intpu_ops, bs, "io_intpu", + memmap[VIRT_INTPU].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_INTPU].base, + &bs->io_intpu); + + memory_region_init_io(&bs->msi_ep, NULL, &msi_ops, bs, "msi_ep", + memmap[VIRT_MSI].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_MSI].base, + &bs->msi_ep); + + memory_region_init(&bs->mem_ep, OBJECT(bs), "pci0-mem", + memmap[VIRT_PCIE_IO_BASE].size); + + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_IO_BASE].base, &bs->mem_ep); + + memory_region_init_alias(&bs->mem_ep64, NULL, "mem_ep64", &bs->mem_ep, + memmap[VIRT_PCIE_IO_BASE].base, + memmap[VIRT_PCIE_IO_BASE].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_IO_BASE].base, &bs->mem_ep64); + + memory_region_init_io(&bs->io_ep, OBJECT(bs), &sw64_pci_ignore_ops, NULL, + "pci0-io-ep", memmap[VIRT_PCIE_PIO].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_PCIE_PIO].base, + &bs->io_ep); + + b = pci_register_root_bus(dev, "pcie.0", sw64_board_set_irq, + sw64_board_map_irq, bs, + &bs->mem_ep, &bs->io_ep, 0, 537, TYPE_PCI_BUS); + phb->bus = b; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + pci_bus_set_route_irq_fn(b, sw64_route_intx_pin_to_irq); + memory_region_init_io(&bs->conf_piu0, OBJECT(bs), &sw64_pci_config_ops, b, + "pci0-ep-conf-io", memmap[VIRT_PCIE_CFG].size); + memory_region_add_subregion(get_system_memory(), + memmap[VIRT_PCIE_CFG].base, &bs->conf_piu0); + + sw64_init_rtc_base_info(); + memory_region_init_io(&bs->io_rtc, OBJECT(bs), &rtc_ops, b, + "sw64-rtc", memmap[VIRT_RTC].size); + memory_region_add_subregion(get_system_memory(), memmap[VIRT_RTC].base, + &bs->io_rtc); + object_property_add_tm(OBJECT(core4ms), "rtc-time", rtc_get_time); + + sw64_create_pcie(bs, b, phb); + + core4ms->fw_cfg = sw64_create_fw_cfg(memmap[VIRT_FW_CFG].base, + memmap[VIRT_FW_CFG].size); + rom_set_fw(core4ms->fw_cfg); + + core4ms->gpio_dev = create_sw64_gpio(core4ms); + + core4ms->bus = phb->bus; + sw64_acpi_setup((SW64MachineState *)core4ms); + + core4_virt_build_smbios(core4ms); +} + +static Property core4_main_pci_host_props[] = { + DEFINE_PROP_UINT32("ofw-addr", BoardState, ofw_addr, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static char *core4_main_ofw_unit_address(const SysBusDevice *dev) +{ + BoardState *s = CORE4_BOARD(dev); + return g_strdup_printf("%x", s->ofw_addr); +} + +static void core4_board_pcihost_class_init(ObjectClass *obj, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(obj); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(obj); + + dc->props_ = core4_main_pci_host_props; + dc->fw_name = "pci"; + sbc->explicit_ofw_unit_address = core4_main_ofw_unit_address; +} + +static const TypeInfo swboard_pcihost_info = { + .name = TYPE_CORE4_BOARD, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(BoardState), + .class_init = core4_board_pcihost_class_init, +}; + +static void swboard_register_types(void) +{ + type_register_static(&swboard_pcihost_info); +} + +type_init(swboard_register_types) diff --git a/hw/sw64/gpio.h b/hw/sw64/gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..b523ab879edbe93f3286ea349184b7d67180ff15 --- /dev/null +++ b/hw/sw64/gpio.h @@ -0,0 +1,54 @@ +#ifndef HW_SW64_GPIO_H +#define HW_SW64_GPIO_H + +#include "hw/sysbus.h" + +#define TYPE_SW64_GPIO "SW64_GPIO" +#define SW64_GPIO(obj) OBJECT_CHECK(SW64GPIOState, (obj), TYPE_SW64_GPIO) + +#define GPIO_SWPORTA_DR (0x00UL) +#define GPIO_SWPORTA_DDR (0X200UL) +#define GPIO_INTEN (0X1800UL) +#define GPIO_INTMASK (0X1a00UL) +#define GPIO_INTTYPE_LEVEL (0x1c00UL) +#define GPIO_INTTYPE_POLA (0x1e00UL) +#define GPIO_INTTYPE_STATUS (0x2000UL) +#define GPIO_RAW_INTTYPE_STATUS (0x2200UL) +#define GPIO_DEB_ENABLE (0x2400UL) +#define GPIO_CLEAN_INT (0x2600UL) +#define GPIO_EXT_PORTA (0x2800UL) +#define GPIO_SYNC_LEVEL (0x3000UL) +#define GPIO_ID_CODE (0x3200UL) +#define GPIO_VERSION (0x3600UL) +#define GPIO_CONF_R1 (0x3a00UL) +#define GPIO_CONF_R2 (0x3800UL) + +#define SW64_GPIO_MEM_SIZE 0x8000 +#define SW64_GPIO_PIN_COUNT 1 + +typedef struct SW64GPIOState { + SysBusDevice parent_obj; + + uint32_t padr; + uint32_t paddr; + uint32_t inter; + uint32_t intmr; + uint32_t intlr; + uint32_t intpr; + uint32_t intsr; + uint32_t rintsr; + uint32_t deber; + uint32_t clintr; + uint32_t expar; + uint32_t synlr; + uint32_t idcr; + uint32_t versionr; + uint32_t conf1r; + uint32_t conf2r; + + qemu_irq irq[SW64_GPIO_PIN_COUNT]; + qemu_irq output[SW64_GPIO_PIN_COUNT]; +} SW64GPIOState; + +void sw64_gpio_set_irq(void *opaque, int irq, int level); +#endif diff --git a/hw/sw64/meson.build b/hw/sw64/meson.build index 8abb18222a5ae67e0d32c81a9af002589f65e1a5..456eb0290be125eb49f39c58f9f3405bc67e646b 100644 --- a/hw/sw64/meson.build +++ b/hw/sw64/meson.build @@ -1,10 +1,17 @@ sw64_ss = ss.source_set() -sw64_ss.add(files('sw64_iommu.c')) +sw64_ss.add(files('sunway.c'), fdt) +sw64_ss.add(when: 'CONFIG_SW64_VT_IOMMU', if_true: files('sw64_iommu.c')) +sw64_ss.add(when: 'CONFIG_ACPI', if_true: files('sw64-acpi-build.c')) sw64_ss.add(when: 'CONFIG_CORE3', if_true: files( 'core3.c', 'core3_board.c', )) +sw64_ss.add(when: 'CONFIG_CORE4', if_true: files( + 'core4.c', + 'core4_board.c', +)) + hw_arch += {'sw64': sw64_ss} diff --git a/hw/sw64/pm.h b/hw/sw64/pm.h new file mode 100644 index 0000000000000000000000000000000000000000..242fef0946993be84f6f4c0d920b44f7af4c400e --- /dev/null +++ b/hw/sw64/pm.h @@ -0,0 +1,59 @@ +#ifndef HW_SW64_PM_H +#define HW_SW64_PM_H + +#include "hw/sysbus.h" +#include "hw/acpi/memory_hotplug.h" + +#include "hw/acpi/cpu_hotplug.h" +#include "hw/acpi/cpu.h" +#include "hw/irq.h" +#include "hw/acpi/acpi_dev_interface.h" +#include "hw/core/cpu.h" +#include "qemu/option.h" +#include "qemu/option_int.h" +#include "qemu/config-file.h" +#include "qapi/qmp/qdict.h" + +#define SUNWAY_CPUHOTPLUG_ADD 0x4 +#define SUNWAY_CPUHOTPLUG_REMOVE 0x8 +#define OFFSET_CPUID 0x20 + +extern int cpu_hot_id; +int get_state_cpumask(int cpu_num); +void sw64_cpu_hotplug_hw_init(CPUHotplugState *state, hwaddr base_addr); +void sw64_acpi_switch_to_modern_cphp(CPUHotplugState *cpuhp_state, uint16_t io_port); + +#define OFFSET_START_ADDR 0x0 +#define OFFSET_LENGTH 0x8 +#define OFFSET_STATUS 0x10 +#define OFFSET_SLOT 0x18 + +#define OFFSET_NODE 0x28 + +#define SUNWAY_MEMHOTPLUG_ADD 0x1 +#define SUNWAY_MEMHOTPLUG_REMOVE 0x2 + +typedef struct SW64PMState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + qemu_irq irq; + MemHotplugState acpi_memory_hotplug; + unsigned long addr; + unsigned long length; + unsigned long status; + unsigned long slot; + unsigned long cpuid; + unsigned long node; + bool cpu_hotplug_legacy; + AcpiCpuHotplug gpe_cpu; + CPUHotplugState cpuhp_state; +} SW64PMState; + +#define TYPE_SW64_PM "SW64_PM" + +DECLARE_INSTANCE_CHECKER(SW64PMState, SW64_PM, TYPE_SW64_PM) + +void sw64_pm_set_irq(void *opaque, int irq, int level); +#endif diff --git a/hw/sw64/sunway.c b/hw/sw64/sunway.c new file mode 100644 index 0000000000000000000000000000000000000000..b16a5787d7a2f826065fa257e9c7cc7311045075 --- /dev/null +++ b/hw/sw64/sunway.c @@ -0,0 +1,626 @@ +/* + * QEMU SUNWAY syetem helper. + * + * Copyright (c) 2023 Lu Feifei + * + * This work is licensed under the GNU GPL license version 2 or later. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/datadir.h" +#include "qapi/error.h" +#include "cpu.h" +#include "hw/hw.h" +#include "hw/irq.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/boards.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "sysemu/reset.h" +#include "hw/char/serial.h" +#include "hw/pci/msi.h" +#include "hw/firmware/smbios.h" +#include "hw/nvram/fw_cfg.h" +#include "qemu/cutils.h" +#include "ui/console.h" +#include "hw/sw64/core.h" +#include "hw/sw64/sunway.h" +#include "sysemu/numa.h" +#include "net/net.h" +#include "sysemu/device_tree.h" +#include + +#define SW_PIN_TO_IRQ 16 +#define SW_FDT_BASE 0x2d00000ULL +#define SW_BIOS_BASE 0x2f00000ULL +#define SW_INITRD_BASE 0x3000000UL + +static uint64_t base_rtc; +static uint64_t last_update; +unsigned long dtb_start_c4; + +void sw64_init_rtc_base_info(void) +{ + struct tm tm; + qemu_get_timedate(&tm, 0); + base_rtc = mktimegm(&tm); + last_update = get_clock_realtime() / NANOSECONDS_PER_SECOND; +} + +static uint64_t rtc_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t val; + uint64_t guest_clock = get_clock_realtime() / NANOSECONDS_PER_SECOND; + + val = base_rtc + guest_clock - last_update; + + return val; +} + +static void rtc_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ +} + +const MemoryRegionOps rtc_ops = { + .read = rtc_read, + .write = rtc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size) +{ + return 1; +} + +static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size) +{ +} + +const MemoryRegionOps sw64_pci_ignore_ops = { + .read = ignore_read, + .write = ignore_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static uint64_t config_read(void *opaque, hwaddr addr, unsigned size) +{ + PCIBus *b = opaque; + uint32_t trans_addr = 0; + + trans_addr |= ((addr >> 16) & 0xffff) << 8; + trans_addr |= (addr & 0xff); + + return pci_data_read(b, trans_addr, size); +} + +static void config_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + PCIBus *b = opaque; + uint32_t trans_addr = 0; + + trans_addr |= ((addr >> 16) & 0xffff) << 8; + trans_addr |= (addr & 0xff); + + pci_data_write(b, trans_addr, val, size); +} + +const MemoryRegionOps sw64_pci_config_ops = { + .read = config_read, + .write = config_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static MemTxResult msi_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + return MEMTX_OK; +} + +MemTxResult msi_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + int ret = 0; + MSIMessage msg = {}; + + if (!kvm_enabled()) + return MEMTX_DECODE_ERROR; + + msg.address = (uint64_t) addr + 0x8000fee00000; + msg.data = (uint32_t) value; + + ret = kvm_irqchip_send_msi(kvm_state, msg); + if (ret < 0) { + fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n", + strerror(-ret)); + } + + return MEMTX_OK; +} + +const MemoryRegionOps msi_ops = { + .read_with_attrs = msi_read, + .write_with_attrs = msi_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = + { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = + { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr) +{ + return addr &= ~0xffffffff80000000 ; +} + +CpuInstanceProperties +sw64_cpu_index_to_props(MachineState *ms, unsigned cpu_index) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); + + assert(cpu_index < possible_cpus->len); + return possible_cpus->cpus[cpu_index].props; +} + +int64_t sw64_get_default_cpu_node_id(const MachineState *ms, int idx) +{ + int nb_numa_nodes = ms->numa_state->num_nodes; + return idx % nb_numa_nodes; +} + +const CPUArchIdList *sw64_possible_cpu_arch_ids(MachineState *ms) +{ + int i; + unsigned int max_cpus = ms->smp.max_cpus; + + if (ms->possible_cpus) { + /* + * make sure that max_cpus hasn't changed since the first use, i.e. + * -smp hasn't been parsed after it + */ + assert(ms->possible_cpus->len == max_cpus); + return ms->possible_cpus; + } + + ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; + for (i = 0; i < ms->possible_cpus->len; i++) { + ms->possible_cpus->cpus[i].type = ms->cpu_type; + ms->possible_cpus->cpus[i].vcpus_count = 1; + ms->possible_cpus->cpus[i].arch_id = i; + ms->possible_cpus->cpus[i].props.has_thread_id = true; + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.has_socket_id = true; + ms->possible_cpus->cpus[i].props.core_id = i; + ms->possible_cpus->cpus[i].props.thread_id = 0; + ms->possible_cpus->cpus[i].props.socket_id = 0; + } + + return ms->possible_cpus; +} + +void sw64_cpu_reset(void *opaque) +{ + SW64CPU *cpu = opaque; + + if (!kvm_enabled()) + cpu_reset(CPU(cpu)); + + return; +} + +void sw64_set_clocksource(void) +{ + FILE *fp; + unsigned long mclk; + char buff[64]; + + fp = fopen("/sys/kernel/debug/sw64/mclk", "rb"); + if (fp == NULL) { + printf("Failed to open file mclk \n"); + return; + } + + if (fgets(buff, 64, fp) == NULL) { + printf("Error in reading mclk \n"); + return; + } + + mclk = atoi(buff); + fclose(fp); + rom_add_blob_fixed("mclk", (char *)&mclk, 0x8, 0x908001); +} + +void sw64_board_reset(MachineState *state) +{ + qemu_devices_reset(); +} + +void sw64_set_ram_size(ram_addr_t ram_size) +{ + ram_addr_t buf; + + if (kvm_enabled()) + buf = ram_size; + else + buf = ram_size | (1UL << 63); + + rom_add_blob_fixed("ram_size", (char *)&buf, 0x8, 0x2040); + + return; +} + +void sw64_clear_uefi_bios(void) +{ + unsigned long uefi_bios[1] = {0}; + + /* Clear the first 8 bytes of UEFI BIOS to ensure the correctness + * of reset process. + * */ + rom_add_blob_fixed("uefi_bios", uefi_bios, 0x8, SW_BIOS_BASE); + + return; +} + +void sw64_clear_smp_rcb(void) +{ + unsigned long smp_rcb[4] = {0}; + + /* Clear the smp_rcb fields to ensure the correctness of reset process. */ + rom_add_blob_fixed("smp_rcb", smp_rcb, 0x20, 0x820000); + + return; +} + +void sw64_clear_kernel_print(void) +{ + unsigned long kernel_print[2048] = {0}; + + /* + * Clear the memory where the kernel is printed when the vm reboots + * will make debugging easier. + */ + rom_add_blob_fixed("kernel_print", kernel_print, 0x4000, 0x700000); + + return; +} + +void sw64_load_hmcode(const char *hmcode_filename, uint64_t *hmcode_entry) +{ + long size; + + size = load_elf(hmcode_filename, NULL, cpu_sw64_virt_to_phys, NULL, + hmcode_entry, NULL, NULL, NULL, 0, EM_SW64, 0, 0); + if (size < 0) { + error_report("could not load hmcode: '%s'", hmcode_filename); + exit(1); + } + + return; +} + +void sw64_find_and_load_bios(const char *bios_name) +{ + char *uefi_filename; + long size; + + uefi_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (uefi_filename == NULL) { + error_report("no virtual bios provided"); + exit(1); + } + + size = load_image_targphys(uefi_filename, SW_BIOS_BASE, -1); + if (size < 0) { + error_report("could not load virtual bios: '%s'", uefi_filename); + exit(1); + } + + g_free(uefi_filename); + return; +} + +void sw64_load_kernel(const char *kernel_filename, uint64_t *kernel_entry, + const char *kernel_cmdline) +{ + long size; + uint64_t param_offset; + + size = load_elf(kernel_filename, NULL, cpu_sw64_virt_to_phys, NULL, + kernel_entry, NULL, NULL, NULL, 0, EM_SW64, 0, 0); + if (size < 0) { + error_report("could not load kernel '%s'", kernel_filename); + exit(1); + } + + if (kernel_cmdline) { + param_offset = 0x90B000UL; + pstrcpy_targphys("cmdline", param_offset, 0x400, kernel_cmdline); + } + + return; +} + +void sw64_load_initrd(const char *initrd_filename, + BOOT_PARAMS *sunway_boot_params) +{ + long initrd_size; + + initrd_size = get_image_size(initrd_filename); + if (initrd_size < 0) { + error_report("could not load initial ram disk '%s'", + initrd_filename); + exit(1); + } + /* Put the initrd image as high in memory as possible. */ + load_image_targphys(initrd_filename, SW_INITRD_BASE, initrd_size); + sunway_boot_params->initrd_start = SW_INITRD_BASE | 0xfff0000000000000UL; + sunway_boot_params->initrd_size = initrd_size; + + return; +} + +int sw64_load_dtb(MachineState *ms, BOOT_PARAMS *sunway_boot_params) +{ + int ret, fdt_size; + hwaddr fdt_base; + + if (ms->kernel_filename) { + /* For direct kernel boot, place the DTB after the initrd to avoid + * overlaying the loaded kernel. + */ + sunway_boot_params->dtb_start = (SW_INITRD_BASE | 0xfff0000000000000UL) + + sunway_boot_params->initrd_size; + } else { + /* For BIOS boot, place the DTB at SW_FDT_BASE temporarily, the + * bootloader will move it to a more proper place later. + */ + sunway_boot_params->dtb_start = SW_FDT_BASE | 0xfff0000000000000UL; + } + + if (!ms->fdt) { + fprintf(stderr, "Board was unable to create a dtb blob\n"); + return -1; + } + + ret = fdt_pack(ms->fdt); + /* Should only fail if we've built a corrupted tree */ + g_assert(ret == 0); + fdt_size = fdt_totalsize(ms->fdt); + qemu_fdt_dumpdtb(ms->fdt, fdt_size); + + /* Put the DTB into the memory map as a ROM image: this will ensure + * the DTB is copied again upon reset, even if addr points into RAM. + */ + fdt_base = sunway_boot_params->dtb_start & (~0xfff0000000000000UL); + + dtb_start_c4 = sunway_boot_params->dtb_start; + + rom_add_blob_fixed("dtb", ms->fdt, fdt_size, fdt_base); + + return 0; +} + +void sw64_board_alarm_timer(void *opaque) +{ + TimerState *ts = (TimerState *)((uintptr_t)opaque); + + if (!kvm_enabled()) { + int cpu = ts->order; + cpu_interrupt(qemu_get_cpu(cpu), CPU_INTERRUPT_TIMER); + } + + return; +} + +void sw64_create_alarm_timer(MachineState *ms, BoardState *bs) +{ + TimerState *ts; + SW64CPU *cpu; + int i; + + for (i = 0; i < ms->smp.cpus; ++i) { + cpu = SW64_CPU(qemu_get_cpu(i)); + ts = g_new(TimerState, 1); + ts->opaque = (void *) ((uintptr_t)bs); + ts->order = i; + cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + &sw64_board_alarm_timer, ts); + } +} + +PCIINTxRoute sw64_route_intx_pin_to_irq(void *opaque, int pin) +{ + PCIINTxRoute route; + + route.mode = PCI_INTX_ENABLED; + route.irq = SW_PIN_TO_IRQ; + return route; +} + +uint64_t convert_bit(int n) +{ + uint64_t ret; + + if (n == 64) + ret = 0xffffffffffffffffUL; + else + ret = (1UL << n) - 1; + + return ret; +} + +FWCfgState *sw64_create_fw_cfg(hwaddr addr, hwaddr size) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + uint16_t smp_cpus = ms->smp.cpus; + FWCfgState *fw_cfg; + + fw_cfg = fw_cfg_init_mem_wide(addr + 8, addr, 8, + addr + 16, &address_space_memory); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, smp_cpus); + + if (!ms->dtb) { + char *nodename; + + nodename = g_strdup_printf("/soc/fw_cfg@8049"); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, + "compatible", "qemu,fw-cfg-mmio"); + qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, + "reg", 2, addr, 2, size); + g_free(nodename); + } + + return fw_cfg; +} + +void sw64_virt_build_smbios(FWCfgState *fw_cfg) +{ + uint8_t *smbios_tables, *smbios_anchor; + size_t smbios_tables_len, smbios_anchor_len; + const char *product = "QEMU Virtual Machine"; + + if (kvm_enabled()) + product = "KVM Virtual Machine"; + + smbios_set_defaults("QEMU", product, + "sw64", false, + true, SMBIOS_ENTRY_POINT_30); + + smbios_get_tables(MACHINE(qdev_get_machine()), NULL, 0, + &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len, + &error_fatal); + + if (smbios_anchor) { + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } + + return; +} + +void sw64_board_set_irq(void *opaque, int irq, int level) +{ + if (level == 0) + return; + + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + + cpu_interrupt(qemu_get_cpu(0), CPU_INTERRUPT_PCIE); +} + +int sw64_board_map_irq(PCIDevice *d, int irq_num) +{ + /* In fact,the return value is the interrupt type passed to kernel, + * so it must keep same with the type in do_entInt in kernel. + */ + return 16; +} + +void serial_set_irq(void *opaque, int irq, int level) +{ + if (level == 0) + return; + + if (kvm_enabled()) { + kvm_set_irq(kvm_state, irq, level); + return; + } + + cpu_interrupt(qemu_get_cpu(0), CPU_INTERRUPT_HARD); +} + +void sw64_new_cpu(const char *name, int64_t arch_id, Error **errp) +{ + Object *cpu = NULL; + Error *local_err = NULL; + + cpu = object_new(name); + object_property_set_uint(cpu, "core-id", arch_id, &local_err); + object_property_set_bool(cpu, "realized", true, &local_err); + + object_unref(cpu); + error_propagate(errp, local_err); +} + +void sw64_create_pcie(BoardState *bs, PCIBus *b, PCIHostState *phb) +{ + int i; + + for (i = 0; i < nb_nics; i++) { + pci_nic_init_nofail(&nd_table[i], b, "e1000", NULL); + } + + pci_vga_init(b); + + bs->serial_irq = qemu_allocate_irq(serial_set_irq, bs, 12); + if (serial_hd(0)) { + serial_mm_init(get_system_memory(), 0x3F8 + 0x880100000000ULL, 0, + bs->serial_irq, (1843200 >> 4), serial_hd(0), + DEVICE_LITTLE_ENDIAN); + } + + pci_create_simple(phb->bus, -1, "nec-usb-xhci"); +} + +void rtc_get_time(Object *obj, struct tm *current_tm, Error **errp) +{ + time_t guest_sec; + int64_t guest_nsec; + + guest_nsec = get_clock_realtime(); + guest_sec = guest_nsec / NANOSECONDS_PER_SECOND; + gmtime_r(&guest_sec, current_tm); +} diff --git a/hw/sw64/sw64-acpi-build.c b/hw/sw64/sw64-acpi-build.c new file mode 100644 index 0000000000000000000000000000000000000000..02a6368caa4ffe016ee1bd8f4b98d300edd1209f --- /dev/null +++ b/hw/sw64/sw64-acpi-build.c @@ -0,0 +1,872 @@ +/* Support for generating ACPI tables and passing them to Guests + * + * SW64 ACPI generation + * + * Copyright (C) 2023 Wang Yuanheng + * + * This work is licensed under the GNU GPL license version 2 or later. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/bitmap.h" +#include "hw/core/cpu.h" +#include "target/sw64/cpu.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/acpi/acpi.h" +#include "hw/nvram/fw_cfg.h" +#include "hw/acpi/bios-linker-loader.h" +#include "hw/acpi/aml-build.h" +#include "hw/acpi/utils.h" +#include "hw/acpi/pci.h" +#include "hw/acpi/memory_hotplug.h" +#include "hw/acpi/generic_event_device.h" +#include "hw/acpi/tpm.h" +#include "hw/pci/pcie_host.h" +#include "hw/acpi/aml-build.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci-host/gpex.h" +#include "hw/sw64/core.h" +#include "hw/platform-bus.h" +#include "sysemu/numa.h" +#include "sysemu/reset.h" +#include "sysemu/tpm.h" +#include "kvm_sw64.h" +#include "migration/vmstate.h" +#include "hw/acpi/ghes.h" +#include "hw/sw64/gpio.h" +#include "hw/irq.h" +#include "sysemu/runstate.h" + +#define SW64_PCIE_IRQMAP 16 +#define SW64_MCU_GSI_BASE 64 +#define ACPI_BUILD_TABLE_SIZE 0x20000 + +static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + uint32_t uart_irq) +{ + Aml *method, *dev, *crs; + Aml *pkg; + Aml *pkg0, *pkg1, *pkg2, *pkg3; + + dev = aml_device("COM0"); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, uart_memmap->base, + uart_memmap->base + uart_memmap->size - 1, + 0, uart_memmap->size)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &uart_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("clock-frequency")); + aml_append(pkg0, aml_int(20000000)); + + pkg1 = aml_package(0x2); + aml_append(pkg1, aml_string("reg-io-width")); + aml_append(pkg1, aml_int(0x1)); + + pkg2 = aml_package(0x2); + aml_append(pkg2, aml_string("reg-shift")); + aml_append(pkg2, aml_int(0x0)); + + pkg3 = aml_package(0x3); + aml_append(pkg3, pkg0); + aml_append(pkg3, pkg1); + aml_append(pkg3, pkg2); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg3); + + aml_append(dev, aml_name_decl("_DSD", pkg)); /* Device-Specific Data */ + aml_append(scope, dev); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); +} + +static void acpi_dsdt_add_sunway_ged(Aml *scope, const MemMapEntry *ged_memmap, + uint32_t ged_irq) +{ + Aml *method, *dev, *crs; + Aml *pkg, *pkg0; + + dev = aml_device("SMHP"); + aml_append(dev, aml_name_decl("_HID", aml_string("SUNW1000"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, ged_memmap->base, + ged_memmap->base + ged_memmap->size - 1, + 0, ged_memmap->size)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &ged_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("clock-frequency")); + aml_append(pkg0, aml_int(20000000)); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg0); + + aml_append(dev, aml_name_decl("_DSD", pkg)); + aml_append(scope, dev); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); +} + + +static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) +{ + Aml *dev = aml_device("FWCF"); + aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + + Aml *crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, fw_cfg_memmap->base, + fw_cfg_memmap->base + fw_cfg_memmap->size - 1, + 0, fw_cfg_memmap->size)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + +static void acpi_dsdt_add_pci_osc(Aml *dev) +{ + Aml *method, *UUID, *ifctx, *ifctx1, *elsectx; + + /* Declare an _OSC (OS Control Handoff) method */ + aml_append(dev, aml_name_decl("SUPP", aml_int(0))); + aml_append(dev, aml_name_decl("CTRL", aml_int(0))); + method = aml_method("_OSC", 4, AML_NOTSERIALIZED); + aml_append(method, + aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); + + /* PCI Firmware Specification 3.0 + * 4.5.1. _OSC Interface for PCI Host Bridge Devices + * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is + * identified by the Universal Unique IDentifier (UUID) + * 33DB4D5B-1FF7-401C-9657-7441C03DD766 + */ + UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"); + ifctx = aml_if(aml_equal(aml_arg(0), UUID)); + aml_append(ifctx, + aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); + aml_append(ifctx, + aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); + aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); + aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); + /* + * Allow OS control for all 5 features: + * PCIeHotplug SHPCHotplug PME AER PCIeCapability. + */ + aml_append(ifctx, aml_and(aml_name("CTRL"), aml_int(0x1F), + aml_name("CTRL"))); + + ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); + aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08), + aml_name("CDW1"))); + aml_append(ifctx, ifctx1); + + ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL")))); + aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x10), + aml_name("CDW1"))); + aml_append(ifctx, ifctx1); + + aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3"))); + aml_append(ifctx, aml_return(aml_arg(3))); + aml_append(method, ifctx); + + elsectx = aml_else(); + aml_append(elsectx, aml_or(aml_name("CDW1"), aml_int(4), + aml_name("CDW1"))); + aml_append(elsectx, aml_return(aml_arg(3))); + aml_append(method, elsectx); + aml_append(dev, method); +} + +static void acpi_dsdt_add_pci(Aml *scope, uint32_t irq, SW64MachineState *vms) +{ + CrsRangeEntry *entry; + Aml *dev, *rbuf, *method, *crs; + CrsRangeSet crs_range_set; + int i; + Aml *pkg0, *pkg1, *pkg; + + struct GPEXConfig cfg = { + .mmio32 = vms->memmap[VIRT_PCIE_MMIO], + .mmio64 = vms->memmap[VIRT_HIGH_PCIE_MMIO], + .pio = vms->memmap[VIRT_PCIE_PIO], + .ecam = vms->memmap[VIRT_PCIE_CFG], + .irq = irq, + .bus = vms->bus, + }; + + /* PCI0 */ + dev = aml_device("PCI0"); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08"))); + aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); + aml_append(dev, aml_name_decl("_SEG", aml_int(0))); + aml_append(dev, aml_name_decl("_BBN", aml_int(0))); + method = aml_method("_PXM", 0, AML_SERIALIZED); + aml_append(method, aml_return(aml_int(0x0))); + aml_append(dev, method); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); + + pkg1 = aml_package(0x9); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,rc_config_base")); + aml_append(pkg0, aml_int(0x0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_config_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_CFG].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_mem_32_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_IO_BASE].base + | vms->memmap[VIRT_PCIE_MMIO].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_mem_64_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_HIGH_PCIE_MMIO].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,ep_io_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_PIO].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,piu_ior0_base")); + aml_append(pkg0, aml_int(0x0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,piu_ior1_base")); + aml_append(pkg0, aml_int(0x0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,rc_index")); + aml_append(pkg0, aml_int(0)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sw64,pcie_io_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_PCIE_IO_BASE].base)); + aml_append(pkg1, pkg0); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg1); + aml_append(dev, aml_name_decl("_DSD", pkg)); + + rbuf = aml_resource_template(); + aml_append(dev, aml_name_decl("CRS0", rbuf)); + aml_append(rbuf, + aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, + 0x0000, 0x0000, 0xFF, 0x0000, 0x100)); + crs_range_set_init(&crs_range_set); + if (cfg.mmio32.size) { + crs_replace_with_free_ranges(crs_range_set.mem_ranges, + cfg.mmio32.base, + cfg.mmio32.base + cfg.mmio32.size - 1); + for (i = 0; i < crs_range_set.mem_ranges->len; i++) { + entry = g_ptr_array_index(crs_range_set.mem_ranges, i); + aml_append(rbuf, + aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, + entry->base, entry->limit, + 0x0000, entry->limit - entry->base + 1)); + } + } + + if (cfg.pio.size) { + crs_replace_with_free_ranges(crs_range_set.io_ranges, + cfg.pio.base, + cfg.pio.base + cfg.pio.size - 1); + for (i = 0; i < crs_range_set.io_ranges->len; i++) { + entry = g_ptr_array_index(crs_range_set.io_ranges, i); + aml_append(rbuf, + aml_qword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, + AML_ENTIRE_RANGE, 0x0000, entry->base, + entry->limit, 0x0000, + entry->limit - entry->base + 1)); + } + } + if (cfg.mmio64.size) { + crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges, + cfg.mmio64.base, + cfg.mmio64.base + cfg.mmio64.size - 1); + for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) { + entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i); + aml_append(rbuf, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, + entry->base, + entry->limit, 0x0000, + entry->limit - entry->base + 1)); + } + } + + method = aml_method("_CRS", 0, AML_SERIALIZED); + aml_append(method, aml_return(rbuf)); + aml_append(dev, method); + acpi_dsdt_add_pci_osc(dev); + + /* RES0 */ + Aml *dev_res0 = aml_device("%s", "RES0"); + aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, + cfg.ecam.base, + cfg.ecam.base + cfg.ecam.size - 1, + 0x0000, + cfg.ecam.size)); + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, dev_res0); + aml_append(scope, dev); + crs_range_set_free(&crs_range_set); +} + +static void +build_srat(GArray *table_data, BIOSLinker *linker, SW64MachineState *vms) +{ + int i; + uint64_t mem_base; + MachineClass *mc = MACHINE_GET_CLASS(vms); + MachineState *ms = MACHINE(vms); + const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms); + AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + + acpi_table_begin(&table, table_data); + build_append_int_noprefix(table_data, 1, 4); /* Reserved */ + build_append_int_noprefix(table_data, 0, 8); /* Reserved */ + + for (i = 0; i < cpu_list->len; ++i) { + uint32_t node_id = cpu_list->cpus[i].props.node_id; + + /* CPU Affinity Structure */ + build_append_int_noprefix(table_data, 2, 1); /* Type */ + build_append_int_noprefix(table_data, 24, 1); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + /* Proximity Domain */ + build_append_int_noprefix(table_data, node_id, 4); + build_append_int_noprefix(table_data, i, 4); /* APIC ID */ + /* Flags */ + build_append_int_noprefix(table_data, 1 /* Enabled */, 4); + build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */ + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + } + + /* Memory Affinity Structure */ + mem_base = 0; + for (i = 0; i < ms->numa_state->num_nodes; ++i) { + if (ms->numa_state->nodes[i].node_mem > 0) { + build_srat_memory(table_data, mem_base, + ms->numa_state->nodes[i].node_mem, i, + MEM_AFFINITY_ENABLED); + mem_base += ms->numa_state->nodes[i].node_mem; + } + } + + if (ms->device_memory) { + build_srat_memory(table_data, ms->device_memory->base, + memory_region_size(&ms->device_memory->mr), + ms->numa_state->num_nodes - 1, + MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + } + + acpi_table_end(linker, &table); +} + +static void build_append_mcu_intc(GArray *table_data) +{ + build_append_int_noprefix(table_data, 0x0, 1); /* Type: MCU INTC */ + build_append_int_noprefix(table_data, 1, 1); /* Status */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, 0xf0000001, 4);/* Hardware ID */ + build_append_int_noprefix(table_data, 0, 8); /* Address Base */ + build_append_int_noprefix(table_data, 0, 4); /* Size */ + build_append_int_noprefix(table_data, SW64_MCU_GSI_BASE, 4); /* GSI Base */ + build_append_int_noprefix(table_data, 16, 4); /* GSI Count */ + build_append_int_noprefix(table_data, 0, 4); /* Cascade Vector */ +} + +static void +build_madt(GArray *table_data, BIOSLinker *linker, SW64MachineState *vms) +{ + int i; + const MemMapEntry *memmap = vms->memmap; + MachineState *ms = MACHINE(vms); + unsigned int num_cpus = ms->smp.max_cpus; + uint32_t flags, enabled, virt, online_capable; + AcpiTable table = { .sig = "APIC", .rev = 4, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + + acpi_table_begin(&table, table_data); + + /* Local Interrupt Controller Address */ + build_append_int_noprefix(table_data, 0, 4); + /* Flags */ + build_append_int_noprefix(table_data, 0, 4); + + /* CINTC Structure */ + for (i = 0; i < num_cpus; i++) { + SW64CPU *sw64cpu = SW64_CPU(qemu_get_cpu(i)); + enabled = sw64cpu ? 1 : 0; + online_capable = !enabled << 1; + virt = 0x1 << 2; + flags = virt | online_capable | enabled; + + build_append_int_noprefix(table_data, 0x80, 1); /* Type */ + build_append_int_noprefix(table_data, 28, 1); /* Length */ + build_append_int_noprefix(table_data, 0x2, 1); /* Version */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + build_append_int_noprefix(table_data, flags, 4);/* Flags */ + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + build_append_int_noprefix(table_data, i, 4); /* Hardware ID */ + build_append_int_noprefix(table_data, 0, 4); /* ACPI Processor UID */ + + /* Boot Flag Address */ + if (i) { + build_append_int_noprefix(table_data, 0, 8); + } else { + build_append_int_noprefix(table_data, + memmap[VIRT_BOOT_FLAG].base, 8); + } + } + + /* PINTC Structure */ + build_append_int_noprefix(table_data, 0x81, 1); /* Type */ + build_append_int_noprefix(table_data, 60, 1); /* Length */ + build_append_int_noprefix(table_data, 0x2, 1); /* Version */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + /* Flags */ + build_append_int_noprefix(table_data, 0x3 /* Enabled && Virtual */, 4); + build_append_int_noprefix(table_data, 0, 4); /* Node */ + build_append_int_noprefix(table_data, 0, 8); /* Address Base */ + build_append_int_noprefix(table_data, 0, 4); /* Size*/ + /* Number of sub Interrupt Controller, only support MCU INTC now */ + build_append_int_noprefix(table_data, 1, 4); /* N */ + + /* Sub PINTC Structure[0]: MCU INTC */ + build_append_mcu_intc(table_data); + + /* MSIC Structure */ + build_append_int_noprefix(table_data, 0x82, 1); /* Type */ + build_append_int_noprefix(table_data, 56, 1); /* Length */ + build_append_int_noprefix(table_data, 0x2, 1); /* Version */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + build_append_int_noprefix(table_data, 0xf2000001, 4); /* Hardware ID */ + /* Flags */ + build_append_int_noprefix(table_data, 0x3 /* Enabled && Virtual */, 4); + build_append_int_noprefix(table_data, 0, 8); /* Address Base */ + build_append_int_noprefix(table_data, 0, 4); /* Size*/ + build_append_int_noprefix(table_data, 0, 4); /* Cascade Vector */ + build_append_int_noprefix(table_data, 0, 4); /* Node */ + build_append_int_noprefix(table_data, 0, 4); /* RC */ + build_append_int_noprefix(table_data, 256, 4); /* Number of Interrupt */ + build_append_int_noprefix(table_data, + memmap[VIRT_MSI].base, 8); /* Message Address */ + build_append_int_noprefix(table_data, 0, 8); /* Reserved[2] */ + + acpi_table_end(linker, &table); +} + +static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap, + uint32_t gpio_irq) +{ + Aml *method, *dev, *crs, *dev1; + Aml *pkg, *pkg0, *pkg1, *pkg2, *pkg3; + + dev = aml_device("GPI0"); + aml_append(dev, aml_name_decl("_HID", aml_string("SUNW0002"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_NON_CACHEABLE, AML_READ_WRITE, + 0, gpio_memmap->base, + gpio_memmap->base + gpio_memmap->size - 1, + 0, gpio_memmap->size)); + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_SHARED, &gpio_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + aml_append(dev, method); + + + Aml *aei = aml_resource_template(); + const uint32_t pin_list[1] = {0}; + aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, AML_PULL_DOWN, 0, pin_list, 1, + "GPI0", NULL, 0)); + aml_append(dev, aml_name_decl("_AEI", aei)); + + method = aml_method("_L00", 0, AML_NOTSERIALIZED); + aml_append(method, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE), + aml_int(0x80))); + aml_append(dev, method); + + + dev1 = aml_device("GP00"); + aml_append(dev1, aml_name_decl("_UID", aml_int(0))); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("compatible")); + aml_append(pkg0, aml_string("snps,dw-apb-gpio-port")); + + pkg1 = aml_package(0x2); + aml_append(pkg1, aml_string("reg")); + aml_append(pkg1, aml_int(0x0)); + + pkg2 = aml_package(0x2); + aml_append(pkg2, aml_string("snps,nr-gpios")); + aml_append(pkg2, aml_int(0x8)); + + pkg3 = aml_package(0x3); + aml_append(pkg3, pkg0); + aml_append(pkg3, pkg1); + aml_append(pkg3, pkg2); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg3); + + aml_append(dev1, aml_name_decl("_DSD", pkg)); + + aml_append(dev, dev1); + aml_append(scope, dev); + +} + +static void acpi_dsdt_add_misc_platform(Aml *scope, SW64MachineState *vms) +{ + Aml *method, *dev; + Aml *pkg, *pkg0, *pkg1; + + dev = aml_device("MIS0"); + aml_append(dev, aml_name_decl("_HID", aml_string("SUNW0200"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + pkg1 = aml_package(0x2); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sunway,spbu_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_SPBU].base)); + aml_append(pkg1, pkg0); + + pkg0 = aml_package(0x2); + aml_append(pkg0, aml_string("sunway,intpu_base")); + aml_append(pkg0, aml_int(vms->memmap[VIRT_INTPU].base)); + aml_append(pkg1, pkg0); + + pkg = aml_package(0x2); + aml_append(pkg, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); + aml_append(pkg, pkg1); + aml_append(dev, aml_name_decl("_DSD", pkg)); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, aml_return(aml_int(0xF))); + + method = aml_method("_PXM", 0, AML_SERIALIZED); + aml_append(method, aml_return(aml_int(0x0))); + aml_append(dev, method); + + aml_append(scope, dev); +} + +/* DSDT */ +static void +build_dsdt(GArray *table_data, BIOSLinker *linker, SW64MachineState *vms) +{ + Aml *scope, *dsdt; + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; + AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = vms->oem_id, + .oem_table_id = vms->oem_table_id }; + + acpi_table_begin(&table, table_data); + dsdt = init_aml_allocator(); + + /* When booting the VM with UEFI, UEFI takes ownership of the RTC hardware. + * While UEFI can use libfdt to disable the RTC device node in the DTB that + * it passes to the OS, it cannot modify AML. Therefore, we won't generate + * the RTC ACPI device at all when using UEFI. + */ + scope = aml_scope("\\_SB"); + + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + SW64_MCU_GSI_BASE)); + + acpi_dsdt_add_sunway_ged(scope, &memmap[VIRT_SUNWAY_GED], + (irqmap[VIRT_SUNWAY_GED] + SW64_MCU_GSI_BASE)); + + acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); + acpi_dsdt_add_pci(scope, SW64_PCIE_IRQMAP, vms); + + acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], + (irqmap[VIRT_GPIO] + SW64_MCU_GSI_BASE)); + + acpi_dsdt_add_power_button(scope); + + acpi_dsdt_add_misc_platform(scope, vms); + + aml_append(dsdt, scope); + + /* copy AML table into ACPI tables blob */ + g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); + + acpi_table_end(linker, &table); + free_aml_allocator(); +} + +typedef +struct AcpiBuildState { + /* Copy of table in RAM (for patching). */ + MemoryRegion *table_mr; + MemoryRegion *rsdp_mr; + MemoryRegion *linker_mr; + /* Is table patched? */ + bool patched; +} AcpiBuildState; + +static void acpi_align_size(GArray *blob, unsigned align) +{ + /* + * Align size to multiple of given size. This reduces the chance + * we need to change size in the future (breaking cross version migration). + */ + g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); +} + +static +void sw64_acpi_build(SW64MachineState *vms, AcpiBuildTables *tables) +{ + GArray *table_offsets; + unsigned dsdt, xsdt; + GArray *tables_blob = tables->table_data; + MachineState *ms = MACHINE(vms); + + table_offsets = g_array_new(false, true /* clear */, + sizeof(uint32_t)); + + bios_linker_loader_alloc(tables->linker, + ACPI_BUILD_TABLE_FILE, tables_blob, + 64, false /* high memory */); + + /* DSDT is pointed to by FADT */ + dsdt = tables_blob->len; + build_dsdt(tables_blob, tables->linker, vms); + + /* FADT MADT MCFG is pointed to by XSDT*/ + acpi_add_table(table_offsets, tables_blob); + { + AcpiFadtData fadt = { + .rev = 5, + .minor_ver = 1, + .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI, + .xdsdt_tbl_offset = &dsdt, + }; + build_fadt(tables_blob, tables->linker, &fadt, vms->oem_id, + vms->oem_table_id); + } + + acpi_add_table(table_offsets, tables_blob); + build_madt(tables_blob, tables->linker, vms); + + acpi_add_table(table_offsets, tables_blob); + { + AcpiMcfgInfo mcfg = { + .base = vms->memmap[VIRT_PCIE_CFG].base, + .size = vms->memmap[VIRT_PCIE_CFG].size, + }; + build_mcfg(tables_blob, tables->linker, &mcfg, vms->oem_id, + vms->oem_table_id); + } + + /* NUMA support */ + if (ms->numa_state->num_nodes > 0) { + acpi_add_table(table_offsets, tables_blob); + build_srat(tables_blob, tables->linker, vms); + + if (ms->numa_state->have_numa_distance) { + acpi_add_table(table_offsets, tables_blob); + build_slit(tables_blob, tables->linker, ms, vms->oem_id, + vms->oem_table_id); + } + } + + /* XSDT is pointed to by RSDP */ + xsdt = tables_blob->len; + build_xsdt(tables_blob, tables->linker, table_offsets, vms->oem_id, + vms->oem_table_id); + + /* RSDP is in FSEG memory, so allocate it separately */ + { + AcpiRsdpData rsdp_data = { + .revision = 2, + .oem_id = vms->oem_id, + .xsdt_tbl_offset = &xsdt, + .rsdt_tbl_offset = NULL, + }; + build_rsdp(tables->rsdp, tables->linker, &rsdp_data); + } + + /* + * The align size is 128, warn if 64k is not enough therefore + * the align size could be resized. + */ + if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) { + warn_report("ACPI table size %u exceeds %d bytes," + " migration may not work", + tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); + error_printf("Try removing CPUs, NUMA nodes, memory slots" + " or PCI bridges."); + } + acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE); + + + /* Cleanup memory that's no longer used. */ + g_array_free(table_offsets, true); +} + +static void acpi_ram_update(MemoryRegion *mr, GArray *data) +{ + uint32_t size = acpi_data_len(data); + + /* Make sure RAM size is correct - in case it got changed + * e.g. by migration */ + memory_region_ram_resize(mr, size, &error_abort); + + memcpy(memory_region_get_ram_ptr(mr), data->data, size); + memory_region_set_dirty(mr, 0, size); +} + +static void sw64_acpi_build_update(void *build_opaque) +{ + AcpiBuildState *build_state = build_opaque; + AcpiBuildTables tables; + + /* No state to update or already patched? Nothing to do. */ + if (!build_state || build_state->patched) { + return; + } + build_state->patched = true; + + acpi_build_tables_init(&tables); + + sw64_acpi_build((SW64MachineState *)MACHINE(qdev_get_machine()), &tables); + + acpi_ram_update(build_state->table_mr, tables.table_data); + acpi_ram_update(build_state->rsdp_mr, tables.rsdp); + acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); + + acpi_build_tables_cleanup(&tables, true); +} + +static void sw64_acpi_build_reset(void *build_opaque) +{ + AcpiBuildState *build_state = build_opaque; + build_state->patched = false; +} + +static const VMStateDescription vmstate_sw64_acpi_build = { + .name = "sw64_acpi_build", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(patched, AcpiBuildState), + VMSTATE_END_OF_LIST() + }, +}; + +static void sw64_powerdown_req(Notifier *n, void *opaque) +{ + SW64MachineState *s = container_of(n, SW64MachineState, powerdown_notifier); + + if (s->gpio_dev) { + SW64GPIOState *gpio = SW64_GPIO(s->gpio_dev); + gpio->intsr = 0x1; + qemu_irq_pulse(gpio->irq[0]); + } else { + printf("error: no gpio device found!\n"); + } + +} + +void sw64_acpi_setup(SW64MachineState *vms) +{ + AcpiBuildTables tables; + AcpiBuildState *build_state; + + if (!vms->fw_cfg) { + return; + } + + build_state = g_malloc0(sizeof *build_state); + + acpi_build_tables_init(&tables); + + sw64_acpi_build(vms, &tables); + /* Now expose it all to Guest */ + build_state->table_mr = acpi_add_rom_blob(sw64_acpi_build_update, + build_state, tables.table_data, + ACPI_BUILD_TABLE_FILE); + assert(build_state->table_mr != NULL); + + build_state->linker_mr = acpi_add_rom_blob(sw64_acpi_build_update, + build_state, + tables.linker->cmd_blob, + ACPI_BUILD_LOADER_FILE); + build_state->rsdp_mr = acpi_add_rom_blob(sw64_acpi_build_update, + build_state, tables.rsdp, + ACPI_BUILD_RSDP_FILE); + + qemu_register_reset(sw64_acpi_build_reset, build_state); + vms->powerdown_notifier.notify = sw64_powerdown_req; + qemu_register_powerdown_notifier(&vms->powerdown_notifier); + sw64_acpi_build_reset(build_state); + vmstate_register(NULL, 0, &vmstate_sw64_acpi_build, build_state); + + /* Cleanup tables but don't free the memory: we track it + * in build_state. + */ + acpi_build_tables_cleanup(&tables, false); +} diff --git a/hw/sw64/sw64_iommu.c b/hw/sw64/sw64_iommu.c index 1ede2a2ce43d45f37bb2d023c193bcc47d0b71e7..c810639f25923707bb5e9196ad14690a73ffa9db 100644 --- a/hw/sw64/sw64_iommu.c +++ b/hw/sw64/sw64_iommu.c @@ -28,6 +28,7 @@ #include "qemu/log.h" #include "qapi/error.h" #include "hw/sw64/sw64_iommu.h" +#include "hw/sw64/sunway.h" #include "sysemu/kvm.h" #define IOMMU_PAGE_SHIFT 13 diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index b165453fa188c8ca72977b6593d8595a9fd77093..8b358f3cd808c6e13b00d2745acb1454ef9634d1 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -191,9 +191,10 @@ enum bfd_architecture #define bfd_mach_alpha_ev4 0x10 #define bfd_mach_alpha_ev5 0x20 #define bfd_mach_alpha_ev6 0x30 - bfd_arch_sw_64, /* Dec Sw_64 */ -#define bfd_mach_sw_64 1 -#define bfd_mach_sw_64_core3 1621 + bfd_arch_sw_64, /* Sw64 */ +#define bfd_mach_sw64 1 +#define bfd_mach_sw64_core3 0x10 +#define bfd_mach_sw64_core4 0x20 bfd_arch_arm, /* Advanced Risc Machines ARM */ #define bfd_mach_arm_unknown 0 #define bfd_mach_arm_2 1 @@ -432,7 +433,7 @@ int print_insn_h8500 (bfd_vma, disassemble_info*); int print_insn_arm_a64 (bfd_vma, disassemble_info*); int print_insn_alpha (bfd_vma, disassemble_info*); disassembler_ftype arc_get_disassembler (int, int); -int print_insn_sw_64 (bfd_vma, disassemble_info*); +int print_insn_sw64 (bfd_vma, disassemble_info*); int print_insn_arm (bfd_vma, disassemble_info*); int print_insn_sparc (bfd_vma, disassemble_info*); int print_insn_big_a29k (bfd_vma, disassemble_info*); diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 5e9b72c0247b817dec2c0b4a815d6c7f57931f2f..1fce83cfcd273fc97a328f1ca2115365f3ee62cd 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -409,6 +409,11 @@ Aml *aml_dword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, uint32_t addr_gran, uint32_t addr_min, uint32_t addr_max, uint32_t addr_trans, uint32_t len); +Aml *aml_qword_io(AmlMinFixed min_fixed, AmlMaxFixed max_fixed, + AmlDecode dec, AmlISARanges isa_ranges, + uint64_t addr_gran, uint64_t addr_min, + uint64_t addr_max, uint64_t addr_trans, + uint64_t len); Aml *aml_dword_memory(AmlDecode dec, AmlMinFixed min_fixed, AmlMaxFixed max_fixed, AmlCacheable cacheable, AmlReadAndWrite read_and_write, diff --git a/include/hw/sw64/core.h b/include/hw/sw64/core.h new file mode 100644 index 0000000000000000000000000000000000000000..f473b6e23120863c9c37f5917a0498749138b3d6 --- /dev/null +++ b/include/hw/sw64/core.h @@ -0,0 +1,136 @@ +#ifndef HW_SW64_CORE_H +#define HW_SW64_CORE_H + +#include "hw/pci/pci_host.h" +#include "qom/object.h" +#include "hw/boards.h" +#include "hw/sw64/pm.h" +#define TYPE_CORE3_BOARD "core3-board" +#define CORE3_BOARD(obj) \ + OBJECT_CHECK(BoardState, (obj), TYPE_CORE3_BOARD) + +#define TYPE_CORE4_BOARD "core4-board" +#define CORE4_BOARD(obj) \ + OBJECT_CHECK(BoardState, (obj), TYPE_CORE4_BOARD) + +#define SW_ACPI_BUILD_APPNAME6 "SUNWAY" +#define SW_ACPI_BUILD_APPNAME8 "SUNWAY " + +#define MAX_CPUS_CORE4 256 + +extern unsigned long dtb_start_c4; + +struct SW64MachineClass { + MachineClass parent; +}; + +struct SW64MachineState { + MachineState parent; + FWCfgState *fw_cfg; + DeviceState *acpi_dev; + DeviceState *gpio_dev; + PCIBus *bus; + char *oem_id; + char *oem_table_id; + MemMapEntry *memmap; + const int *irqmap; + Notifier powerdown_notifier; +}; + +#define TYPE_SW64_MACHINE MACHINE_TYPE_NAME("sw64") +OBJECT_DECLARE_TYPE(SW64MachineState, SW64MachineClass, SW64_MACHINE) + +struct CORE3MachineClass { + MachineClass parent; +}; + +struct CORE3MachineState { + MachineState parent; + FWCfgState *fw_cfg; + DeviceState *acpi_dev; + PCIBus *bus; + char *oem_id; + char *oem_table_id; + const MemMapEntry *memmap; + const int *irqmap; + int fdt_size; +}; + +#define TYPE_CORE3_MACHINE MACHINE_TYPE_NAME("core3") +OBJECT_DECLARE_TYPE(CORE3MachineState, CORE3MachineClass, CORE3_MACHINE) + +struct CORE4MachineClass { + MachineClass parent; +}; + +struct CORE4MachineState { + MachineState parent; + FWCfgState *fw_cfg; + DeviceState *acpi_dev; + DeviceState *gpio_dev; + PCIBus *bus; + char *oem_id; + char *oem_table_id; + const MemMapEntry *memmap; + const int *irqmap; + int fdt_size; +}; + +#define TYPE_CORE4_MACHINE MACHINE_TYPE_NAME("core4") +OBJECT_DECLARE_TYPE(CORE4MachineState, CORE4MachineClass, CORE4_MACHINE) + +typedef struct BoardState { + PCIHostState parent_obj; + MemoryRegion io_mcu; + MemoryRegion io_spbu; + MemoryRegion io_intpu; + MemoryRegion msi_ep; + MemoryRegion mem_ep; + MemoryRegion mem_ep64; + MemoryRegion conf_piu0; + MemoryRegion io_piu0; + MemoryRegion io_ep; + MemoryRegion io_rtc; + qemu_irq serial_irq; + uint32_t ofw_addr; +} BoardState; + +typedef struct TimerState { + void *opaque; + int order; +} TimerState; + +enum { + VIRT_BOOT_FLAG, + VIRT_PCIE_MMIO, + VIRT_MSI, + VIRT_SPBU, + VIRT_SUNWAY_GED, + VIRT_INTPU, + VIRT_RTC, + VIRT_FW_CFG, + VIRT_PCIE_IO_BASE, + VIRT_PCIE_PIO, + VIRT_UART, + VIRT_PCIE_CFG, + VIRT_HIGH_PCIE_MMIO, + VIRT_MCU, + VIRT_GPIO, +}; + +typedef struct boot_params { + unsigned long initrd_start; /* logical address of initrd */ + unsigned long initrd_size; /* size of initrd */ + unsigned long dtb_start; /* logical address of dtb */ + unsigned long efi_systab; /* logical address of EFI system table */ + unsigned long efi_memmap; /* logical address of EFI memory map */ + unsigned long efi_memmap_size; /* size of EFI memory map */ + unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */ + unsigned long efi_memdesc_version; /* memory descriptor version */ + unsigned long cmdline; /* logical address of cmdline */ +} BOOT_PARAMS; + +void core3_board_init(MachineState *machine); +void core4_board_init(MachineState *machine); +void sw64_acpi_setup(SW64MachineState *vms); +#endif diff --git a/include/hw/sw64/sunway.h b/include/hw/sw64/sunway.h new file mode 100644 index 0000000000000000000000000000000000000000..71732a5bc9d85815fb926d9042a7b04bec566dad --- /dev/null +++ b/include/hw/sw64/sunway.h @@ -0,0 +1,50 @@ +#ifndef SW64_SUNWAY_H +#define SW64_SUNWAY_H + +#include "exec/cpu-defs.h" +#include "hw/pci/pci.h" +#include "hw/loader.h" +#include "hw/sw64/core.h" + +extern const MemoryRegionOps rtc_ops; +extern const MemoryRegionOps sw64_pci_ignore_ops; +extern const MemoryRegionOps sw64_pci_config_ops; +extern const MemoryRegionOps msi_ops; + +void sw64_init_rtc_base_info(void); + +uint64_t cpu_sw64_virt_to_phys(void *opaque, uint64_t addr); +CpuInstanceProperties sw64_cpu_index_to_props(MachineState *ms, + unsigned cpu_index); +int64_t sw64_get_default_cpu_node_id(const MachineState *ms, + int idx); +const CPUArchIdList *sw64_possible_cpu_arch_ids(MachineState *ms); +void sw64_cpu_reset(void *opaque); +void sw64_board_reset(MachineState *state); + +void sw64_set_clocksource(void); +void sw64_set_ram_size(ram_addr_t ram_size); +void sw64_clear_uefi_bios(void); +void sw64_clear_smp_rcb(void); +void sw64_load_hmcode(const char *hmcode_filename, uint64_t *hmcode_entry); +void sw64_find_and_load_bios(const char *bios_name); +void sw64_load_kernel(const char *kernel_filename, uint64_t *kernel_entry, + const char *kernel_cmdline); +void sw64_load_initrd(const char *initrd_filename, + BOOT_PARAMS *sunway_boot_params); +int sw64_load_dtb(MachineState *ms, BOOT_PARAMS *sunway_boot_params); +void sw64_board_alarm_timer(void *opaque); +void sw64_create_alarm_timer(MachineState *ms, BoardState *bs); +uint64_t convert_bit(int n); +FWCfgState *sw64_create_fw_cfg(hwaddr addr, hwaddr size); +void sw64_virt_build_smbios(FWCfgState *fw_cfg); +void sw64_board_set_irq(void *opaque, int irq, int level); +int sw64_board_map_irq(PCIDevice *d, int irq_num); +void serial_set_irq(void *opaque, int irq, int level); +void sw64_new_cpu(const char *name, int64_t arch_id, Error **errp); +void sw64_create_pcie(BoardState *bs, PCIBus *b, PCIHostState *phb); +PCIINTxRoute sw64_route_intx_pin_to_irq(void *opaque, int pin); +MemTxResult msi_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size, MemTxAttrs attrs); +void rtc_get_time(Object *obj, struct tm *current_tm, Error **errp); +#endif /* SW64_SUNWAY_H */ diff --git a/include/hw/sw64/sw64_iommu.h b/include/hw/sw64/sw64_iommu.h index 71918760836034dba09bba4505e832d5cf0eaece..eb59ff107adf886ad7e04ba064840e99bc16941b 100644 --- a/include/hw/sw64/sw64_iommu.h +++ b/include/hw/sw64/sw64_iommu.h @@ -100,6 +100,4 @@ extern void swvt_address_space_invalidate_iova(SW64IOMMUState *s, unsigned long extern void swvt_address_space_unmap_iova(SW64IOMMUState *s, unsigned long val); extern void swvt_address_space_map_iova(SW64IOMMUState *s, unsigned long val); extern SWVTAddressSpace *iommu_find_add_as(SW64IOMMUState *s, PCIBus *bus, int devfn); -extern MemTxResult msi_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, - MemTxAttrs attrs); #endif diff --git a/linux-headers/asm-sw64/kvm.h b/linux-headers/asm-sw64/kvm.h index 5de7014b5237584d716c802810bb970d482f1046..9310ad49bbb730a4b9539817333b484fcabf41d5 100644 --- a/linux-headers/asm-sw64/kvm.h +++ b/linux-headers/asm-sw64/kvm.h @@ -8,99 +8,51 @@ /* * for KVM_GET_REGS and KVM_SET_REGS */ -struct kvm_regs { - unsigned long r0; - unsigned long r1; - unsigned long r2; - unsigned long r3; - - unsigned long r4; - unsigned long r5; - unsigned long r6; - unsigned long r7; - - unsigned long r8; - unsigned long r9; - unsigned long r10; - unsigned long r11; - - unsigned long r12; - unsigned long r13; - unsigned long r14; - unsigned long r15; - - unsigned long r19; - unsigned long r20; - unsigned long r21; - unsigned long r22; - - unsigned long r23; - unsigned long r24; - unsigned long r25; - unsigned long r26; +struct user_pt_regs { + unsigned long r[31]; + unsigned long pc; + unsigned long pstate; +}; - unsigned long r27; - unsigned long r28; - unsigned long __padding0; - unsigned long fpcr; +/* 256 bits aligned for simd */ +struct fpreg { + unsigned long v[4] __attribute__((aligned(32))); +}; - unsigned long fp[124]; - /* These are saved by hmcode: */ - unsigned long ps; - unsigned long pc; - unsigned long gp; - unsigned long r16; - unsigned long r17; - unsigned long r18; +struct user_fpsimd_state { + struct fpreg fp[31]; + unsigned long fpcr; + unsigned long __reserved[3]; }; -struct vcpucb { - unsigned long go_flag; - unsigned long pcbb; - unsigned long ksp; - unsigned long usp; - unsigned long kgp; - unsigned long ent_arith; - unsigned long ent_if; - unsigned long ent_int; - unsigned long ent_mm; - unsigned long ent_sys; - unsigned long ent_una; - unsigned long stack_pc; - unsigned long new_a0; - unsigned long new_a1; - unsigned long new_a2; - unsigned long whami; - unsigned long csr_save; - unsigned long wakeup_magic; - unsigned long host_vcpucb; - unsigned long upcr; - unsigned long vpcr; - unsigned long dtb_pcr; - unsigned long guest_ksp; - unsigned long guest_usp; - unsigned long vcpu_irq_disabled; - unsigned long vcpu_irq; - unsigned long ptbr; - unsigned long int_stat0; - unsigned long int_stat1; - unsigned long int_stat2; - unsigned long int_stat3; - unsigned long reset_entry; - unsigned long pvcpu; - unsigned long exit_reason; - unsigned long ipaddr; - unsigned long vcpu_irq_vector; - unsigned long pri_base; - unsigned long stack_pc_dfault; - unsigned long guest_p20; - unsigned long guest_dfault_double; - unsigned long guest_irqs_pending; - unsigned long guest_hm_r30; - unsigned long migration_mark; - unsigned long guest_longtime; - unsigned long guest_longtime_offset; - unsigned long reserved[3]; +struct kvm_regs { + union { + struct { + unsigned long r[27]; + unsigned long fpcr; + + unsigned long fp[124]; + /* These are saved by hmcode: */ + unsigned long ps; + unsigned long pc; + unsigned long gp; + unsigned long r16; + unsigned long r17; + unsigned long r18; + unsigned long reserved[6]; + } c3_regs; + struct { + union { + struct user_pt_regs reg; + struct { + unsigned long r[31]; + unsigned long pc; + unsigned long ps; + } + }; + struct user_fpsimd_state fpstate; + } c4_regs; + }; }; /* diff --git a/meson.build b/meson.build index 45bc69bf0c718199c6af166c777b96472ac6c009..6fcf95a973fd947f9435b9579656c5dd6891ad5d 100644 --- a/meson.build +++ b/meson.build @@ -3278,6 +3278,7 @@ summary_info += {'Trace backends': ','.join(get_option('trace_backends'))} if 'simple' in get_option('trace_backends') summary_info += {'Trace output file': get_option('trace_file') + '-'} endif +summary_info += {'vt-iommu': config_host.has_key('CONFIG_SW64_VT_IOMMU')} summary_info += {'QOM debugging': config_host.has_key('CONFIG_QOM_CAST_DEBUG')} summary_info += {'vhost-kernel support': config_host.has_key('CONFIG_VHOST_KERNEL')} summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')} diff --git a/pc-bios/c3-uefi-bios-sw b/pc-bios/c3-uefi-bios-sw new file mode 100755 index 0000000000000000000000000000000000000000..095cc83a26872af6ee0f0bfb60a5301f2cffd31a Binary files /dev/null and b/pc-bios/c3-uefi-bios-sw differ diff --git a/pc-bios/c4-uefi-bios-sw b/pc-bios/c4-uefi-bios-sw new file mode 100644 index 0000000000000000000000000000000000000000..3dd29837b7fb3d621800f6f28da55002a634c721 Binary files /dev/null and b/pc-bios/c4-uefi-bios-sw differ diff --git a/pc-bios/core3-hmcode b/pc-bios/core3-hmcode index a488707bba0d2db7762636a8e2c112bf69189376..94bb0c2214d61ed5015b02c7843c0d79afb26696 100644 Binary files a/pc-bios/core3-hmcode and b/pc-bios/core3-hmcode differ diff --git a/pc-bios/core4-hmcode b/pc-bios/core4-hmcode index 668a9e97b3a39e9bd44273860d1f35505025ec71..e2e47b9c170fbffaf19429294332bb788770cecc 100755 Binary files a/pc-bios/core4-hmcode and b/pc-bios/core4-hmcode differ diff --git a/pc-bios/core4-reset b/pc-bios/core4-reset new file mode 100755 index 0000000000000000000000000000000000000000..ab5220ef7ecba0b26d73f734c83e936e982171e0 Binary files /dev/null and b/pc-bios/core4-reset differ diff --git a/pc-bios/meson.build b/pc-bios/meson.build index f2a1d111a1518b32ff26abd45e90cc9161f3f0bf..0383ac84b48eeb26144376b4c01f7202fa8415fd 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -38,9 +38,12 @@ blobs = files( 'vgabios-ramfb.bin', 'vgabios-bochs-display.bin', 'vgabios-ati.bin', - 'uefi-bios-sw', + 'c3-uefi-bios-sw', 'core3-reset', 'core3-hmcode', + 'c4-uefi-bios-sw', + 'core4-reset', + 'core4-hmcode', 'openbios-sparc32', 'openbios-sparc64', 'openbios-ppc', diff --git a/pc-bios/uefi-bios-sw b/pc-bios/uefi-bios-sw-old old mode 100755 new mode 100644 similarity index 100% rename from pc-bios/uefi-bios-sw rename to pc-bios/uefi-bios-sw-old diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 682dc86b427c02ddba0387cb84529d0ffc8a324d..4c807594f545b683e0886afa3f83ffb039316c94 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -325,7 +325,8 @@ 'TARGET_I386', 'TARGET_S390X', 'TARGET_MIPS', - 'TARGET_LOONGARCH64' ] } } + 'TARGET_LOONGARCH64', + 'TARGET_SW64' ] } } ## # @query-cpu-definitions: @@ -342,4 +343,5 @@ 'TARGET_I386', 'TARGET_S390X', 'TARGET_MIPS', - 'TARGET_LOONGARCH64' ] } } + 'TARGET_LOONGARCH64', + 'TARGET_SW64' ] } } diff --git a/qemu-options.hx b/qemu-options.hx index ab82ad4150d8cb02ba67673843a2f0a67692b2e9..a1f4131cec573da98b8363f40e14fe8ece953619 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2548,7 +2548,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, " specify SMBIOS type 17 fields\n" "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n" " specify SMBIOS type 41 fields\n", - QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH64) + QEMU_ARCH_I386 | QEMU_ARCH_ARM | QEMU_ARCH_LOONGARCH64 | QEMU_ARCH_SW64) SRST ``-smbios file=binary`` Load SMBIOS entry from binary file. diff --git a/target/sw64/Makefile.objs b/target/sw64/Makefile.objs deleted file mode 100644 index c702eaa26db53fc0bd58eca052f874bd179a77bc..0000000000000000000000000000000000000000 --- a/target/sw64/Makefile.objs +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_SOFTMMU) += machine.o -obj-y += cpu.o translate.o profile.o helper.o -obj-y += int_helper.o float_helper.o simd_helper.o helper.o exception.o -obj-$(CONFIG_KVM) += kvm.o -obj-y += gdbstub.o diff --git a/target/sw64/cpu-qom.h b/target/sw64/cpu-qom.h index b093c2bec81d1a001228fb51d7ff4e625fa72e44..262cdc2db1cb4cde88523a2ba9e14ae9b9393e89 100644 --- a/target/sw64/cpu-qom.h +++ b/target/sw64/cpu-qom.h @@ -18,16 +18,10 @@ #define QEMU_SW64_CPU_QOM #include "hw/core/cpu.h" +#include "qom/object.h" #define TYPE_SW64_CPU "sw64-cpu" - -#define SW64_CPU_CLASS(kclass) \ - OBJECT_CLASS_CHECK(SW64CPUClass, (kclass), TYPE_SW64_CPU) -#define SW64_CPU(obj) \ - OBJECT_CHECK(SW64CPU, (obj), TYPE_SW64_CPU) -#define SW64_CPU_GET_CLASS(obj) \ - OBJECT_GET_CLASS(SW64CPUClass, (obj), TYPE_SW64_CPU) - +OBJECT_DECLARE_TYPE(SW64CPU, SW64CPUClass, SW64_CPU) /** * SW64CPUClass: * @parent_realize: The parent class' realize handler. @@ -40,8 +34,7 @@ typedef struct SW64CPUClass { CPUClass parent_class; /* public */ DeviceRealize parent_realize; + DeviceUnrealize parent_unrealize; DeviceReset parent_reset; } SW64CPUClass; - -typedef struct SW64CPU SW64CPU; #endif diff --git a/target/sw64/cpu.c b/target/sw64/cpu.c index 8987361346ca9cf082529b03f7f57883991ac262..bb5c80856f825dc13073bedf15cfba24942732fb 100644 --- a/target/sw64/cpu.c +++ b/target/sw64/cpu.c @@ -25,6 +25,9 @@ #include "kvm_sw64.h" #include "sysemu/reset.h" #include "hw/qdev-properties.h" +#include "sysemu/arch_init.h" +#include "qapi/qapi-commands-machine-target.h" +#include "hw/sw64/pm.h" static void sw64_cpu_set_pc(CPUState *cs, vaddr value) { @@ -102,10 +105,30 @@ static void sw64_machine_cpu_reset(void *opaque) static void sw64_cpu_realizefn(DeviceState *dev, Error **errp) { + SW64CPU *cpu = SW64_CPU(dev); CPUState *cs = CPU(dev); SW64CPUClass *scc = SW64_CPU_GET_CLASS(dev); Error *local_err = NULL; + MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int max_cpus = ms->smp.max_cpus; + + if (cpu->core_id > 0) { + cpu_hot_id = cpu->core_id; + if (!cpu_hot_id || cpu_hot_id > max_cpus - 1) { + error_setg(&local_err, "error:" + "Cpu num must be less than max cpus and can not be 0!"); + error_propagate(errp, local_err); + return ; + } + if (get_state_cpumask(cpu_hot_id)) { + error_setg(&local_err, "error: Unable to add already online cpu!"); + error_propagate(errp, local_err); + return ; + } + } + + cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); @@ -120,10 +143,85 @@ static void sw64_cpu_realizefn(DeviceState *dev, Error **errp) scc->parent_realize(dev, errp); } +static void sw64_cpu_unrealizefn(DeviceState *dev) +{ + CPUState *cs = CPU(dev); + SW64CPUClass *scc = SW64_CPU_GET_CLASS(dev); +#ifndef CONFIG_USER_ONLY + cpu_remove_sync(CPU(dev)); + qemu_unregister_reset(sw64_machine_cpu_reset, cs); +#endif + scc->parent_unrealize(dev); +} + +static char *sw64_cpu_class_get_model_name(SW64CPUClass *cc) +{ + const char *class_name = object_class_get_name(OBJECT_CLASS(cc)); + assert(g_str_has_suffix(class_name, SW64_CPU_TYPE_SUFFIX)); + return g_strndup(class_name, + strlen(class_name) - strlen(SW64_CPU_TYPE_SUFFIX)); +} + +static void sw64_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + SW64CPUClass *cc = SW64_CPU_CLASS(oc); + + char *name = sw64_cpu_class_get_model_name(cc); + qemu_printf("sw64 %s\n", name); + g_free(name); +} + +void sw64_cpu_list(void) +{ + GSList *list; + + list = object_class_get_list_sorted(TYPE_SW64_CPU, false); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, sw64_cpu_list_entry, NULL); + g_slist_free(list); +} + +static void sw64_cpu_add_definition(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + const char *typename; + + typename = object_class_get_name(oc); + info = g_malloc0(sizeof(*info)); + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_SW64_CPU)); + info->q_typename = g_strdup(typename); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = *cpu_list; + *cpu_list = entry; +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + GSList *list; + + list = object_class_get_list(TYPE_SW64_CPU, false); + g_slist_foreach(list, sw64_cpu_add_definition, &cpu_list); + g_slist_free(list); + + return cpu_list; +} + static void sw64_cpu_disas_set_info(CPUState *cs, disassemble_info *info) { - info->mach = bfd_mach_sw_64_core3; - info->print_insn = print_insn_sw_64; + CPUSW64State *env = cs->env_ptr; + if (test_feature(env, SW64_FEATURE_CORE3)) + info->mach = bfd_mach_sw64_core3; + else if(test_feature(env, SW64_FEATURE_CORE4)) + info->mach = bfd_mach_sw64_core4; + info->print_insn = print_insn_sw64; } #include "fpu/softfloat.h" @@ -138,6 +236,17 @@ static void core3_init(Object *obj) set_feature(env, SW64_FEATURE_CORE3); } +static void core4_init(Object *obj) +{ + CPUState *cs = CPU(obj); + CPUSW64State *env = cs->env_ptr; +#ifdef CONFIG_USER_ONLY + env->fpcr = 0x680e800000000000; + parallel_cpus = true; +#endif + set_feature(env, SW64_FEATURE_CORE4); +} + static ObjectClass *sw64_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; @@ -164,7 +273,7 @@ bool sw64_cpu_has_work(CPUState *cs) * wake up by hard interrupt, timer, ii, mail or mchk. */ return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER | - CPU_INTERRUPT_II0| CPU_INTERRUPT_MCHK); + CPU_INTERRUPT_II0 | CPU_INTERRUPT_MCHK | CPU_INTERRUPT_IINM); } static void sw64_cpu_initfn(Object *obj) @@ -191,6 +300,9 @@ static void sw64_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr MemTxResult response, uintptr_t retaddr) { #ifdef DEBUG_TRANS + SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = &cpu->env; + if (retaddr) { cpu_restore_state(cs, retaddr, true); } @@ -218,10 +330,15 @@ static void sw64_cpu_reset(DeviceState *dev) static Property sw64_cpu_properties[] = { #ifdef CONFIG_USER_ONLY /* apic_id = 0 by default for *-user, see commit 9886e834 */ - DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0), + DEFINE_PROP_UINT32("thread-id", SW64CPU, thread_id, 0), + DEFINE_PROP_UINT32("core-id", SW64CPU, core_id, 0), + DEFINE_PROP_UINT32("socket-id", SW64CPU, socket_id, 0), #else - DEFINE_PROP_UINT32("cid", SW64CPU, cid, 0xFFFFFFFF), + DEFINE_PROP_UINT32("thread-id", SW64CPU, thread_id, 0), + DEFINE_PROP_UINT32("core-id", SW64CPU, core_id, 0xFFFFFFFF), + DEFINE_PROP_UINT32("socket-id", SW64CPU, socket_id, 0), #endif + DEFINE_PROP_UINT32("node-id", SW64CPU, node_id, -1), DEFINE_PROP_END_OF_LIST() }; @@ -253,10 +370,16 @@ static void sw64_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); SW64CPUClass *scc = SW64_CPU_CLASS(oc); - device_class_set_parent_realize(dc, sw64_cpu_realizefn, &scc->parent_realize); + device_class_set_parent_realize(dc, sw64_cpu_realizefn, + &scc->parent_realize); device_class_set_parent_reset(dc, sw64_cpu_reset, &scc->parent_reset); device_class_set_props(dc, sw64_cpu_properties); + scc->parent_unrealize = dc->unrealize; + dc->unrealize = sw64_cpu_unrealizefn; + + dc->user_creatable = true; + cc->class_by_name = sw64_cpu_class_by_name; #ifndef CONFIG_USER_ONLY dc->vmsd = &vmstate_sw64_cpu; @@ -281,6 +404,10 @@ static const SW64CPUInfo sw64_cpus[] = .name = "core3", .initfn = core3_init, }, + { + .name = "core4", + .initfn = core4_init, + }, { .name = NULL }, diff --git a/target/sw64/cpu.h b/target/sw64/cpu.h index 4e14891e849ee7cf59410f72a10e14d2db8e5bc8..8704d59def9400c723653bb73161b13f9c8905ee 100644 --- a/target/sw64/cpu.h +++ b/target/sw64/cpu.h @@ -60,7 +60,7 @@ #define MCU_CLOCK 25000000 -#define init_pc 0xffffffff80011100 +#define PTE_MASK 0xbfffffffffffffff typedef struct CPUSW64State CPUSW64State; typedef CPUSW64State CPUArchState; @@ -118,6 +118,7 @@ struct CPUSW64State { uint8_t stable; }; #define SW64_FEATURE_CORE3 0x2 +#define SW64_FEATURE_CORE4 0x4 static inline void set_feature(CPUSW64State *env, int feature) { @@ -137,11 +138,14 @@ struct SW64CPU { CPUNegativeOffsetState neg; CPUSW64State env; - uint64_t k_regs[158]; - uint64_t k_vcb[48]; + uint64_t k_regs[164]; + uint64_t k_vcb[96]; QEMUTimer *alarm_timer; target_ulong irq; - uint32_t cid; + uint32_t node_id; + uint32_t thread_id; + uint32_t core_id; + uint32_t socket_id; }; enum { @@ -228,8 +232,9 @@ static inline SW64CPU *sw64_env_get_cpu(CPUSW64State *env) #define SW64_CPU_TYPE_SUFFIX "-" TYPE_SW64_CPU #define SW64_CPU_TYPE_NAME(name) (name SW64_CPU_TYPE_SUFFIX) +#define cpu_list sw64_cpu_list int cpu_sw64_signal_handler(int host_signum, void *pinfo, void *puc); -int sw64_cpu_gdb_read_register(CPUState *cs, uint8_t *buf, int reg); +int sw64_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int reg); int sw64_cpu_gdb_write_register(CPUState *cs, uint8_t *buf, int reg); bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, @@ -250,6 +255,7 @@ void sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, uintptr_t retaddr) QEMU_NORETURN; bool sw64_cpu_has_work(CPUState *cs); extern struct VMStateDescription vmstate_sw64_cpu; +void sw64_cpu_list(void); /* SW64-specific interrupt pending bits */ #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0 @@ -257,7 +263,7 @@ extern struct VMStateDescription vmstate_sw64_cpu; #define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2 #define CPU_INTERRUPT_PCIE CPU_INTERRUPT_TGT_EXT_3 #define CPU_INTERRUPT_WAKEUP CPU_INTERRUPT_TGT_EXT_3 -#define CPU_INTERRUPT_SLAVE CPU_INTERRUPT_TGT_EXT_4 +#define CPU_INTERRUPT_IINM CPU_INTERRUPT_TGT_EXT_4 #define cpu_signal_handler cpu_sw64_signal_handler #define CPU_RESOLVING_TYPE TYPE_SW64_CPU @@ -285,18 +291,34 @@ enum { SWCSR(DTB_IU, 0x45), SWCSR(DTB_IS, 0x46), SWCSR(II_REQ, 0x82), - - SWCSR(PTBR, 0x8), - SWCSR(PRI_BASE, 0x10), - SWCSR(TIMER_CTL, 0x2a), - SWCSR(TIMER_TH, 0x2b), - SWCSR(INT_STAT, 0x30), - SWCSR(INT_CLR, 0x31), - SWCSR(IER, 0x32), +/* core3 csr */ + SWCSR(C3_PTBR, 0x8), + SWCSR(C3_PRI_BASE, 0x10), + SWCSR(C3_UPCR, 0x22), + SWCSR(C3_TIMER_CTL, 0x2a), + SWCSR(C3_TIMER_TH, 0x2b), + SWCSR(C3_INT_STAT, 0x30), + SWCSR(C3_INT_CLR, 0x31), + SWCSR(C3_IER, 0x32), SWCSR(INT_PCI_INT, 0x33), - SWCSR(DVA, 0x4e), - SWCSR(SOFT_CID, 0xc9), - SWCSR(SHTCLOCK, 0xca), + SWCSR(C3_DVA, 0x4e), + SWCSR(C3_DTB_PCR, 0x47), +/* core4 csr */ + SWCSR(C4_PRI_BASE, 0xf), + SWCSR(C4_UPCR, 0x15), + SWCSR(INT_EN, 0x1a), + SWCSR(C4_INT_STAT, 0x1b), + SWCSR(C4_INT_CLR, 0x1c), + SWCSR(PCIE_INT, 0x21), + SWCSR(C4_TIMER_TH, 0x23), + SWCSR(C4_TIMER_CTL, 0x24), + SWCSR(IINM, 0x2f), + SWCSR(C4_DVA, 0x54), + SWCSR(C4_DTB_UPCR, 0x58), + SWCSR(C4_PTBR_SYS, 0x68), + SWCSR(C4_PTBR_USR, 0x69), + SWCSR(SOFT_CID, 0xc9), + SWCSR(SHTCLOCK, 0xca), }; #include "exec/cpu-all.h" @@ -314,6 +336,7 @@ enum { EXCP_NONE, EXCP_HALT, EXCP_II0, + EXCP_IINM, EXCP_OPCDEC, EXCP_CALL_SYS, EXCP_ARITH, diff --git a/target/sw64/exception.c b/target/sw64/exception.c index a2df1cd32980efacfd274cd60ab8347e373d163d..9b316a56e37102c5e2f6916587650971fd2c0536 100644 --- a/target/sw64/exception.c +++ b/target/sw64/exception.c @@ -21,7 +21,10 @@ void QEMU_NORETURN sw64_cpu_do_unaligned_access(CPUState *cs, vaddr addr, } fprintf(stderr, "Error %s addr = %lx\n", __func__, addr); - env->csr[DVA] = addr; + if (test_feature(env, SW64_FEATURE_CORE3)) + env->csr[C3_DVA] = addr; + else if (test_feature(env, SW64_FEATURE_CORE4)) + env->csr[C4_DVA] = addr; env->csr[EXC_SUM] = ((insn >> 21) & 31) << 8; /* opcode */ env->csr[DS_STAT] = (insn >> 26) << 4; /* dest regno */ diff --git a/target/sw64/gdbstub.c b/target/sw64/gdbstub.c index da4d39d215d0a89d40f2b4a377381fc007fd7cb9..b3a49b6cdd441f015682af94e959ccdf9c6845cb 100644 --- a/target/sw64/gdbstub.c +++ b/target/sw64/gdbstub.c @@ -21,7 +21,7 @@ #include "cpu.h" #include "exec/gdbstub.h" -int sw64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +int sw64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { SW64CPU *cpu = SW64_CPU(cs); CPUSW64State *env = &cpu->env; diff --git a/target/sw64/helper.c b/target/sw64/helper.c index e317c08f0a5492a218ae8fa9b19917298003bb79..345c13a5a2798f91f15838ec5a3c2ac97c0b575a 100644 --- a/target/sw64/helper.c +++ b/target/sw64/helper.c @@ -31,13 +31,14 @@ static target_ulong ldq_phys_clear(CPUState *cs, target_ulong phys) static int get_sw64_physical_address(CPUSW64State *env, target_ulong addr, int prot_need, int mmu_idx, target_ulong *pphys, - int *pprot) + int *pprot, target_ulong *page_size) { CPUState *cs = CPU(sw64_env_get_cpu(env)); target_ulong phys = 0; int prot = 0; int ret = MM_K_ACV; - target_ulong L1pte, L2pte, L3pte, L4pte; + target_ulong page_offset = 0; + target_ulong L1pte, L2pte, L3pte, pte; target_ulong pt = 0, index = 0, pte_pfn_s = 0; if (((addr >> 28) & 0xffffffff8) == 0xffffffff8) { @@ -54,10 +55,15 @@ static int get_sw64_physical_address(CPUSW64State *env, target_ulong addr, goto exit; } do_pgmiss: - pte_pfn_s = 28; - pt = env->csr[PTBR]; + if (test_feature(env, SW64_FEATURE_CORE3)) { + pte_pfn_s = 28; + pt = env->csr[C3_PTBR]; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + pte_pfn_s = 24; + pt = (((addr>>52)&0x1) == 1) ? env->csr[C4_PTBR_SYS] : env->csr[C4_PTBR_USR]; + } index = (addr >> (TARGET_PAGE_BITS + 3 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); - L1pte = ldq_phys_clear(cs, pt + index * 8); + L1pte = ldq_phys_clear(cs, pt + index * 8) & PTE_MASK; if ((L1pte & PTE_VALID) == 0) { ret = MM_K_TNV; goto exit; @@ -73,7 +79,7 @@ do_pgmiss: pt = L1pte >> pte_pfn_s << TARGET_PAGE_BITS; index = (addr >> (TARGET_PAGE_BITS + 2 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); - L2pte = ldq_phys_clear(cs, pt + index * 8); + L2pte = ldq_phys_clear(cs, pt + index * 8) & PTE_MASK; if ((L2pte & PTE_VALID) == 0) { ret = MM_K_TNV; @@ -91,7 +97,7 @@ do_pgmiss: pt = L2pte >> pte_pfn_s << TARGET_PAGE_BITS; index = (addr >> (TARGET_PAGE_BITS + 1 * TARGET_LEVEL_BITS)) & ((1 << TARGET_LEVEL_BITS)-1); - L3pte = ldq_phys_clear(cs, pt + index * 8); + L3pte = ldq_phys_clear(cs, pt + index * 8) & PTE_MASK; if ((L3pte & PTE_VALID) == 0) { ret = MM_K_TNV; @@ -109,27 +115,37 @@ do_pgmiss: pt = L3pte >> pte_pfn_s << TARGET_PAGE_BITS; index = (addr >> TARGET_PAGE_BITS) & ((1 << TARGET_LEVEL_BITS)-1); - L4pte = ldq_phys_clear(cs, pt + index * 8); - if ((L4pte & PTE_VALID) == 0) { - ret = MM_K_TNV; - goto exit; + + target_ulong page_granularity = (L3pte >> 5) & 0x3; + if (page_granularity != 0) { + pte = L3pte; + *page_size = 1 << 23; + page_offset = addr & 0x7fe000; + } else { + *page_size = TARGET_PAGE_SIZE; + page_offset = 0; + pte = ldq_phys_clear(cs, pt + index * 8) & PTE_MASK; + if ((pte & PTE_VALID) == 0) { + ret = MM_K_TNV; + goto exit; + } } #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4 #error page bits out of date #endif /* Check access violations. */ - if ((L4pte & PTE_FOR) == 0) { + if ((pte & PTE_FOR) == 0) { prot |= PAGE_READ | PAGE_EXEC; } - if ((L4pte & PTE_FOW) == 0) { + if ((pte & PTE_FOW) == 0) { prot |= PAGE_WRITE; } /* Check fault-on-operation violations. */ - prot &= ~(L4pte >> 1); + prot &= ~(pte >> 1); - phys = (L4pte >> pte_pfn_s << TARGET_PAGE_BITS); + phys = (pte >> pte_pfn_s << TARGET_PAGE_BITS) + page_offset; if (unlikely((prot & prot_need) == 0)) { ret = (prot_need & PAGE_EXEC @@ -154,8 +170,14 @@ bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, SW64CPU *cpu = SW64_CPU(cs); CPUSW64State *env = &cpu->env; target_ulong phys; - int prot, fail; + int prot, fail, DVA = 0; + target_ulong page_size = TARGET_PAGE_SIZE; + if (test_feature(env, SW64_FEATURE_CORE3)) { + DVA = C3_DVA; + } else if (test_feature(env, SW64_FEATURE_CORE4)){ + DVA = C4_DVA; + } if (mmu_idx == MMU_PHYS_IDX) { phys = address; prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -165,7 +187,8 @@ bool sw64_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } do_pgmiss: - fail = get_sw64_physical_address(env, address, 1 << access_type, mmu_idx, &phys, &prot); + fail = get_sw64_physical_address(env, address, 1 << access_type, mmu_idx, + &phys, &prot, &page_size); if (unlikely(fail >= 0)) { if (probe) { return false; @@ -183,7 +206,7 @@ do_pgmiss: } done: tlb_set_page(cs, address & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK, prot, - mmu_idx, TARGET_PAGE_SIZE); + mmu_idx, page_size); return true; } @@ -192,6 +215,7 @@ hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) SW64CPU *cpu = SW64_CPU(cs); CPUSW64State *env = &cpu->env; target_ulong phys; + target_ulong page_size = TARGET_PAGE_SIZE; int prot, fail; int mmu_index = cpu_mmu_index(env, 0); if (mmu_index == MMU_PHYS_IDX) { @@ -202,7 +226,8 @@ hwaddr sw64_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) goto done; } do_pgmiss: - fail = get_sw64_physical_address(&cpu->env, addr, 1, mmu_index, &phys, &prot); + fail = get_sw64_physical_address(&cpu->env, addr, 1, mmu_index, + &phys, &prot, &page_size); done: return (fail >= 0 ? -1 : phys); } @@ -250,7 +275,11 @@ void sw64_cpu_do_interrupt(CPUState *cs) break; case EXCP_CLK_INTERRUPT: case EXCP_DEV_INTERRUPT: - i = 0xE80; + case EXCP_IINM: + if (test_feature(env, SW64_FEATURE_CORE3)) + i = 0xE80;/* core3 */ + else if (test_feature(env, SW64_FEATURE_CORE4)) + i = 0xE00;/* core4 */ break; case EXCP_MMFAULT: i = 0x980; @@ -262,7 +291,7 @@ void sw64_cpu_do_interrupt(CPUState *cs) break; default: break; - } + } env->pc = env->hm_entry + i; env->flags = ENV_FLAG_HM_MODE; } @@ -271,11 +300,28 @@ bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { SW64CPU *cpu = SW64_CPU(cs); CPUSW64State *env = &cpu->env; - int idx = -1; + int idx = -1, INT_STAT = 0, IER = 0, PCI_INT = 0; /* We never take interrupts while in PALmode. */ if (env->flags & ENV_FLAG_HM_MODE) return false; + if (test_feature(env, SW64_FEATURE_CORE3)) { + IER = C3_IER; + INT_STAT = C3_INT_STAT; + PCI_INT = INT_PCI_INT; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + IER = INT_EN; + INT_STAT = C4_INT_STAT; + PCI_INT = PCIE_INT; + } + + if (interrupt_request & CPU_INTERRUPT_IINM) { + idx = EXCP_IINM; + env->csr[IINM] = 1UL << 1; + cs->interrupt_request &= ~CPU_INTERRUPT_IINM; + goto done; + } + if (interrupt_request & CPU_INTERRUPT_II0) { idx = EXCP_II0; env->csr[INT_STAT] |= 1UL << 6; @@ -306,7 +352,7 @@ bool sw64_cpu_exec_interrupt(CPUState *cs, int interrupt_request) if (interrupt_request & CPU_INTERRUPT_PCIE) { idx = EXCP_DEV_INTERRUPT; env->csr[INT_STAT] |= 1UL << 1; - env->csr[INT_PCI_INT] = 0x10; + env->csr[PCI_INT] = 0x10; if ((env->csr[IER] & env->csr[INT_STAT]) == 0) return false; cs->interrupt_request &= ~CPU_INTERRUPT_PCIE; @@ -392,10 +438,12 @@ void cpu_sw64_store_fpcr(CPUSW64State* env, uint64_t val) { uint64_t helper_read_csr(CPUSW64State *env, uint64_t index) { - if (index == PRI_BASE) - env->csr[index] = 0x10000; + if ((index == C3_PRI_BASE) || (index == C4_PRI_BASE)) + env->csr[index] = 0x10000; +#ifndef CONFIG_USER_ONLY if (index == SHTCLOCK) - env->csr[index] = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 40; + env->csr[index] = qemu_clock_get_ns(QEMU_CLOCK_HOST) / 40; +#endif return env->csr[index]; } @@ -417,19 +465,29 @@ void helper_write_csr(CPUSW64State *env, uint64_t index, uint64_t va) if ((index == DTB_IA) || (index == DTB_IV) || (index == DTB_IVP) || (index == DTB_IU) || (index == DTB_IS) || (index == ITB_IA) || (index == ITB_IV) || (index == ITB_IVP) || (index == ITB_IU) || - (index == ITB_IS) || (index == PTBR)) { + (index == ITB_IS) || (index == C3_PTBR) || (index == C4_PTBR_SYS) || + (index == C4_PTBR_USR) || (index == C3_UPCR) || (index == C3_DTB_PCR) || + (index == C4_UPCR) || (index == C4_DTB_UPCR)) { tlb_flush(cs); } - if (index == INT_CLR) { - env->csr[INT_STAT] &= ~va; +//core3 + if (index == C3_INT_CLR) { + env->csr[C3_INT_STAT] &= ~va; } - if ((index == TIMER_CTL) && (va == 1)) { - timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + env->csr[TIMER_TH]); + if ((index == C3_TIMER_CTL) && (va == 1)) { + timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + env->csr[C3_TIMER_TH]); } - if (index == TIMER_CTL && env->csr[index] == 1) { - timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1000000000 / 250); +//core4 + if (index == C4_INT_CLR) { + env->csr[C4_INT_STAT] &= ~va; } + if (index == IINM) + env->csr[index] &= ~va; + if ((index == C4_TIMER_CTL) && (va == 1)) { + timer_mod(cpu->alarm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + env->csr[C4_TIMER_TH]); + } + #endif } diff --git a/target/sw64/kvm.c b/target/sw64/kvm.c index c38db7cabe0e2957b75c3643385a7f1df246b7b0..c5103c369ee0b38f1562dc2b2fed2458d9c40419 100644 --- a/target/sw64/kvm.c +++ b/target/sw64/kvm.c @@ -23,8 +23,12 @@ #include "exec/memattrs.h" #include "exec/address-spaces.h" #include "hw/boards.h" +#include "hw/sw64/core.h" #include "qemu/log.h" +unsigned long core3_init_pc = 0xfff0000000011100; +unsigned long core4_init_pc = 0xfff0000000011002; + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; @@ -33,9 +37,13 @@ int kvm_sw64_vcpu_init(CPUState *cs) { struct kvm_regs *regs; SW64CPU *cpu = SW64_CPU(cs); + CPUSW64State *env = cs->env_ptr; regs = (struct kvm_regs *)cpu->k_regs; - regs->pc = init_pc; - return kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); + if (test_feature(env, SW64_FEATURE_CORE3)) + regs->c3_regs.pc = core3_init_pc; + else if (test_feature(env, SW64_FEATURE_CORE4)) + regs->c4_regs.pc = core4_init_pc; + return kvm_vcpu_ioctl(cs, KVM_SET_REGS, regs); } static void kvm_sw64_host_cpu_class_init(ObjectClass *oc, void *data) @@ -67,26 +75,27 @@ int kvm_arch_init(MachineState *ms, KVMState *s) /* 50000 jump to bootlader while 2f00000 jump to bios*/ void kvm_sw64_reset_vcpu(SW64CPU *cpu) { - CPUState *cs = CPU(cpu); struct kvm_regs *regs; + CPUState *cs = CPU(cpu); + CPUSW64State *env = cs->env_ptr; int ret; - struct vcpucb *vcb; - regs = (struct kvm_regs *)cpu->k_regs; - regs->pc = init_pc; - - ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); - + if (test_feature(env, SW64_FEATURE_CORE3)) + regs->c3_regs.pc = core3_init_pc; + else if (test_feature(env, SW64_FEATURE_CORE4)) { + if (kvm_arch_vcpu_id(cs) == 0) { + regs->c4_regs.r[16] = 0xDEED2024; + regs->c4_regs.r[17] = dtb_start_c4; + } + regs->c4_regs.pc = core4_init_pc; + } + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, regs); if (ret < 0) { fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); abort(); } - vcb = (struct vcpucb *)cpu->k_vcb; - vcb->vcpu_irq_disabled = 1; - ret = kvm_vcpu_ioctl(cs, KVM_SW64_VCPU_INIT, NULL); - if (ret < 0) { fprintf(stderr, "kvm_sw64_vcpu_init failed: %s\n", strerror(-ret)); abort(); @@ -120,7 +129,9 @@ int kvm_arch_get_registers(CPUState *cs) SW64CPU *cpu = SW64_CPU(cs); CPUSW64State *env = &cpu->env; - ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &cpu->k_regs); + struct kvm_regs *regs; + regs = (struct kvm_regs *)cpu->k_regs; + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, regs); if (ret < 0) return ret; @@ -128,25 +139,30 @@ int kvm_arch_get_registers(CPUState *cs) if (ret < 0) return ret; - for (i = 0; i < 16; i++) - env->ir[i] = cpu->k_regs[i]; - - env->ir[16] = cpu->k_regs[155]; - env->ir[17] = cpu->k_regs[156]; - env->ir[18] = cpu->k_regs[157]; - - for (i = 19; i < 29; i++) - env->ir[i] = cpu->k_regs[i-3]; - - env->ir[29] = cpu->k_regs[154]; - - if (cpu->k_regs[152] >> 3) - env->ir[30] = cpu->k_vcb[3]; /* usp */ - else - env->ir[30] = cpu->k_vcb[2]; /* ksp */ - - env->pc = cpu->k_regs[153]; - + if (test_feature(env, SW64_FEATURE_CORE3)) { + for (i = 0; i < 16; i++) + env->ir[i] = regs->c3_regs.r[i]; + + for (i = 19; i < 29; i++) + env->ir[i] = regs->c3_regs.r[i-3]; + + env->ir[16] = regs->c3_regs.r16; + env->ir[17] = regs->c3_regs.r17; + env->ir[18] = regs->c3_regs.r18; + + env->ir[29] = regs->c3_regs.gp; + env->pc = regs->c3_regs.pc; + if (regs->c3_regs.ps >> 3) + env->ir[30] = cpu->k_vcb[3]; //usp + else + env->ir[30] = cpu->k_vcb[2]; //ksp + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + for (i = 0; i < 30; i++) { + env->ir[i] = regs->c4_regs.r[i]; + } + env->ir[30] = cpu->k_vcb[44]; + env->pc = regs->c4_regs.pc; + } return 0; } @@ -154,41 +170,63 @@ int kvm_arch_put_registers(CPUState *cs, int level) { int ret; SW64CPU *cpu = SW64_CPU(cs); - struct vcpucb *vcb; - - if (level == KVM_PUT_RUNTIME_STATE) { - int i; - CPUSW64State *env = &cpu->env; - - for (i = 0; i < 16; i++) - cpu->k_regs[i] = env->ir[i]; - - for (i = 19; i < 29; i++) - cpu->k_regs[i-3] = env->ir[i]; - - cpu->k_regs[155] = env->ir[16]; - cpu->k_regs[156] = env->ir[17]; - cpu->k_regs[157] = env->ir[18]; - - cpu->k_regs[154] = env->ir[29]; + struct kvm_regs *regs; + CPUSW64State *env = &cpu->env; - if (cpu->k_regs[152] >> 3) - cpu->k_vcb[3] = env->ir[30]; /* usp */ - else - cpu->k_vcb[2] = env->ir[30]; /* ksp */ + regs = (struct kvm_regs *)cpu->k_regs; - cpu->k_regs[153] = env->pc; + if (level == KVM_PUT_RUNTIME_STATE) { + int i; + if (test_feature(env, SW64_FEATURE_CORE3)) { + for (i = 0; i < 16; i++) + regs->c3_regs.r[i] = env->ir[i]; + + for (i = 19; i < 29; i++) + regs->c3_regs.r[i-3] = env->ir[i]; + + regs->c3_regs.r16 = env->ir[16]; + regs->c3_regs.r17 = env->ir[17]; + regs->c3_regs.r18 = env->ir[18]; + + regs->c3_regs.gp = env->ir[29]; + + if (regs->c3_regs.ps >> 3) + cpu->k_vcb[3] = env->ir[30]; //usp + else + cpu->k_vcb[2] = env->ir[30]; //ksp + + regs->c3_regs.pc = env->pc; + } else if (test_feature(env, SW64_FEATURE_CORE4)) { + for (i = 0; i < 30; i++) { + regs->c4_regs.r[i] = env->ir[i]; + } + cpu->k_vcb[44] = env->ir[30]; + + /* Using for guest kernel debugging */ + if ((env->pc & 0x2) == 0) { + env->pc |= 0x2; + } + regs->c4_regs.pc = env->pc; + } } - ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &cpu->k_regs); + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, regs); if (ret < 0) return ret; - vcb = (struct vcpucb *)cpu->k_vcb; - vcb->whami = kvm_arch_vcpu_id(cs); - fprintf(stderr,"vcpu %ld init.\n", vcb->whami); - if (level == KVM_PUT_RESET_STATE) - vcb->pcbb = 0; + cpu->k_vcb[15] = kvm_arch_vcpu_id(cs); + fprintf(stderr,"vcpu %ld init.\n", cpu->k_vcb[15]); + + if (test_feature(env, SW64_FEATURE_CORE4)) { + if (level == KVM_PUT_RESET_STATE) { + /* Set initial value of PTBR_USR */ + cpu->k_vcb[27] = 0x0; + } + /* Set initial value of CSR_ATC */ + cpu->k_vcb[50] = 0x3; + /* Set initial value of CSR_PRI_BASE */ + cpu->k_vcb[51] = 0x10000; + } return kvm_vcpu_ioctl(cs, KVM_SW64_SET_VCB, &cpu->k_vcb); } @@ -266,6 +304,12 @@ bool kvm_sw64_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit) /* Ensure PC is synchronised */ kvm_cpu_synchronize_state(cs); + /* For gdb correctness, remove the mode bit if it exists */ + if (env->pc & 0x2) { + env->pc &= ~0x2; + debug_exit->epc &= ~0x2; + } + if (cs->singlestep_enabled) { return true; } else if (kvm_find_sw_breakpoint(cs, debug_exit->epc)) { diff --git a/target/sw64/machine.c b/target/sw64/machine.c index 93b1968ad8578dee4ada8c8d40e9b759f2969322..e117acf8821e8257c79c88eddd16e13c1bb92db5 100644 --- a/target/sw64/machine.c +++ b/target/sw64/machine.c @@ -10,8 +10,8 @@ VMStateDescription vmstate_sw64_cpu = { .minimum_version_id = 1, .fields = (VMStateField[]) { #ifdef CONFIG_KVM - VMSTATE_UINTTL_ARRAY(k_regs, SW64CPU, 158), - VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 48), + VMSTATE_UINTTL_ARRAY(k_regs, SW64CPU, 164), + VMSTATE_UINTTL_ARRAY(k_vcb, SW64CPU, 96), #endif VMSTATE_END_OF_LIST() } diff --git a/target/sw64/translate.c b/target/sw64/translate.c index 1e725b9294d3b8deb44cc6cbff54a1651efaf14b..43662eca21148f0a72191570a8295aa7607aa24c 100644 --- a/target/sw64/translate.c +++ b/target/sw64/translate.c @@ -343,9 +343,87 @@ static void gen_mask_h(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, tcg_temp_free(shift); } +static void gen_lshift_mask(TCGv v0, TCGv v1, int size) +{ + TCGv mask = tcg_const_i64((1UL << size) - 1); + int i; + + tcg_gen_shl_i64(mask, mask, v1); + tcg_gen_andi_i64(mask, mask, (uint64_t)((1UL << size) - 1)); + tcg_gen_mov_i64(v0, mask); + + for (i = size; i < 64; i = i * 2) { + tcg_gen_shli_i64(mask, v0, i); + tcg_gen_or_i64(v0, mask, v0); + } + tcg_temp_free(mask); +} + +static void gen_lshifti_mask(TCGv v0, int v1, int size) +{ + int i; + uint64_t mask; + mask = (1UL << size) - 1; + mask = (mask << v1) & (uint64_t)((1UL << size) - 1); + for (i = size; i < 64; i = i * 2) { + mask |= (mask << i); + } + tcg_gen_movi_i64(v0, mask); +} + +static void gen_rshift_mask(TCGv v0, TCGv v1, int size) +{ + TCGv mask = tcg_const_i64((1UL << size) - 1); + int i; + + tcg_gen_shr_i64(mask, mask, v1); + tcg_gen_mov_i64(v0, mask); + + for (i = size; i < 64; i = i * 2) { + tcg_gen_shli_i64(mask, v0, i); + tcg_gen_or_i64(v0, mask, v0); + } + tcg_temp_free(mask); +} + +static void gen_rshifti_mask(TCGv v0, int v1, int size) +{ + int i; + uint64_t mask; + mask = (1UL << size) - 1; + mask = (mask >> v1) & (uint64_t)((1UL << size) - 1); + for (i = size; i < 64; i = i * 2) { + mask |= (mask << i); + } + tcg_gen_movi_i64(v0, mask); +} + +static void gen_rsign_mask(TCGv v0, TCGv v1,int size) +{ + TCGv mask, tmp; + uint64_t sign_mask = 0; + mask = tcg_temp_new(); + tmp = tcg_temp_new(); + int i; + + for (i = 0; i < 64 / size; i++) { + sign_mask |= (1UL << (size - 1)) << (i * size); + } + + tcg_gen_andi_i64(mask, v1, sign_mask); + tcg_gen_mov_i64(tmp, mask); + for (i = 1; i < size; i = i * 2) { + tcg_gen_shri_i64(mask, tmp, i); + tcg_gen_or_i64(tmp, mask, tmp); + } + tcg_gen_andc_i64(v0, tmp, v0); + tcg_temp_free(mask); + tcg_temp_free(tmp); +} + static inline void gen_load_mem( DisasContext *ctx, void (*tcg_gen_qemu_load)(TCGv t0, TCGv t1, int flags), - int ra, int rb, int32_t disp16, bool fp, bool clear) + int ra, int rb, int32_t disp16, bool fp, uint64_t mask) { TCGv tmp, addr, va; @@ -366,20 +444,21 @@ static inline void gen_load_mem( tcg_gen_mov_i64(tmp, addr); addr = tmp; } - if (clear) { - tcg_gen_andi_i64(tmp, addr, ~0x7UL); - addr = tmp; + + if (mask) { + tcg_gen_andi_i64(addr, addr, mask); } va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); tcg_gen_qemu_load(va, addr, ctx->mem_idx); + //gen_helper_trace_mem(cpu_env, addr, va); tcg_temp_free(tmp); } static inline void gen_store_mem( DisasContext *ctx, void (*tcg_gen_qemu_store)(TCGv t0, TCGv t1, int flags), - int ra, int rb, int32_t disp16, bool fp, bool clear) + int ra, int rb, int32_t disp16, bool fp, uint64_t mask) { TCGv tmp, addr, va; @@ -392,9 +471,9 @@ static inline void gen_store_mem( tcg_gen_mov_i64(tmp, addr); addr = tmp; } - if (clear) { - tcg_gen_andi_i64(tmp, addr, ~0x7); - addr = tmp; + + if (mask) { + tcg_gen_andi_i64(addr, addr, mask); } va = (fp ? cpu_fr[ra] : load_gir(ctx, ra)); @@ -406,7 +485,8 @@ static inline void gen_store_mem( static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, int32_t disp13, uint16_t fn) { - TCGv tmp; + TCGv tmp, t1, tmp1; + TCGv_i32 tmpa, tmpb, tmpc; switch (fn & 0xff) { case 0x00: @@ -493,6 +573,62 @@ static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, tcg_gen_mul_i64(vc, va, vb); tcg_gen_ext32s_i64(vc, vc); break; + case 0x11: + /* TODO: DIVW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_div_i32(tmpc, tmpa, tmpb); + tcg_gen_ext_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; + case 0x12: + /* UDIVW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_divu_i32(tmpc, tmpa, tmpb); + tcg_gen_extu_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; + case 0x13: + /* REMW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_rem_i32(tmpc, tmpa, tmpb); + tcg_gen_ext_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; + case 0x14: + /* UREMW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_remu_i32(tmpc, tmpa, tmpb); + tcg_gen_extu_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; case 0x18: /* MULL */ tcg_gen_mul_i64(vc, va, vb); @@ -503,6 +639,42 @@ static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, tcg_gen_mulu2_i64(tmp, vc, va, vb); tcg_temp_free(tmp); break; + case 0x1A: + /* DIVL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_div_i64(vc, va, vb); + break; + case 0x1B: + /* UDIVL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_divu_i64(vc, va, vb); + break; + case 0x1C: + /* REML */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_rem_i64(vc, va, vb); + break; + case 0x1D: + /* UREML */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_remu_i64(vc, va, vb); + break; + case 0x1E: + /* TODO:ADDPI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_const_i64(disp13); + tcg_gen_shli_i64(tmp, tmp, 2); + tcg_gen_addi_i64(vc, tmp, ctx->base.pc_next & ~3UL); + tcg_temp_free_i64(tmp); + break; + case 0x1F: + /* ADDPIS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_const_i64(disp13); + tcg_gen_shli_i64(tmp, tmp, 16); + tcg_gen_addi_i64(vc, tmp, ctx->base.pc_next & 0xffffffffffff0000); + tcg_temp_free_i64(tmp); + break; case 0x28: /* CMPEQ */ tcg_gen_setcond_i64(TCG_COND_EQ, vc, va, vb); @@ -523,6 +695,28 @@ static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, /* CMPULE */ tcg_gen_setcond_i64(TCG_COND_LEU, vc, va, vb); break; + case 0x2D: + /* SBT */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + t1 = tcg_const_i64(1); + tcg_gen_andi_i64(tmp, vb, 0x3f); + tcg_gen_shl_i64(tmp, t1, tmp); + tcg_gen_or_i64(vc, va, tmp); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(t1); + break; + case 0x2E: + /* CBT */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + t1 = tcg_const_i64(1); + tcg_gen_andi_i64(tmp, vb, 0x3f); + tcg_gen_shl_i64(tmp, t1, tmp); + tcg_gen_andc_i64(vc, va, tmp); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(t1); + break; case 0x38: /* AND */ tcg_gen_and_i64(vc, va, vb); @@ -600,6 +794,60 @@ static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, tcg_gen_sar_i64(vc, va, tmp); tcg_temp_free(tmp); break; + case 0x4B: + /* ROLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + tcg_gen_andi_i64(tmp, vb, 0x3f); + tcg_gen_rotl_i64(vc, va, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x4C: + /* SLLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new(); + tmp1 = tcg_temp_new(); + tcg_gen_andi_i64(tmp, vb, 0x1f); + tcg_gen_ext32u_i64(tmp1, va); + tcg_gen_shl_i64(vc, tmp1, tmp); + tcg_gen_ext32u_i64(vc, vc); + tcg_temp_free(tmp); + tcg_temp_free(tmp1); + break; + case 0x4D: + /* SRLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new(); + tcg_gen_andi_i64(tmp, vb, 0x1f); + tcg_gen_ext32u_i64(va, va); + tcg_gen_shr_i64(vc, va, tmp); + tcg_gen_ext32u_i64(vc, vc); + tcg_temp_free(tmp); + break; + case 0x4E: + /* SRAW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new(); + tcg_gen_andi_i64(tmp, vb, 0x1f); + tcg_gen_ext32s_i64(va, va); + tcg_gen_sar_i64(vc, va, tmp); + tcg_gen_ext32u_i64(vc, vc); + tcg_temp_free(tmp); + break; + case 0x4F: + /* ROLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmpa = tcg_temp_new_i32(); + tmpb = tcg_temp_new_i32(); + tmpc = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(tmpa, va); + tcg_gen_extrl_i64_i32(tmpb, vb); + tcg_gen_rotl_i32(tmpc, tmpa, tmpb); + tcg_gen_extu_i32_i64(vc, tmpc); + tcg_temp_free_i32(tmpa); + tcg_temp_free_i32(tmpb); + tcg_temp_free_i32(tmpc); + break; case 0x50: /* EXTLB */ gen_ext_l(ctx, vc, va, vb, 0x1); @@ -644,6 +892,37 @@ static void cal_with_iregs_2(DisasContext *ctx, TCGv vc, TCGv va, TCGv vb, /* CTTZ */ tcg_gen_ctzi_i64(vc, vb, 64); break; + case 0x5B: + /* REVBH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + tcg_gen_andi_i64(tmp, vb, 0xffffUL); + tcg_gen_bswap16_i64(vc, tmp, TCG_BSWAP_IZ); + tcg_temp_free_i64(tmp); + break; + case 0x5C: + /* REVBW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp = tcg_temp_new_i64(); + tcg_gen_andi_i64(tmp, vb, 0xffffffffUL); + tcg_gen_bswap32_i64(vc, tmp, TCG_BSWAP_IZ); + tcg_temp_free_i64(tmp); + break; + case 0x5D: + /* REVBL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_bswap64_i64(vc, vb); + break; + case 0x5E: + /* CASW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_atomic_cmpxchg_i64(vc, vb, va, vc, ctx->mem_idx, MO_TEUL); + break; + case 0x5F: + /* CASL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_atomic_cmpxchg_i64(vc, vb, va, vc, ctx->mem_idx, MO_TEQ); + break; case 0x60: /* MASKLB */ gen_mask_l(ctx, vc, va, vb, 0x1); @@ -894,8 +1173,6 @@ static inline void gen_load_mem_simd( } tcg_gen_qemu_load(ra, addr, ctx->mem_idx); - // FIXME: for debug - tcg_temp_free(tmp); } @@ -917,9 +1194,7 @@ static inline void gen_store_mem_simd( if (mask) { tcg_gen_andi_i64(addr, addr, mask); } - // FIXME: for debug tcg_gen_qemu_store(ra, addr, ctx->mem_idx); - tcg_temp_free(tmp); } @@ -1142,6 +1417,18 @@ static void gen_fcvtdl(int rb, int rc, uint64_t round_mode) gen_fp_exc_raise(rc); } +static void gen_transformat(int rb, int rc, + void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv), + uint64_t round_mode) +{ + TCGv tmp64; + tmp64 = tcg_temp_new_i64(); + tcg_gen_movi_i64(tmp64, round_mode); + helper(cpu_fr[rc], cpu_env, cpu_fr[rb], tmp64); + tcg_temp_free(tmp64); + gen_fp_exc_raise(rc); +} + static void cal_with_fregs_2(DisasContext *ctx, uint8_t rc, uint8_t ra, uint8_t rb, uint8_t fn) { @@ -1325,6 +1612,68 @@ static void cal_with_fregs_2(DisasContext *ctx, uint8_t rc, uint8_t ra, gen_helper_setfpcrx(cpu_env, tmp64); tcg_temp_free(tmp64); break; + case 0x58: + /* TODO:FRECS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_frecs(ctx, ra, rc); + break; + case 0x59: + /* TODO:FRECD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_frecd(ctx, ra, rc); + break; + case 0x5A: + /* TODO:FRIS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, + 5); + break; + case 0x5B: + /* TODO:FRIS_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 0); + break; + case 0x5C: + /* TODO:FRIS_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 2); + break; + case 0x5D: + /* TODO:FRIS_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 3); + break; + case 0x5F: + /* TODO:FRIS_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_fris, 1); + break; + case 0x60: + /* TODO:FRID */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, + 5); + break; + case 0x61: + /* TODO:FRID_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 0); + break; + case 0x62: + /* TODO:FRID_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 2); + break; + case 0x63: + /* TODO:FRID_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 3); + break; + case 0x64: + /* TODO:FRID_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + gen_transformat(rb, rc, gen_helper_frid, 1); + break; default: fprintf(stderr, "Illegal insn func[%x]\n", fn); gen_invalid(ctx); @@ -1378,7 +1727,6 @@ static void cal_with_fregs_4(DisasContext *ctx, uint8_t rd, uint8_t ra, break; case 0x10: /* FSELEQ */ - // Maybe wrong translation. tmp64 = tcg_temp_new(); gen_helper_fcmpeq(tmp64, cpu_env, va, zero); tcg_gen_movcond_i64(TCG_COND_EQ, vd, tmp64, zero, vc, vb); @@ -1459,7 +1807,8 @@ static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb, lab_done = gen_new_label(); tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail); tcg_temp_free_i64(addr); - tcg_gen_brcondi_i64(TCG_COND_NE, cpu_lock_flag, 0x1, lab_fail); + if (test_feature(ctx->env, SW64_FEATURE_CORE3)) + tcg_gen_brcondi_i64(TCG_COND_NE, cpu_lock_flag, 0x1, lab_fail); #ifdef SW64_FIXLOCK TCGv val = tcg_temp_new_i64(); tcg_gen_atomic_cmpxchg_i64(val, cpu_lock_addr, cpu_lock_value, @@ -1476,6 +1825,11 @@ static DisasJumpType gen_store_conditional(DisasContext *ctx, int ra, int rb, tcg_gen_movi_i64(cpu_lock_success, 0); gen_set_label(lab_done); + if (test_feature(ctx->env, SW64_FEATURE_CORE4)) + { + tcg_gen_mov_i64(load_gir(ctx, ra), cpu_lock_success); + tcg_gen_movi_i64(cpu_lock_success, 0); + } tcg_gen_movi_i64(cpu_lock_flag, 0); tcg_gen_movi_i64(cpu_lock_addr, -1); return DISAS_NEXT; @@ -1663,6 +2017,43 @@ static void tcg_gen_sllowi_i64(int ra, int rc, int disp8) tcg_temp_free(shift); } +static void tcg_gen_sraow_i64(int ra, int rc, int rb) +{ + TCGv va, vb, vc; + TCGv shift; + + va = tcg_const_i64(ra); + vc = tcg_const_i64(rc); + shift = tcg_temp_new(); + vb = cpu_fr[rb]; + tcg_gen_shri_i64(shift, vb, 29); + tcg_gen_andi_i64(shift, shift, 0xff); + + gen_helper_sraow(cpu_env, va, vc, shift); + + tcg_temp_free(vc); + tcg_temp_free(va); + tcg_temp_free(shift); +} + +static void tcg_gen_sraowi_i64(int ra, int rc, int disp8) +{ + TCGv va, vc; + TCGv shift; + + va = tcg_const_i64(ra); + vc = tcg_const_i64(rc); + shift = tcg_temp_new(); + tcg_gen_movi_i64(shift, disp8); + tcg_gen_andi_i64(shift, shift, 0xff); + + gen_helper_sraow(cpu_env, va, vc, shift); + + tcg_temp_free(vc); + tcg_temp_free(va); + tcg_temp_free(shift); +} + static void gen_qemu_vstw_uh(int t0, TCGv t1, int memidx) { TCGv byte4_len; @@ -2226,7 +2617,7 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, int32_t i; TCGv va, vb, vc, vd; TCGv_i32 tmp32; - TCGv_i64 tmp64, tmp64_0, tmp64_1, shift; + TCGv_i64 tmp64, tmp64_0, tmp64_1, tmp64_2, tmp64_3, shift; TCGv_i32 tmpa, tmpb, tmpc; DisasJumpType ret; DisasContext* ctx = container_of(dcbase, DisasContext, base); @@ -2288,6 +2679,11 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, /* IMEMB */ /* No achievement in Qemu*/ break; + case 0x0002: + /* WMEMB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC); + break; case 0x0020: /* RTC */ if (disp16 && unlikely(ra == 31)) break; @@ -2315,12 +2711,14 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, break; case 0x1000: /* RD_F */ + if(test_feature(ctx->env, SW64_FEATURE_CORE4)) break; if (disp16 && unlikely(ra == 31)) break; va = load_gir(ctx, ra); tcg_gen_mov_i64(va, cpu_lock_success); break; case 0x1020: /* WR_F */ + if(test_feature(ctx->env, SW64_FEATURE_CORE4)) break; if (disp16 && unlikely(ra == 31)) break; va = load_gir(ctx, ra); tcg_gen_andi_i64(cpu_lock_flag, va, 0x1); @@ -2332,6 +2730,28 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, read_csr(0xc7, va); break; default: + if ((disp16 & 0xFF00) == 0xFC00) { + /* CSRWS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new_i64(); + read_csr(disp16 & 0xff, tmp64); + va = load_gir(ctx, ra); + tcg_gen_or_i64(tmp64, tmp64, va); + write_csr(disp16 & 0xff, tmp64, ctx->env); + tcg_temp_free_i64(tmp64); + break; + } + if ((disp16 & 0xFF00) == 0xFD00) { + /* CSRWC */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new_i64(); + read_csr(disp16 & 0xff, tmp64); + va = load_gir(ctx, ra); + tcg_gen_andc_i64(tmp64, tmp64, va); + write_csr(disp16 & 0xff, tmp64, ctx->env); + tcg_temp_free_i64(tmp64); + break; + } if ((disp16 & 0xFF00) == 0xFE00) { /* PRI_RCSR */ if (disp16 && unlikely(ra == 31)) break; @@ -2342,7 +2762,7 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, if ((disp16 & 0xFF00) == 0xFF00) { /* PRI_WCSR */ va = load_gir(ctx, ra); - write_csr(disp16 & 0xff, va, ctx->env); + write_csr(disp16 & 0xff, va ,ctx->env); break; } goto do_invalid; @@ -2926,82 +3346,476 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, tcg_gen_subi_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8); } break; - case 0x18: - /* CTPOPOW */ - tmp64 = tcg_const_i64(0); - tmp64_0 = tcg_temp_new(); - + case 0x10: + /* VSLLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + gen_lshift_mask(tmp64, shift, 8); for (i = 0; i < 128; i += 32) { - tcg_gen_ctpop_i64(tmp64_0, cpu_fr[ra + i]); - tcg_gen_add_i64(tmp64, tmp64, tmp64_0); + tcg_gen_shl_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); } - tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); tcg_temp_free(tmp64); - tcg_temp_free(tmp64_0); - break; - case 0x19: - /* CTLZOW */ - va = tcg_const_i64(ra); - gen_helper_ctlzow(cpu_fr[rc], cpu_env, va); - tcg_temp_free(va); + tcg_temp_free(shift); break; - case 0x40: - /* VUCADDW */ - va = tcg_const_i64(ra); - vb = tcg_const_i64(rb); - vc = tcg_const_i64(rc); - gen_helper_vucaddw(cpu_env, va, vb, vc); - tcg_temp_free(va); - tcg_temp_free(vb); - tcg_temp_free(vc); + case 0x30: + /* VSLLBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0x7UL, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x7UL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); break; - case 0x60: - /* VUCADDW */ - va = tcg_const_i64(ra); - vb = tcg_const_i64(disp8); - vc = tcg_const_i64(rc); - gen_helper_vucaddwi(cpu_env, va, vb, vc); - tcg_temp_free(va); - tcg_temp_free(vb); - tcg_temp_free(vc); + case 0x11: + /* VSRLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + gen_rshift_mask(tmp64, shift, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_shr_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(shift); break; - case 0x41: - /* VUCSUBW */ - va = tcg_const_i64(ra); - vb = tcg_const_i64(rb); - vc = tcg_const_i64(rc); - gen_helper_vucsubw(cpu_env, va, vb, vc); - tcg_temp_free(va); - tcg_temp_free(vb); - tcg_temp_free(vc); + case 0x31: + /* VSRLBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0x7UL, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x7UL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } break; - case 0x61: - /* VUCSUBW */ - va = tcg_const_i64(ra); - vb = tcg_const_i64(disp8); - vc = tcg_const_i64(rc); - gen_helper_vucsubwi(cpu_env, va, vb, vc); - tcg_temp_free(va); - tcg_temp_free(vb); - tcg_temp_free(vc); + case 0x12: + /* VSRAB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + gen_rshift_mask(tmp64, shift, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 8); + tcg_gen_sar_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(shift); break; - case 0x42: - /* VUCADDH */ - va = tcg_const_i64(ra); - vb = tcg_const_i64(rb); - vc = tcg_const_i64(rc); - gen_helper_vucaddh(cpu_env, va, vb, vc); - tcg_temp_free(va); - tcg_temp_free(vb); - tcg_temp_free(vc); + case 0x32: + /* VSRABI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0x7UL, 8); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 8); + tcg_gen_sari_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8 & 0x7UL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); break; - case 0x62: - /* VUCADDH */ - va = tcg_const_i64(ra); - vb = tcg_const_i64(disp8); - vc = tcg_const_i64(rc); - gen_helper_vucaddhi(cpu_env, va, vb, vc); - tcg_temp_free(va); + case 0x13: + /* VROLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0x7UL); + tcg_gen_subfi_i64(tmp64_3, 8, shift); + gen_lshift_mask(tmp64, shift, 8); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shl_i64(tmp64_1, cpu_fr[ra + i], shift); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shr_i64(tmp64_2, cpu_fr[ra + i], tmp64_3); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + break; + case 0x33: + /* VROLBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0x7UL, 8); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(tmp64_1, cpu_fr[ra + i], disp8 & 0x7UL); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shri_i64(tmp64_2, cpu_fr[ra + i], 8 - (disp8 & 0x7UL)); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + break; + case 0x14: + /* VSLLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + gen_lshift_mask(tmp64, shift, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shl_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(shift); + break; + case 0x34: + /* VSLLHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0xfUL, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0xfUL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + break; + case 0x15: + /* VSRLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + gen_rshift_mask(tmp64, shift, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shr_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(shift); + break; + case 0x35: + /* VSRLHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0xfUL, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0xfUL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + break; + case 0x16: + /* VSRAH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + gen_rshift_mask(tmp64, shift, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 16); + tcg_gen_sar_i64(cpu_fr[rc + i], cpu_fr[ra + i], shift); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(shift); + break; + case 0x36: + /* VSRAHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + shift = tcg_temp_new(); + gen_rshifti_mask(tmp64, disp8 & 0xfUL, 16); + for (i = 0; i < 128; i += 32) { + tcg_gen_mov_i64(tmp64_0, tmp64); + gen_rsign_mask(tmp64_0, cpu_fr[ra + i], 16); + tcg_gen_sari_i64(cpu_fr[rc + i], cpu_fr[ra + i], disp8 & 0xfUL); + tcg_gen_and_i64(cpu_fr[rc + i], tmp64, cpu_fr[rc + i]); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_0, cpu_fr[rc + i]); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(shift); + break; + case 0x17: + /* VROLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_shri_i64(shift, cpu_fr[rb], 29); + tcg_gen_andi_i64(shift, shift, 0xfUL); + tcg_gen_subfi_i64(tmp64_3, 16, shift); + gen_lshift_mask(tmp64, shift, 16); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shl_i64(tmp64_1, cpu_fr[ra + i], shift); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shr_i64(tmp64_2, cpu_fr[ra + i], tmp64_3); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + break; + case 0x37: + /* VROLHI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tmp64_1 = tcg_temp_new(); + tmp64_2 = tcg_temp_new(); + tmp64_3 = tcg_temp_new(); + shift = tcg_temp_new(); + gen_lshifti_mask(tmp64, disp8 & 0xfUL, 16); + tcg_gen_not_i64(tmp64_0, tmp64); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(tmp64_1, cpu_fr[ra + i], disp8 & 0xfUL); + tcg_gen_and_i64(tmp64_1, tmp64_1, tmp64); + tcg_gen_shri_i64(tmp64_2, cpu_fr[ra + i], 16 - (disp8 & 0xfUL)); + tcg_gen_and_i64(tmp64_2, tmp64_2, tmp64_0); + tcg_gen_or_i64(cpu_fr[rc + i], tmp64_1, tmp64_2); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + tcg_temp_free(tmp64_1); + tcg_temp_free(tmp64_2); + tcg_temp_free(tmp64_3); + tcg_temp_free(shift); + break; + case 0x18: + /* CTPOPOW */ + tmp64 = tcg_const_i64(0); + tmp64_0 = tcg_temp_new(); + + for (i = 0; i < 128; i += 32) { + tcg_gen_ctpop_i64(tmp64_0, cpu_fr[ra + i]); + tcg_gen_add_i64(tmp64, tmp64, tmp64_0); + } + tcg_gen_shli_i64(cpu_fr[rc], tmp64, 29); + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0x19: + /* CTLZOW */ + va = tcg_const_i64(ra); + gen_helper_ctlzow(cpu_fr[rc], cpu_env, va); + tcg_temp_free(va); + break; + case 0x1A: + /* VSLLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_shl_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3A: + /* VSLLLI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_shli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1B: + /* VSRLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_shr_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3B: + /* VSRLLI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1C: + /* VSRAL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_sar_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3C: + /* VSRALI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_sari_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1D: + /* VROLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_shri_i64(tmp64, cpu_fr[rb], 29); + tcg_gen_andi_i64(tmp64, tmp64, 0x3f); + + tcg_gen_rotl_i64(cpu_fr[rc + i], cpu_fr[ra + i], tmp64); + } + tcg_temp_free(tmp64); + break; + case 0x3D: + /* VROLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + tcg_gen_rotli_i64(cpu_fr[rc + i], cpu_fr[ra + i], + disp8 & 0x3f); + } + break; + case 0x1E: + /* VMAXB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vmaxb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x1F: + /* VMINB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vminb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x40: + /* VUCADDW */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vucaddw(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x60: + /* VUCADDW */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vucaddwi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x41: + /* VUCSUBW */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vucsubw(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x61: + /* VUCSUBW */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vucsubwi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x42: + /* VUCADDH */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vucaddh(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x62: + /* VUCADDH */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vucaddhi(cpu_env, va, vb, vc); + tcg_temp_free(va); tcg_temp_free(vb); tcg_temp_free(vc); break; @@ -3035,32 +3849,322 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, tcg_temp_free(vb); tcg_temp_free(vc); break; - case 0x64: - /* VUCADDB */ + case 0x64: + /* VUCADDB */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vucaddbi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x45: + /* VUCSUBB */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vucsubb(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x65: + /* VUCSUBB */ + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vucsubbi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x46: + /* SRAOW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_sraow_i64(ra, rc, rb); + break; + case 0x66: + /* SRAOWI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_sraowi_i64(ra, rc, disp8); + break; + case 0x47: + /* TODO:VSUMW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tcg_gen_ext32u_i64(tmp64, cpu_fr[ra]); + tcg_gen_shri_i64(cpu_fr[rc], cpu_fr[ra], 32); + tcg_gen_add_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + for (i = 32; i < 128; i += 32) { + tcg_gen_ext32u_i64(tmp64, cpu_fr[ra + i]); + tcg_gen_add_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shri_i64(tmp64, cpu_fr[ra + i], 32); + tcg_gen_add_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + } + tcg_temp_free(tmp64); + break; + case 0x48: + /* VSUML */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tcg_gen_mov_i64(cpu_fr[rc], cpu_fr[ra]); + for (i = 32; i < 128; i += 32) { + tcg_gen_add_i64(cpu_fr[rc], cpu_fr[ra + i], cpu_fr[rc]); + } + break; + case 0x49: + /* VSM4R */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vsm4r(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x4A: + /* VBINVW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + for (i = 0; i < 128; i += 32) { + tcg_gen_bswap64_i64(tmp64, cpu_fr[rb + i]); + tcg_gen_rotli_i64(tmp64, tmp64, 32); + tcg_gen_mov_i64(cpu_fr[rc + i], tmp64); + } + break; + case 0x4B: + /* VCMPUEQB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vcmpueqb(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x6B: + /* VCMPUEQBI*/ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vcmpueqbi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x4C: + /* VCMPUGTB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vcmpugtb(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x6C: + /* VCMPUGTBI */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(disp8); + vc = tcg_const_i64(rc); + gen_helper_vcmpugtbi(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x4D: + /* VSM3MSW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + gen_helper_vsm3msw(cpu_env, va, vb, vc); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x50: + /* VMAXH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vmaxh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x51: + /* VMINH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vminh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x52: + /* VMAXW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vmaxw(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x53: + /* VMINW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vminw(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x54: + /* VMAXL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_GE, vc, va, vb, va, vb); + } + break; + case 0x55: + /* VMINL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_LE, vc, va, vb, va, vb); + } + break; + case 0x56: + /* VUMAXB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vumaxb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x57: + /* VUMINB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vuminb(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x58: + /* VUMAXH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vumaxh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x59: + /* VUMINH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rc); + + gen_helper_vuminh(cpu_env, va, vb, vc); + + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + break; + case 0x5A: + /* VUMAXW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); va = tcg_const_i64(ra); - vb = tcg_const_i64(disp8); + vb = tcg_const_i64(rb); vc = tcg_const_i64(rc); - gen_helper_vucaddbi(cpu_env, va, vb, vc); + + gen_helper_vumaxw(cpu_env, va, vb, vc); + tcg_temp_free(va); tcg_temp_free(vb); tcg_temp_free(vc); break; - case 0x45: - /* VUCSUBB */ + case 0x5B: + /* VUMINW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); va = tcg_const_i64(ra); vb = tcg_const_i64(rb); vc = tcg_const_i64(rc); - gen_helper_vucsubb(cpu_env, va, vb, vc); + + gen_helper_vuminw(cpu_env, va, vb, vc); + tcg_temp_free(va); tcg_temp_free(vb); tcg_temp_free(vc); break; - case 0x65: - /* VUCSUBB */ + case 0x5C: + /* VUMAXL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_GEU, vc, va, vb, va, vb); + } + break; + case 0x5D: + /* VUMINL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + tcg_gen_movcond_i64(TCG_COND_LEU, vc, va, vb, va, vb); + } + break; + case 0x68: + /* VSM4KEY */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); va = tcg_const_i64(ra); vb = tcg_const_i64(disp8); vc = tcg_const_i64(rc); - gen_helper_vucsubbi(cpu_env, va, vb, vc); + gen_helper_vsm4key(cpu_env, va, vb, vc); tcg_temp_free(va); tcg_temp_free(vb); tcg_temp_free(vc); @@ -3161,6 +4265,224 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, gen_faddd(ctx, rc, ra + 64, rc); gen_faddd(ctx, rc, ra + 96, rc); break; + case 0x95: + /* VFCVTSD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtsd(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x96: + /* VFCVTDS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtds(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x99: + /* VFCVTLS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtls(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x9A: + /* VFCVTLD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtld(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x9B: + /* VFCVTDL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_helper_fcvtdl_dyn(cpu_fr[rc + i], cpu_env, + cpu_fr[rb + i]); + } + break; + case 0x9C: + /* VFCVTDL_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 0); + } + break; + case 0x9D: + /* VFCVTDL_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 2); + } + break; + case 0x9E: + /* VFCVTDL_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 3); + } + break; + case 0x9F: + /* VFCVTDL_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_fcvtdl(rb + i, rc + i, 1); + } + break; + case 0xA0: + /* VFRIS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat( + rb + i, rc + i, gen_helper_fris, + 5); + } + break; + case 0xA1: + /* VFRIS_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 0); + } + break; + case 0xA2: + /* VFRIS_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 2); + } + break; + case 0xA3: + /* VFRIS_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 3); + } + break; + case 0xA4: + /* VFRIS_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_fris, 1); + } + break; + case 0xA5: + /* VFRID */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 5); + } + break; + case 0xA6: + /* VFRID_G */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 0); + } + break; + case 0xA7: + /* VFRID_P */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 2); + } + break; + case 0xA8: + /* VFRID_Z */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 3); + } + break; + case 0xA9: + /* VFRID_N */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_transformat(rb + i, rc + i, gen_helper_frid, 1); + } + break; + case 0xAA: + /* VFRECS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_frecs(ctx, ra + i, rc + i); + } + break; + case 0xAB: + /* VFRECD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + for (i = 0; i < 128; i += 32) { + gen_frecd(ctx, ra + i, rc + i); + } + break; + case 0xAC: + /* VMAXS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmpge_s(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0xAD: + /* VMINS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmple_s(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0xAE: + /* VMAXD */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmpge(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; + case 0xAF: + /* VMIND */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_const_i64(0); + for (i = 0; i < 128; i += 32) { + va = cpu_fr[ra + i]; + vb = cpu_fr[rb + i]; + vc = cpu_fr[rc + i]; + gen_helper_fcmple(tmp64, cpu_env, va, vb); + tcg_gen_movcond_i64(TCG_COND_NE, vc, tmp64, tmp64_0, + va, vb); + } + tcg_temp_free(tmp64); + tcg_temp_free(tmp64_0); + break; default: printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn8); ret = gen_invalid(ctx); @@ -3368,10 +4690,6 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, /* VCPYW */ tmp64 = tcg_temp_new(); tmp64_0 = tcg_temp_new(); - /* FIXME: for debug - tcg_gen_movi_i64(tmp64, ra); - gen_helper_v_print(cpu_env, tmp64); - */ tcg_gen_shri_i64(tmp64, cpu_fr[ra], 29); tcg_gen_andi_i64(tmp64_0, tmp64, 0x3fffffffUL); tcg_gen_shri_i64(tmp64, cpu_fr[ra], 62); @@ -3384,12 +4702,6 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rc]); tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[rc]); tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rc]); - /* FIXME: for debug - tcg_gen_movi_i64(tmp64, rb); - gen_helper_v_print(cpu_env, tmp64); - tcg_gen_movi_i64(tmp64, rc); - gen_helper_v_print(cpu_env, tmp64); - */ tcg_temp_free(tmp64); tcg_temp_free(tmp64_0); break; @@ -3444,6 +4756,166 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, tcg_temp_free(tmp64); tcg_temp_free(vd); break; + case 0x2A: + /* VINSB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = cpu_fr[ra]; + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vinsb(cpu_env, va, vb, vc, vd); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x2B: + /* VINSH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = cpu_fr[ra]; + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vinsh(cpu_env, va, vb, vc, vd); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x2C: + /* VINSECTLH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vinsectlh(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x2D: + /* VINSECTLW */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vinsectlw(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x2E: + /* VINSECTLL */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tmp64_0 = tcg_temp_new(); + tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rb + 32]); + tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[ra + 32]); + tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rb]); + tcg_gen_mov_i64(cpu_fr[rc], cpu_fr[ra]); + break; + case 0x2F: + /* VINSECTLB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vinsectlb(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x30: + /* VSHFQ */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vshfq(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x31: + /* VSHFQB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vd = tcg_const_i64(rc); + gen_helper_vshfqb(cpu_env, va, vb, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vd); + break; + case 0x32: + /* VCPYB */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[ra], 0xffUL); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 8); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 16); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 32); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rc]); + tcg_temp_free(tmp64); + break; + case 0x33: + /* VCPYH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + tmp64 = tcg_temp_new(); + tcg_gen_andi_i64(cpu_fr[rc], cpu_fr[ra], 0xffffUL); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 16); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_shli_i64(tmp64, cpu_fr[rc], 32); + tcg_gen_or_i64(cpu_fr[rc], tmp64, cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 32], cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 64], cpu_fr[rc]); + tcg_gen_mov_i64(cpu_fr[rc + 96], cpu_fr[rc]); + tcg_temp_free(tmp64); + break; + case 0x34: + /* VSM3R */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vsm3r(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x35: + /* VFCVTSH */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vfcvtsh(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; + case 0x36: + /* VFCVTHS */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + va = tcg_const_i64(ra); + vb = tcg_const_i64(rb); + vc = tcg_const_i64(rd); + vd = tcg_const_i64(rc); + gen_helper_vfcvths(cpu_env, va, vb, vc, vd); + tcg_temp_free(va); + tcg_temp_free(vb); + tcg_temp_free(vc); + tcg_temp_free(vd); + break; default: printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn6); ret = gen_invalid(ctx); @@ -3529,6 +5001,100 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, break; } break; + case 0x1D: + /* LBR */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + ret = gen_bdirect(ctx, 31, disp26); + break; + case 0x1E: + /* LD/ST CORE4 */ + arch_assert(test_feature(ctx->env, SW64_FEATURE_CORE4)); + switch (fn4) { + case 0x0: + /* LDBU_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x1: + /* LDHU_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x2: + /* LDW_A */ + vb = load_gir(ctx, rb); + /* SEXT to ra */ + gen_load_mem(ctx, &tcg_gen_qemu_ld32s, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x3: + /* LDL_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x4: + /* FLDS_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &gen_qemu_flds, ra, rb, 0, 1, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x5: + /* FLDD_A */ + vb = load_gir(ctx, rb); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, 0, 1, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x6: + /* STBU_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st8, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x7: + /* STHU_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x8: + /* STW_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st32, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0x9: + /* STL_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, 0, 0, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0xA: + /* FSTS_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &gen_qemu_fsts, ra, rb, 0, 1, 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0xB: + /* FSTD_A */ + vb = load_gir(ctx, rb); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, 0, 1, + 0); + tcg_gen_addi_i64(vb, vb, disp12); + break; + case 0xE: + /* TODO: DPFHR */ + break; + case 0xF: + /* TODO: DPFHW */ + break; + default: + printf("ILLEGAL BELOW OPC[%x] func[%08x]\n", opc, fn4); + ret = gen_invalid(ctx); + } + break; case 0x20: /* LDBU */ gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0); @@ -3547,15 +5113,15 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, break; case 0x24: /* LDL_U */ - gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1); + gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, ~0x7UL); break; case 0x25: /* PRI_LD */ #ifndef CONFIG_USER_ONLY if ((insn >> 12) & 1) { - gen_load_mem(ctx, &gen_qemu_pri_ldl, ra, rb, disp12, 0, 1); + gen_load_mem(ctx, &gen_qemu_pri_ldl, ra, rb, disp12, 0, ~0x7UL); } else { - gen_load_mem(ctx, &gen_qemu_pri_ldw, ra, rb, disp12, 0, 1); + gen_load_mem(ctx, &gen_qemu_pri_ldw, ra, rb, disp12, 0, ~0x3UL); } #endif break; @@ -3585,15 +5151,15 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, break; case 0x2c: /* STL_U */ - gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, 1); + gen_store_mem(ctx, &tcg_gen_qemu_st64, ra, rb, disp16, 0, ~0x7UL); break; case 0x2d: /* PRI_ST */ #ifndef CONFIG_USER_ONLY if ((insn >> 12) & 1) { - gen_store_mem(ctx, &gen_qemu_pri_stl, ra, rb, disp12, 0, 1); + gen_store_mem(ctx, &gen_qemu_pri_stl, ra, rb, disp12, 0, ~0x7UL); } else { - gen_store_mem(ctx, &gen_qemu_pri_stw, ra, rb, disp12, 0, 1); + gen_store_mem(ctx, &gen_qemu_pri_stw, ra, rb, disp12, 0, ~0x3UL); } #endif break; @@ -3664,7 +5230,7 @@ DisasJumpType translate_one(DisasContextBase *dcbase, uint32_t insn, case 0x3f: /* LDIH */ disp16 = ((uint32_t)disp16) << 16; - if (ra == 31) break; + if (ra == 31) break; va = load_gir(ctx, ra); if (rb == 31) { tcg_gen_movi_i64(va, disp16); @@ -3728,7 +5294,6 @@ static void sw64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) translator_loop_temp_check(&ctx->base); } -/* FIXME:Linhainan */ static void sw64_tr_tb_stop(DisasContextBase* dcbase, CPUState* cpu) { DisasContext* ctx = container_of(dcbase, DisasContext, base); @@ -3753,7 +5318,6 @@ static void sw64_tr_tb_stop(DisasContextBase* dcbase, CPUState* cpu) { /* FALLTHRU */ case DISAS_PC_UPDATED_NOCHAIN: if (ctx->base.singlestep_enabled) { - /* FIXME: for gdb*/ cpu_loop_exit(cpu); } else { tcg_gen_exit_tb(NULL, 0); @@ -3766,7 +5330,7 @@ static void sw64_tr_tb_stop(DisasContextBase* dcbase, CPUState* cpu) { static void sw64_tr_disas_log(const DisasContextBase* dcbase, CPUState* cpu) { SW64CPU* sc = SW64_CPU(cpu); - qemu_log("IN(%d): %s\n", sc->cid, + qemu_log("IN(%d): %s\n", sc->core_id, lookup_symbol(dcbase->pc_first)); log_target_disas(cpu, dcbase->pc_first & (~0x3UL), dcbase->tb->size); }