diff options
author | Richard Miller <miller.research@gmail.com> | 2020-11-09 11:33:44 +0000 |
---|---|---|
committer | Richard Miller <miller.research@gmail.com> | 2020-11-09 11:33:44 +0000 |
commit | 2a571cc0ece4073eb56d5ccfc3e061a09a353e13 (patch) | |
tree | 7daccd0dac9144a55a00570e3fb11af7f0862659 | |
parent | ed97654bd7a11d480b44505c8300d06b42e5fefe (diff) |
Add riscv and riscv64 support to libmach
-rw-r--r-- | utils/include/a.out.h | 4 | ||||
-rw-r--r-- | utils/include/mach.h | 12 | ||||
-rw-r--r-- | utils/libmach/elf.h | 1 | ||||
-rw-r--r-- | utils/libmach/executable.c | 30 | ||||
-rw-r--r-- | utils/libmach/i.c | 70 | ||||
-rw-r--r-- | utils/libmach/idb.c | 697 | ||||
-rw-r--r-- | utils/libmach/iobj.c | 134 | ||||
-rw-r--r-- | utils/libmach/j.c | 70 | ||||
-rw-r--r-- | utils/libmach/mkfile | 4 | ||||
-rw-r--r-- | utils/libmach/obj.c | 6 | ||||
-rw-r--r-- | utils/libmach/setmach.c | 16 | ||||
-rw-r--r-- | utils/libmach/uregi.h | 57 | ||||
-rw-r--r-- | utils/libmach/uregj.h | 39 |
13 files changed, 1136 insertions, 4 deletions
diff --git a/utils/include/a.out.h b/utils/include/a.out.h index 86c7d061..915cdaae 100644 --- a/utils/include/a.out.h +++ b/utils/include/a.out.h @@ -31,9 +31,11 @@ struct Exec #define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */ #define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */ #define R_MAGIC _MAGIC(HDR_MAGIC, 28) /* arm64 */ +#define Z_MAGIC _MAGIC(0, 29) /* riscv */ +#define Y_MAGIC _MAGIC(0, 30) /* riscv64 */ #define MIN_MAGIC 8 -#define MAX_MAGIC 28 /* <= 90 */ +#define MAX_MAGIC 30 /* <= 90 */ #define DYN_MAGIC 0x80000000 /* dlm */ diff --git a/utils/include/mach.h b/utils/include/mach.h index 1c8d7a83..25e89279 100644 --- a/utils/include/mach.h +++ b/utils/include/mach.h @@ -16,6 +16,8 @@ * powerpc, * powerpc64 * arm64 + * riscv + * riscv64 */ enum { @@ -36,6 +38,8 @@ enum MAMD64, MPOWER64, MARM64, + MRISCV, + MRISCV64, /* types of executables */ FNONE = 0, /* unidentified */ FMIPS, /* v.out */ @@ -67,6 +71,10 @@ enum FPOWER64B, /* 9.out bootable */ FARM64, /* arm64 */ FARM64B, /* arm64 bootable */ + FRISCV, /* riscv */ + FRISCVB, /* riscv bootable */ + FRISCV64, /* riscv64 */ + FRISCV64B, /* riscv64 bootable */ ANONE = 0, /* dissembler types */ AMIPS, @@ -85,6 +93,8 @@ enum AAMD64, APOWER64, AARM64, + ARISCV, + ARISCV64, /* object file types */ Obj68020 = 0, /* .2 */ ObjSparc, /* .k */ @@ -103,6 +113,8 @@ enum ObjSpim, /* .0 */ ObjPower64, /* .9 */ ObjArm64, /* .4? */ + ObjRiscv, /* .i */ + ObjRiscv64, /* .j */ Maxobjtype, CNONE = 0, /* symbol table classes */ diff --git a/utils/libmach/elf.h b/utils/libmach/elf.h index 6bd483d2..e945ba11 100644 --- a/utils/libmach/elf.h +++ b/utils/libmach/elf.h @@ -84,6 +84,7 @@ enum { ARM = 40, /* ARM */ AMD64 = 62, /* Amd64 */ ARM64 = 183, /* ARM64 */ + RISCV = 243, /* RISC-V */ NO_VERSION = 0, /* version, ident[VERSION] */ CURRENT = 1, diff --git a/utils/libmach/executable.c b/utils/libmach/executable.c index b9954f0a..2734cf44 100644 --- a/utils/libmach/executable.c +++ b/utils/libmach/executable.c @@ -65,6 +65,8 @@ extern Mach mamd64; extern Mach marm; extern Mach mpower; extern Mach mpower64; +extern Mach mriscv; +extern Mach mriscv64; ExecTable exectab[] = { @@ -203,6 +205,24 @@ ExecTable exectab[] = sizeof(Exec), leswal, armdotout }, + { Z_MAGIC, /* riscv i.out */ + "riscv executable", + nil, + FRISCV, + 0, + &mriscv, + sizeof(Exec), + beswal, + common }, + { Y_MAGIC, /* riscv j.out */ + "riscv64 executable", + nil, + FRISCV64, + 0, + &mriscv64, + sizeof(Exec), + beswal, + common }, { 0 }, }; @@ -357,6 +377,12 @@ commonboot(Fhdr *fp) fp->name = "amd64 plan 9 boot image"; fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); break; + case FRISCV: + fp->type = FRISCVB; + fp->txtaddr = (u32int)fp->entry; + fp->name = "riscv plan 9 boot image"; + fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize); + break; default: return; } @@ -580,6 +606,10 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) mach = &marm; fp->type = FARM; break; + case RISCV: + mach = &mriscv; + fp->type = FRISCV; + break; default: return 0; } diff --git a/utils/libmach/i.c b/utils/libmach/i.c new file mode 100644 index 00000000..659ca3c3 --- /dev/null +++ b/utils/libmach/i.c @@ -0,0 +1,70 @@ +/* + * RISC-V definition + */ +#include <lib9.h> +#include <bio.h> +#include "uregi.h" +#include <mach.h> + +#define REGOFF(x) offsetof(struct Ureg, x) +#define REGSIZE sizeof(struct Ureg) + +Reglist riscvreglist[] = { + {"PC", REGOFF(pc), RINT, 'X'}, + {"SP", REGOFF(r27), RINT, 'X'}, + {"R31", REGOFF(r31), RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mriscv = +{ + "riscv", + MRISCV, /* machine type */ + riscvreglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R1", /* name of link register */ + "setSB", /* static base register name */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0x80000000ULL, /* kernel base */ + 0xC0000000ULL, /* kernel text mask */ + 0x3FFFFFFFULL, /* user stack top */ + 2, /* quantization of pc */ + 4, /* szaddr */ + 4, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/idb.c b/utils/libmach/idb.c new file mode 100644 index 00000000..62df623e --- /dev/null +++ b/utils/libmach/idb.c @@ -0,0 +1,697 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> +#include "ic/i.out.h" + +static char *riscvexcep(Map*, Rgetter); + +/* + * RISCV-specific debugger interface + */ + +typedef struct Instr Instr; +struct Instr +{ + Map *map; + ulong w; + uvlong addr; + char *fmt; + int n; + int op; + int func3; + int func7; + char rs1, rs2, rs3, rd; + char rv64; + long imm; + + char* curr; /* fill point in buffer */ + char* end; /* end of buffer */ +}; + +typedef struct Optab Optab; +struct Optab { + int func7; + int op[8]; +}; + +typedef struct Opclass Opclass; +struct Opclass { + char *fmt; + Optab tab[4]; +}; + +/* Major opcodes */ +enum { + OLOAD, OLOAD_FP, Ocustom_0, OMISC_MEM, OOP_IMM, OAUIPC, OOP_IMM_32, O48b, + OSTORE, OSTORE_FP, Ocustom_1, OAMO, OOP, OLUI, OOP_32, O64b, + OMADD, OMSUB, ONMSUB, ONMADD, OOP_FP, Ores_0, Ocustom_2, O48b_2, + OBRANCH, OJALR, Ores_1, OJAL, OSYSTEM, Ores_2, Ocustom_3, O80b +}; + +/* copy anames from compiler */ +static +#include "ic/enam.c" + +static Opclass opOLOAD = { + "a,d", + 0, AMOVB, AMOVH, AMOVW, AMOV, AMOVBU, AMOVHU, AMOVWU, 0, +}; +static Opclass opOLOAD_FP = { + "a,fd", + 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0, +}; +static Opclass opOMISC_MEM = { + "", + 0, AFENCE, AFENCE_I,0, 0, 0, 0, 0, 0, +}; +static Opclass opOOP_IMM = { + "$i,s,d", + 0x20, 0, 0, 0, 0, 0, ASRA, 0, 0, + 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND, +}; +static Opclass opOAUIPC = { + "$i(PC),d", + 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, +}; +static Opclass opOOP_IMM_32 = { + "$i,s,d", + 0x20, 0, 0, 0, 0, 0, ASRAW, 0, 0, + 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0, +}; +static Opclass opOSTORE = { + "2,a", + 0, AMOVB, AMOVH, AMOVW, AMOV, 0, 0, 0, 0, +}; +static Opclass opOSTORE_FP = { + "f2,a", + 0, 0, 0, AMOVF, AMOVD, 0, 0, 0, 0, +}; +static Opclass opOAMO = { + "7,2,s,d", + 0x04, 0, 0, ASWAP_W,ASWAP_D,0, 0, 0, 0, + 0x08, 0, 0, ALR_W, ALR_D, 0, 0, 0, 0, + 0x0C, 0, 0, ASC_W, ASC_D, 0, 0, 0, 0, + 0, 0, 0, AAMO_W, AAMO_D, 0, 0, 0, 0, +}; +static Opclass opOOP = { + "2,s,d", + 0x01, AMUL, AMULH, AMULHSU,AMULHU, ADIV, ADIVU, AREM, AREMU, + 0x20, ASUB, 0, 0, 0, 0, ASRA, 0, 0, + 0, AADD, ASLL, ASLT, ASLTU, AXOR, ASRL, AOR, AAND, +}; +static Opclass opOLUI = { + "$i,d", + 0, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, ALUI, +}; +static Opclass opOOP_32 = { + "2,s,d", + 0x01, AMULW, 0, 0, 0, ADIVW, ADIVUW, AREMW, AREMUW, + 0x20, ASUBW, 0, 0, 0, 0, ASRAW, 0, 0, + 0, AADDW, ASLLW, 0, 0, 0, ASRLW, 0, 0, +}; +static Opclass opOBRANCH = { + "2,s,p", + 0, ABEQ, ABNE, 0, 0, ABLT, ABGE, ABLTU, ABGEU, +}; +static Opclass opOJALR = { + "d,a", + 0, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, AJALR, +}; +static Opclass opOJAL = { + "d,p", + 0, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, AJAL, +}; +static Opclass opOSYSTEM = { + "", + 0, ASYS, ACSRRW, ACSRRS, ACSRRC, 0, ACSRRWI,ACSRRSI,ACSRRCI, +}; +static char fmtcsr[] = "c,s,d"; +static char fmtcsri[] = "c,js,d"; +static char *fmtOSYSTEM[8] = { + "$i", fmtcsr, fmtcsr, fmtcsr, "", fmtcsri, fmtcsri, fmtcsri, +}; +static Opclass opOOP_FP = { + "fs,fd", + 0x0, AADDF, ASUBF, AMULF, ADIVF, AMOVF, 0, 0, 0, + 0x1, AMOVDF, 0, 0, 0, 0, 0, 0, 0, + 0x2, ACMPLEF,ACMPLTF,ACMPEQF,0, 0, 0, 0, 0, + 0x3, AMOVFW, 0, AMOVFV, 0, AMOVWF, AMOVUF, AMOVVF, AMOVUVF, +}; +static Opclass opOOP_DP = { + "f2,fs,fd", + 0x0, AADDD, ASUBD, AMULD, ADIVD, AMOVD, 0, 0, 0, + 0x1, AMOVFD, 0, 0, 0, 0, 0, 0, 0, + 0x2, ACMPLED,ACMPLTD,ACMPEQD,0, 0, 0, 0, 0, + 0x3, AMOVDW, 0, AMOVDV, 0, AMOVWD, AMOVUD, AMOVVD, AMOVUVD, +}; + +typedef struct Compclass Compclass; +struct Compclass { + char *fmt; + uchar immbits[18]; +}; + +static Compclass rv32compressed[0x2D] = { +/* 00-07 ([1:0] = 0) ([15:13] = 0-7) */ + {"ADDI4SPN $i,d", 22, 6, 5, 11, 12, 7, 8, 9, 10}, /* 12:5 → 5:4|9:6|2|3 */ + {"FLD a,fd", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"LW a,d", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */ + {"FLW a,fd", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */ + {"? ", 0}, + {"FSD f2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"SW 2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 */ + {"FSW f2,a", 25, 6, 10, 11, 12, 5}, /* 12:10|6:5 → 5:2|6 rv32 */ + +/* 08-0F ([1:0] = 1) ([15:13] = 0-7 not 4) */ + {"ADDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + {"JAL p", ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 rv32 D*/ + {"LI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + {"LUI $i,d", ~14, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 17:12 */ + {"? ", 0}, + {"J p", ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 */ + {"BEQZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */ + {"BNEZ s,p", ~23, 3, 4, 10, 11, 2, 5, 6, 12}, /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */ + +/* 10-17 ([1:0] = 2) ([15:13] = 0-7 not 4) */ + {"SLLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */ + {"FLDSP i,fd", 23, 5, 6, 12, 2, 3, 4}, /* 12|6:2 → 5:3|8:6 */ + {"LWSP i,d", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 */ + {"FLWSP i,fd", 24, 4, 5, 6, 12, 2, 3}, /* 12|6:2 → 5:2|7:6 rv32 */ + {"? ", 0}, + {"FSDSP f2,$i", 23, 10, 11, 12, 7, 8, 9}, /* 12:7 → 5:3|8:6 */ + {"SWSP 2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 */ + {"FSWSP f2,$i", 24, 9, 10, 11, 12, 7, 8}, /* 12:7 → 5:2|7:6 rv32 */ + +/* 18-1A ([1:0] = 1) ([15:13] = 4) ([11:10] = 0-2) */ + {"SRLI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */ + {"SRAI $i,d", 26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → 5:0 */ + {"ANDI $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + +/* 1B-22 ([1:0] = 1) ([15:13] = 4) ([11:10] = 3) ([12] = 0-1) ([6:5] = 0-3) */ + {"SUB 2,d", 0}, + {"XOR 2,d", 0}, + {"OR 2,d", 0}, + {"AND 2,d", 0}, + {"SUBW 2,d", 0}, /* rv64 */ + {"ADDW 2,d", 0}, /* rv64 */ + {"? ", 0}, + {"? ", 0}, + +/* 23-26 ([1:0] = 2) ([15:13] = 4) ((rs2 != 0) = 0-1) */ + {"JR s", 0}, + {"MV 2,d", 0}, + {"JALR s", 0}, + {"ADD 2,d", 0}, + +/* 27-27 ([1:0] = 1) ([15:13] = 3) ( rd = 2) */ + {"ADDI16SP $i", ~22, 6, 2, 5, 3, 4, 12}, /* 12|6:2 → * 9|4|6|8:7|5 */ + +/* 28-2C rv64 alternates */ + {"LD a,d", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"SD 2,a", 24, 10, 11, 12, 5, 6}, /* 12:10|6:5 → 5:3|7:6 */ + {"ADDIW $i,d", ~26, 2, 3, 4, 5, 6, 12}, /* 12|6:2 → * 5:0 */ + {"LDSP i,d", 23, 5, 6, 12, 2, 3, }, /* 12|6:2 → 5:3|8:6 */ + {"SDSP 2,i", 23, 10, 11, 12, 7, 8, 9} /* 12:7 → 5:3|8:6 */ +}; + +/* map major opcodes to opclass table */ +static Opclass *opclass[32] = { + [OLOAD] &opOLOAD, + [OLOAD_FP] &opOLOAD_FP, + [OMISC_MEM] &opOMISC_MEM, + [OOP_IMM] &opOOP_IMM, + [OAUIPC] &opOAUIPC, + [OOP_IMM_32] &opOOP_IMM_32, + [OSTORE] &opOSTORE, + [OSTORE_FP] &opOSTORE_FP, + [OAMO] &opOAMO, + [OOP] &opOOP, + [OLUI] &opOLUI, + [OOP_FP] &opOOP_FP, + [OOP_32] &opOOP_32, + [OBRANCH] &opOBRANCH, + [OJALR] &opOJALR, + [OJAL] &opOJAL, + [OSYSTEM] &opOSYSTEM, +}; + +/* + * Print value v as name[+offset] + */ +static int +gsymoff(char *buf, int n, ulong v, int space) +{ + Symbol s; + int r; + long delta; + + r = delta = 0; /* to shut compiler up */ + if (v) { + r = findsym(v, space, &s); + if (r) + delta = v-s.value; + if (delta < 0) + delta = -delta; + } + if (v == 0 || r == 0 || delta >= 4096) + return snprint(buf, n, "#%lux", v); + if (strcmp(s.name, ".string") == 0) + return snprint(buf, n, "#%lux", v); + if (!delta) + return snprint(buf, n, "%s", s.name); + if (s.type != 't' && s.type != 'T') + return snprint(buf, n, "%s+%llux", s.name, v-s.value); + else + return snprint(buf, n, "#%lux", v); +} + +#pragma varargck argpos bprint 2 + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static void +format(Instr *i, char *opcode, char *f) +{ + int c; + long imm; + char reg; + + reg = 'R'; + if(opcode != nil){ + bprint(i, "%s", opcode); + if(f == 0) + return; + bprint(i, "\t"); + }else + bprint(i, "C."); + for(; (c = *f); f++){ + switch(c){ + default: + bprint(i, "%c", c); + break; + case ' ': + bprint(i, "\t"); + break; + case 'f': + reg = 'F'; + break; + case 'j': + reg = '$'; + break; + case 's': + bprint(i, "%c%d", reg, i->rs1); + reg = 'R'; + break; + case '2': + bprint(i, "%c%d", reg, i->rs2); + reg = 'R'; + break; + case '3': + bprint(i, "%c%d", reg, i->rs3); + break; + case 'd': + bprint(i, "%c%d", reg, i->rd); + reg = 'R'; + break; + case 'i': + imm = i->imm; + if(imm < 0) + bprint(i, "-%lux", -imm); + else + bprint(i, "%lux", imm); + break; + case 'p': + imm = i->addr + i->imm; + i->curr += gsymoff(i->curr, i->end-i->curr, imm, CANY); + break; + case 'a': + if(i->rs1 == REGSB && mach->sb){ + i->curr += gsymoff(i->curr, i->end-i->curr, i->imm+mach->sb, CANY); + bprint(i, "(SB)"); + break; + } + bprint(i, "%lx(R%d)", i->imm, i->rs1); + break; + case '7': + bprint(i, "%ux", i->func7); + break; + case 'c': + bprint(i, "CSR(%lx)", i->imm&0xFFF); + break; + } + } +} + +static int +badinst(Instr *i) +{ + format(i, "???", 0); + return 4; +} + +static long +immshuffle(uint w, uchar *p) +{ + int shift, i; + ulong imm; + + shift = *p++; + imm = 0; + while((i = *p++) != 0){ + imm >>= 1; + if((w>>i) & 0x01) + imm |= (1<<31); + } + if(shift & 0x80) + imm = (long)imm >> (shift ^ 0xFF); + else + imm >>= shift; + return imm; +} + +static int +decompress(Instr *i) +{ + ushort w; + int op, aop; + Compclass *cop; + + w = i->w; + i->n = 2; + i->func3 = (w>>13)&0x7; + op = w&0x3; + i->op = op; + switch(op){ + case 0: + i->rd = 8 + ((w>>2)&0x7); + i->rs1 = 8 + ((w>>7)&0x7); + i->rs2 = i->rd; + break; + case 1: + i->rd = (w>>7)&0x1F; + if((i->func3&0x4) != 0) + i->rd = 8 + (i->rd&0x7); + i->rs1 = i->rd; + i->rs2 = 8 + ((w>>2)&0x7); + break; + case 2: + i->rd = (w>>7)&0x1F; + i->rs1 = i->rd; + i->rs2 = (w>>2)&0x1F; + } + aop = (op << 3) + i->func3; + if((aop & 0x7) == 4){ + switch(op){ + case 1: + aop = 0x18 + ((w>>10) & 0x7); + if(aop == 0x1B) + aop += (w>>5) & 0x3; + break; + case 2: + aop = 0x23 + ((w>>11) & 0x2) + (i->rs2 != 0); + break; + } + } + if(aop == 0x0B && i->rd == 2) + aop = 0x27; + if(i->rv64) switch(aop){ + case 0x03: aop = 0x28; break; + case 0x07: aop = 0x29; break; + case 0x09: aop = 0x2A; break; + case 0x13: aop = 0x2B; break; + case 0x17: aop = 0x2C; break; + } + cop = &rv32compressed[aop]; + i->fmt = cop->fmt; + i->imm = immshuffle(w, cop->immbits); + return 2; +} + +static int +decode(Map *map, uvlong pc, Instr *i) +{ + ulong w; + int op; + + if(get4(map, pc, &w) < 0) { + werrstr("can't read instruction: %r"); + return -1; + } + i->addr = pc; + i->map = map; + if((w&0x3) != 3){ + i->w = w & 0xFFFF; + return decompress(i); + } + i->w = w; + i->n = 4; + op = (w&0x7F); + i->op = op; + i->func3 = (w>>12)&0x7; + i->func7 = (w>>25)&0x7F; + i->rs1 = (w>>15)&0x1F; + i->rs2 = (w>>20)&0x1F; + i->rs3 = (w>>27)&0x1F; + i->rd = (w>>7)&0x1F; +#define FIELD(hi,lo,off) (w>>(lo-off))&(((1<<(hi-lo+1))-1)<<off) +#define LFIELD(hi,lo,off) (w<<(off-lo))&(((1<<(hi-lo+1))-1)<<off) +#define SFIELD(lo,off) ((long)(w&((~0)<<lo))>>(lo-off)) + switch(op>>2) { + case OSTORE: /* S-type */ + case OSTORE_FP: + i->imm = SFIELD(25,5) | FIELD(11,7,0); + break; + case OBRANCH: /* B-type */ + i->imm = SFIELD(31,12) | LFIELD(7,7,11) | FIELD(30,25,5) | FIELD(11,8,1); + break; + case OOP_IMM: /* I-type */ + case OOP_IMM_32: + if(i->func3 == 1 || i->func3 == 5){ /* special case ASL/ASR */ + i->imm = FIELD(25,20,0); + break; + } + /* fall through */ + case OLOAD: + case OLOAD_FP: + case OMISC_MEM: + case OJALR: + case OSYSTEM: + i->imm = SFIELD(20,0); + break; + case OAUIPC: /* U-type */ + case OLUI: + i->imm = SFIELD(12,12); + break; + case OJAL: /* J-type */ + i->imm = SFIELD(31,20) | FIELD(19,12,12) | FIELD(20,20,11) | FIELD(30,21,1); + break; + } + return 4; +} + +static int +pseudo(Instr *i, int aop) +{ + char *op; + + switch(aop){ + case AJAL: + if(i->rd == 0){ + format(i, "JMP", "p"); + return 1; + } + break; + case AJALR: + if(i->rd == 0){ + format(i, "JMP", "a"); + return 1; + } + break; + case AADD: + if((i->op>>2) == OOP_IMM){ + op = i->rv64 ? "MOV" : "MOVW"; + if(i->rs1 == 0) + format(i, op, "$i,d"); + else if(i->rs1 == REGSB && mach->sb && i->rd != REGSB) + format(i, op, "$a,d"); + else if(i->imm == 0) + format(i, op, "s,d"); + else break; + return 1; + } + break; + } + return 0; +} + +static int +mkinstr(Instr *i) +{ + Opclass *oc; + Optab *o; + char *fmt; + int aop; + + if((i->op&0x3) != 0x3){ + format(i, nil, i->fmt); + return 2; + } + oc = opclass[i->op>>2]; + if(oc == 0) + return badinst(i); + fmt = oc->fmt; + if(oc == &opOSYSTEM) + fmt = fmtOSYSTEM[i->func3]; + if(oc == &opOOP_FP){ + if(i->func7 & 1) + oc = &opOOP_DP; + o = &oc->tab[i->func7>>5]; + switch(o->func7){ + case 0: + fmt = "f2,fs,fd"; + /* fall through */ + default: + aop = o->op[(i->func7>>2)&0x7]; + if((i->func7&~1) == 0x10){ + if(i->func3 == 0 && i->rs1 == i->rs2) + fmt = "fs,fd"; + else + aop = 0; + } + break; + case 2: + aop = o->op[i->func3]; + break; + case 3: + if(i->func7 & 0x10) + return badinst(i); + aop = o->op[(i->func7>>1)&0x4 | (i->rs2&0x3)]; + if(i->func7 & 0x8) + fmt = "s,fd"; + else + fmt = "fs,d"; + break; + } + if(aop == 0) + return badinst(i); + format(i, anames[aop], fmt); + return 4; + } + o = oc->tab; + while(o->func7 != 0 && (i->func7 != o->func7 || o->op[i->func3] == 0)) + o++; + if((aop = o->op[i->func3]) == 0) + return badinst(i); + if(pseudo(i, aop)) + return 4; + format(i, anames[aop], fmt); + return 4; +} + +static int +riscvdas(Map *map, uvlong pc, char modifier, char *buf, int n) +{ + Instr i; + + USED(modifier); + i.rv64 = 0; + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + return mkinstr(&i); +} + +static int +riscv64das(Map *map, uvlong pc, char modifier, char *buf, int n) +{ + Instr i; + + USED(modifier); + i.rv64 = 1; + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + return mkinstr(&i); +} + +static int +riscvhexinst(Map *map, uvlong pc, char *buf, int n) +{ + Instr i; + + i.curr = buf; + i.end = buf+n; + if(decode(map, pc, &i) < 0) + return -1; + if(i.end-i.curr > 2*i.n) + i.curr = _hexify(buf, i.w, 2*i.n - 1); + *i.curr = 0; + return i.n; +} + +static int +riscvinstlen(Map *map, uvlong pc) +{ + Instr i; + + return decode(map, pc, &i); +} + +static char* +riscvexcep(Map* m, Rgetter r) +{ + return "Trap"; +} + +/* + * Debugger interface + */ +Machdata riscvmach = +{ + {0x3a, 0xa0, 0x3d, 0x00}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + riscvexcep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precisioin float printer */ + 0, /* following addresses */ + riscvdas, /* symbolic disassembly */ + riscvhexinst, /* hex disassembly */ + riscvinstlen, /* instruction size */ +}; + +Machdata riscv64mach = +{ + {0x3a, 0xa0, 0x3d, 0x00}, /* break point */ + 4, /* break point size */ + + leswab, /* short to local byte order */ + leswal, /* long to local byte order */ + leswav, /* long to local byte order */ + risctrace, /* C traceback */ + riscframe, /* Frame finder */ + riscvexcep, /* print exception */ + 0, /* breakpoint fixup */ + 0, /* single precision float printer */ + 0, /* double precisioin float printer */ + 0, /* following addresses */ + riscv64das, /* symbolic disassembly */ + riscvhexinst, /* hex disassembly */ + riscvinstlen, /* instruction size */ +}; diff --git a/utils/libmach/iobj.c b/utils/libmach/iobj.c new file mode 100644 index 00000000..a789f30e --- /dev/null +++ b/utils/libmach/iobj.c @@ -0,0 +1,134 @@ +/* + * iobj.c - identify and parse a riscv object file + */ +#include <lib9.h> +#include <bio.h> +#include <mach.h> +#include "ic/i.out.h" +#include "obj.h" + +typedef struct Addr Addr; +struct Addr +{ + char type; + char sym; + char name; +}; +static Addr addr(Biobuf*); +static char type2char(int); +static void skip(Biobuf*, int); + +int +_isi(char *s) +{ + return s[0] == ANAME /* ANAME */ + && s[1] == D_FILE /* type */ + && s[2] == 1 /* sym */ + && s[3] == '<'; /* name of file */ +} + +int +_readi(Biobuf *bp, Prog *p) +{ + int as, n; + Addr a; + + as = Bgetc(bp); /* as */ + if(as < 0) + return 0; + p->kind = aNone; + p->sig = 0; + if(as == ANAME || as == ASIGNAME){ + if(as == ASIGNAME){ + Bread(bp, &p->sig, 4); + p->sig = leswal(p->sig); + } + p->kind = aName; + p->type = type2char(Bgetc(bp)); /* type */ + p->sym = Bgetc(bp); /* sym */ + n = 0; + for(;;) { + as = Bgetc(bp); + if(as < 0) + return 0; + n++; + if(as == 0) + break; + } + p->id = malloc(n); + if(p->id == 0) + return 0; + Bseek(bp, -n, 1); + if(Bread(bp, p->id, n) != n) + return 0; + return 1; + } + if(as == ATEXT) + p->kind = aText; + else if(as == AGLOBL) + p->kind = aData; + skip(bp, 5); /* reg(1), lineno(4) */ + a = addr(bp); + addr(bp); + if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN) + p->kind = aNone; + p->sym = a.sym; + return 1; +} + +static Addr +addr(Biobuf *bp) +{ + Addr a; + long off; + + a.type = Bgetc(bp); /* a.type */ + skip(bp,1); /* reg */ + a.sym = Bgetc(bp); /* sym index */ + a.name = Bgetc(bp); /* sym type */ + switch(a.type){ + default: + case D_NONE: case D_REG: case D_FREG: + break; + case D_OREG: + case D_CONST: + case D_BRANCH: + case D_CTLREG: + off = Bgetc(bp); + off |= Bgetc(bp) << 8; + off |= Bgetc(bp) << 16; + off |= Bgetc(bp) << 24; + if(off < 0) + off = -off; + if(a.sym && (a.name==D_PARAM || a.name==D_AUTO)) + _offset(a.sym, off); + break; + case D_VCONST: + case D_SCONST: + skip(bp, NSNAME); + break; + case D_FCONST: + skip(bp, 8); + break; + } + return a; +} + +static char +type2char(int t) +{ + switch(t){ + case D_EXTERN: return 'U'; + case D_STATIC: return 'b'; + case D_AUTO: return 'a'; + case D_PARAM: return 'p'; + default: return UNKNOWN; + } +} + +static void +skip(Biobuf *bp, int n) +{ + while (n-- > 0) + Bgetc(bp); +} diff --git a/utils/libmach/j.c b/utils/libmach/j.c new file mode 100644 index 00000000..26c8c4c8 --- /dev/null +++ b/utils/libmach/j.c @@ -0,0 +1,70 @@ +/* + * RISC-V RV64 definition + */ +#include <lib9.h> +#include <bio.h> +#include "uregj.h" +#include <mach.h> + +#define REGOFF(x) offsetof(struct Ureg, x) +#define REGSIZE sizeof(struct Ureg) + +Reglist riscv64reglist[] = { + {"PC", REGOFF(pc), RINT, 'X'}, + {"SP", REGOFF(r27), RINT, 'X'}, + {"R31", REGOFF(r31), RINT, 'X'}, + {"R30", REGOFF(r30), RINT, 'X'}, + {"R28", REGOFF(r28), RINT, 'X'}, + {"R27", REGOFF(r27), RINT, 'X'}, + {"R26", REGOFF(r26), RINT, 'X'}, + {"R25", REGOFF(r25), RINT, 'X'}, + {"R24", REGOFF(r24), RINT, 'X'}, + {"R23", REGOFF(r23), RINT, 'X'}, + {"R22", REGOFF(r22), RINT, 'X'}, + {"R21", REGOFF(r21), RINT, 'X'}, + {"R20", REGOFF(r20), RINT, 'X'}, + {"R19", REGOFF(r19), RINT, 'X'}, + {"R18", REGOFF(r18), RINT, 'X'}, + {"R17", REGOFF(r17), RINT, 'X'}, + {"R16", REGOFF(r16), RINT, 'X'}, + {"R15", REGOFF(r15), RINT, 'X'}, + {"R14", REGOFF(r14), RINT, 'X'}, + {"R13", REGOFF(r13), RINT, 'X'}, + {"R12", REGOFF(r12), RINT, 'X'}, + {"R11", REGOFF(r11), RINT, 'X'}, + {"R10", REGOFF(r10), RINT, 'X'}, + {"R9", REGOFF(r9), RINT, 'X'}, + {"R8", REGOFF(r8), RINT, 'X'}, + {"R7", REGOFF(r7), RINT, 'X'}, + {"R6", REGOFF(r6), RINT, 'X'}, + {"R5", REGOFF(r5), RINT, 'X'}, + {"R4", REGOFF(r4), RINT, 'X'}, + {"R3", REGOFF(r3), RINT, 'X'}, + {"R2", REGOFF(r2), RINT, 'X'}, + {"R1", REGOFF(r1), RINT, 'X'}, + { 0 } +}; + + /* the machine description */ +Mach mriscv64 = +{ + "riscv64", + MRISCV64, /* machine type */ + riscv64reglist, /* register set */ + REGSIZE, /* register set size */ + 0, /* fp register set size */ + "PC", /* name of PC */ + "SP", /* name of SP */ + "R1", /* name of link register */ + "setSB", /* static base register name */ + 0, /* static base register value */ + 0x1000, /* page size */ + 0x80000000ULL, /* kernel base */ + 0xC0000000ULL, /* kernel text mask */ + 0x3FFFFFFFULL, /* user stack top */ + 2, /* quantization of pc */ + 8, /* szaddr */ + 8, /* szreg */ + 4, /* szfloat */ + 8, /* szdouble */ +}; diff --git a/utils/libmach/mkfile b/utils/libmach/mkfile index 9114ed66..ac474d15 100644 --- a/utils/libmach/mkfile +++ b/utils/libmach/mkfile @@ -7,12 +7,15 @@ OFILES=\ 6.$O\ 8.$O\ 9.$O\ + i.$O\ + j.$O\ k.$O\ q.$O\ t.$O\ v.$O\ 5db.$O\ 8db.$O\ + idb.$O\ kdb.$O\ qdb.$O\ tdb.$O\ @@ -21,6 +24,7 @@ OFILES=\ 6obj.$O\ 8obj.$O\ 9obj.$O\ + iobj.$O\ kobj.$O\ qobj.$O\ vobj.$O\ diff --git a/utils/libmach/obj.c b/utils/libmach/obj.c index 7b1f1b62..5f6e6250 100644 --- a/utils/libmach/obj.c +++ b/utils/libmach/obj.c @@ -28,13 +28,15 @@ int _is5(char*), _isk(char*), _isq(char*), _isv(char*), + _isi(char*), _read5(Biobuf*, Prog*), _read6(Biobuf*, Prog*), _read8(Biobuf*, Prog*), _read9(Biobuf*, Prog*), _readk(Biobuf*, Prog*), _readq(Biobuf*, Prog*), - _readv(Biobuf*, Prog*); + _readv(Biobuf*, Prog*), + _readi(Biobuf*, Prog*); typedef struct Obj Obj; typedef struct Symtab Symtab; @@ -64,6 +66,8 @@ static Obj obj[] = /*[ObjAmd64]*/ "amd64 .6", _is6, _read6, /*[ObjSpim]*/ {0, 0,}, /*[ObjPower64]*/ "power64 .9", _is9, _read9, + /*[ObjRiscv]*/ "riscv .i", _isi, _readi, + /*[ObjRiscv64]*/ "riscv64 .j", _isi, _readi, /*[Maxobjtype]*/ 0, 0 }; diff --git a/utils/libmach/setmach.c b/utils/libmach/setmach.c index 7247881c..8bfd3c18 100644 --- a/utils/libmach/setmach.c +++ b/utils/libmach/setmach.c @@ -16,9 +16,9 @@ struct machtab }; extern Mach mmips, msparc, mi386, mamd64, - marm, mmips2be, mmips2le, mpower, mpower64; + marm, mmips2be, mmips2le, mpower, mpower64, mriscv, mriscv64; extern Machdata mipsmach, sparcmach, i386mach, - armmach, mipsmach2le, powermach; + armmach, mipsmach2le, powermach, riscvmach, riscv64mach; /* * machine selection table. machines with native disassemblers should @@ -99,6 +99,18 @@ Machtab machines[] = APOWER64, &mpower64, &powermach, }, + { "riscv", + FRISCV, + FRISCVB, + ARISCV, + &mriscv, + &riscvmach, }, + { "riscv64", + FRISCV64, + FRISCV64B, + ARISCV64, + &mriscv64, + &riscv64mach, }, { 0 }, /*the terminator*/ }; diff --git a/utils/libmach/uregi.h b/utils/libmach/uregi.h new file mode 100644 index 00000000..27d202b6 --- /dev/null +++ b/utils/libmach/uregi.h @@ -0,0 +1,57 @@ +struct Ureg +{ + union { + uintptr pc; + uintptr regs[1]; + }; + uintptr r1; /* link */ + union{ + uintptr r2; + uintptr sp; + uintptr usp; + }; + uintptr r3; /* sb */ + uintptr r4; + uintptr r5; + uintptr r6; /* up in kernel */ + uintptr r7; /* m in kernel */ + union{ + uintptr r8; + uintptr arg; + uintptr ret; + }; + uintptr r9; + uintptr r10; + uintptr r11; + uintptr r12; + uintptr r13; + uintptr r14; + uintptr r15; + uintptr r16; + uintptr r17; + uintptr r18; + uintptr r19; + uintptr r20; + uintptr r21; + uintptr r22; + uintptr r23; + uintptr r24; + uintptr r25; + uintptr r26; + uintptr r27; + uintptr r28; + uintptr r29; + uintptr r30; + uintptr r31; + + /* csrs: generally supervisor ones */ + uintptr status; + uintptr ie; + union { + uintptr cause; + uintptr type; + }; + uintptr tval; /* faulting address */ + + uintptr curmode; +}; diff --git a/utils/libmach/uregj.h b/utils/libmach/uregj.h new file mode 100644 index 00000000..593da792 --- /dev/null +++ b/utils/libmach/uregj.h @@ -0,0 +1,39 @@ +struct Ureg +{ + u64int pc; + u64int r1; + union{ + u64int r2; + u64int sp; + u64int usp; + }; + u64int r3; + u64int r4; + u64int r5; + u64int r6; + u64int r7; + u64int r8; + u64int r9; + u64int r10; + u64int r11; + u64int r12; + u64int r13; + u64int r14; + u64int r15; + u64int r16; + u64int r17; + u64int r18; + u64int r19; + u64int r20; + u64int r21; + u64int r22; + u64int r23; + u64int r24; + u64int r25; + u64int r26; + u64int r27; + u64int r28; + u64int r29; + u64int r30; + u64int r31; +}; |