From ae669bfa83ee41d627ef25615d7b377ad1d407fa Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Mon, 23 Oct 2023 22:28:10 -0400 Subject: [PATCH] Buildable skeleton for ARM64 architecture specific code. --- SConstruct | 18 +- lib/libc/arm64/crti.S | 47 ++ lib/libc/arm64/crtn.S | 43 + lib/libc/arm64/syscall.S | 13 + lib/libc/posix/mman.c | 5 + sys/SConscript | 35 +- sys/arm64/debug.c | 181 ++++ sys/arm64/disasm.c | 1627 ++++++++++++++++++++++++++++++++++++ sys/arm64/include/asm.h | 10 + sys/arm64/include/atomic.h | 38 + sys/arm64/include/cpu.h | 46 + sys/arm64/include/cpuop.h | 35 + sys/arm64/include/ioapic.h | 13 + sys/arm64/include/mp.h | 23 + sys/arm64/include/pmap.h | 81 ++ sys/arm64/include/thread.h | 17 + sys/arm64/include/trap.h | 91 ++ sys/arm64/irq.c | 53 ++ sys/arm64/kernel.lds | 227 +++++ sys/arm64/machine.c | 170 ++++ sys/arm64/mbentry.c | 61 ++ sys/arm64/mp.c | 213 +++++ sys/arm64/multiboot.S | 30 + sys/arm64/pci.c | 77 ++ sys/arm64/pmap.c | 323 +++++++ sys/arm64/support.S | 26 + sys/arm64/switch.S | 19 + sys/arm64/thread.c | 68 ++ sys/arm64/time.c | 25 + sys/arm64/trap.c | 121 +++ sys/arm64/trapentry.S | 38 + sys/include/mp.h | 8 + 32 files changed, 3772 insertions(+), 10 deletions(-) create mode 100644 lib/libc/arm64/crti.S create mode 100644 lib/libc/arm64/crtn.S create mode 100644 lib/libc/arm64/syscall.S create mode 100644 sys/arm64/debug.c create mode 100644 sys/arm64/disasm.c create mode 100644 sys/arm64/include/asm.h create mode 100644 sys/arm64/include/atomic.h create mode 100644 sys/arm64/include/cpu.h create mode 100644 sys/arm64/include/cpuop.h create mode 100644 sys/arm64/include/ioapic.h create mode 100644 sys/arm64/include/mp.h create mode 100644 sys/arm64/include/pmap.h create mode 100644 sys/arm64/include/thread.h create mode 100644 sys/arm64/include/trap.h create mode 100644 sys/arm64/irq.c create mode 100644 sys/arm64/kernel.lds create mode 100644 sys/arm64/machine.c create mode 100644 sys/arm64/mbentry.c create mode 100644 sys/arm64/mp.c create mode 100644 sys/arm64/multiboot.S create mode 100644 sys/arm64/pci.c create mode 100644 sys/arm64/pmap.c create mode 100644 sys/arm64/support.S create mode 100644 sys/arm64/switch.S create mode 100644 sys/arm64/thread.c create mode 100644 sys/arm64/time.c create mode 100644 sys/arm64/trap.c create mode 100644 sys/arm64/trapentry.S diff --git a/SConstruct b/SConstruct index 25553da..4cda479 100644 --- a/SConstruct +++ b/SConstruct @@ -20,7 +20,7 @@ opts.AddVariables( ("NUMCPUS", "Number of CPUs to use for build (0 means auto).", "0"), ("WITH_GPROF", "Include gprof profiling (0 or 1).", "0"), ("PREFIX", "Installation target directory.", "#pxelinux"), - ("ARCH", "Target Architecture", "amd64"), + ("ARCH", "Target Architecture", "arm64"), ("BOOTDISK", "Build boot disk (0 or 1)", "1"), ("BOOTDISK_SIZE", "Boot disk size", "128") ) @@ -51,8 +51,16 @@ if 'LDFLAGS' in os.environ: toolenv = env.Clone() env.Append(CFLAGS = [ "-Wshadow", "-Wno-typedef-redefinition" ]) -env.Append(CPPFLAGS = [ "-target", "x86_64-freebsd-freebsd-elf", - "-fno-builtin", "-fno-stack-protector", + +if env["ARCH"] == "amd64": + env.Append(CPPFLAGS = [ "-target", "x86_64-freebsd-freebsd-elf" ]) +elif env["ARCH"] == "arm64": + env.Append(CPPFLAGS = [ "-target", "arm64-freebsd-freebsd-elf" ]) +else: + print("Unsupported architecture: " + env["ARCH"]) + sys.exit(-1) + +env.Append(CPPFLAGS = [ "-fno-builtin", "-fno-stack-protector", "-fno-optimize-sibling-calls" ]) #env.Append(LINKFLAGS = [ "-no-pie" ]) @@ -78,10 +86,6 @@ else: print("Error BUILDTYPE must be RELEASE or DEBUG") sys.exit(-1) -if env["ARCH"] != "amd64": - print("Unsupported architecture: " + env["ARCH"]) - sys.exit(-1) - try: hf = open(".git/HEAD", 'r') head = hf.read() diff --git a/lib/libc/arm64/crti.S b/lib/libc/arm64/crti.S new file mode 100644 index 0000000..3ae6ee3 --- /dev/null +++ b/lib/libc/arm64/crti.S @@ -0,0 +1,47 @@ +/*- + * Copyright 2001 David E. O'Brien + * Copyright 2014 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Andrew Turner + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + + .section .init,"ax",@progbits + .align 4 + .globl _init + .type _init,@function +_init: + sub sp, sp, #16 + str lr, [sp] + + .section .fini,"ax",@progbits + .align 4 + .globl _fini + .type _fini,@function +_fini: + sub sp, sp, #16 + str lr, [sp] + diff --git a/lib/libc/arm64/crtn.S b/lib/libc/arm64/crtn.S new file mode 100644 index 0000000..ef8940a --- /dev/null +++ b/lib/libc/arm64/crtn.S @@ -0,0 +1,43 @@ +/*- + * Copyright 2001 David E. O'Brien + * Copyright 2014 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Andrew Turner + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + + .section .init,"ax",@progbits + ldr lr, [sp] + add sp, sp, #16 + ret + + + .section .fini,"ax",@progbits + ldr lr, [sp] + add sp, sp, #16 + ret + + .section .note.GNU-stack,"",%progbits diff --git a/lib/libc/arm64/syscall.S b/lib/libc/arm64/syscall.S new file mode 100644 index 0000000..a7b8dd3 --- /dev/null +++ b/lib/libc/arm64/syscall.S @@ -0,0 +1,13 @@ +/* + * System Call + */ + +#include + +.text + +FUNC_BEGIN(syscall) + svc 0 + ret +FUNC_END(syscall) + diff --git a/lib/libc/posix/mman.c b/lib/libc/posix/mman.c index 8f51dc7..0971892 100644 --- a/lib/libc/posix/mman.c +++ b/lib/libc/posix/mman.c @@ -22,6 +22,11 @@ getpagesizes(size_t *pagesize, int nelem) return (nelem > 3 ? 3 : nelem); } return 3; +#elif defined(__aarch64__) + if (pagesize) { + pagesize[0] = PGSIZE; + } + return 1; #else #error "Unsupported Architecture!" #endif diff --git a/sys/SConscript b/sys/SConscript index fb018de..eec68cc 100644 --- a/sys/SConscript +++ b/sys/SConscript @@ -36,6 +36,27 @@ src_amd64 = [ "dev/x86/vgacons.c", ] +src_arm64 = [ + # Multiboot requires multiboot.S to be the first file + "arm64/multiboot.S", + "arm64/mbentry.c", + # AMD64 + "arm64/debug.c", + "arm64/disasm.c", + "arm64/irq.c", + "arm64/machine.c", + "arm64/mp.c", + "arm64/pci.c", + "arm64/pmap.c", + "arm64/support.S", + "arm64/switch.S", + "arm64/thread.c", + "arm64/time.c", + "arm64/trap.c", + "arm64/trapentry.S", + # Devices +] + src_common = [ "kern/copy.c", "kern/critical.c", @@ -75,14 +96,22 @@ src_common = [ if (env["ARCH"] == "amd64"): src.append(src_amd64) ldscript = "#sys/amd64/kernel.lds" +elif (env["ARCH"] == "arm64"): + src.append(src_arm64) + ldscript = "#sys/arm64/kernel.lds" src.append(src_common) kern_env.Append(LINKFLAGS = ['-T', ldscript[1:], '-nostdlib']) kern_env.Append(CPPFLAGS = ['-D_KERNEL']) kern_env.Append(CPPFLAGS = ['-ffreestanding', '-fno-builtin', '-nostdinc', - '-mno-red-zone', '-mno-mmx', '-mno-sse', - '-mcmodel=large']) -# '-target', 'amd64-orion-eabi' + '-mno-red-zone']) + +if env["ARCH"] == "amd64": + kern_env.Append(CPPFLAGS = ['-mno-mmx', '-mno-sse', '-mcmodel=large']) + # '-target', 'amd64-orion-eabi' +elif env["ARCH"] == "arm64": + kern_env.Append(CPPFLAGS = ['-mcmodel=large']) + kern_env.Append(CPPPATH = ['#build/include']) kernel = kern_env.Program("castor", src) diff --git a/sys/arm64/debug.c b/sys/arm64/debug.c new file mode 100644 index 0000000..a36e6f5 --- /dev/null +++ b/sys/arm64/debug.c @@ -0,0 +1,181 @@ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +TrapFrame *frames[MAX_CPUS]; + +volatile static uint64_t debugLock = 0; +volatile static uint64_t debugCmd = 0; +volatile static uint64_t debugHalted = 0; + +void +Debug_HaltCPUs() +{ + debugCmd = 0; + + //if (MP_GetCPUs() == 1) + return; + + //LAPIC_BroadcastNMI(T_DEBUGIPI); + + // Wait for processors to enter + /*while (debugHalted < (MP_GetCPUs() - 1)) { + pause(); + }*/ +} + +void +Debug_ResumeCPUs() +{ + debugCmd = 1; + + // Wait for processors to resume + while (debugHalted > 0) { + pause(); + } +} + +void +Debug_HaltIPI(TrapFrame *tf) +{ + MP_SetState(CPUSTATE_HALTED); + __sync_fetch_and_add(&debugHalted, 1); + + frames[CPU()] = tf; + + while (debugCmd == 0) { + pause(); + } + + __sync_fetch_and_sub(&debugHalted, 1); + MP_SetState(CPUSTATE_BOOTED); +} + +void +Debug_Breakpoint(TrapFrame *tf) +{ + frames[CPU()] = tf; + + // Should probably force all cores into the debugger + while(atomic_swap_uint64(&debugLock, 1) == 1) { + // Wait to acquire debugger lock + } + + // Stop all processors + Debug_HaltCPUs(); + + // Enter prompt + Debug_Prompt(); + + // Resume all processors + Debug_ResumeCPUs(); + atomic_set_uint64(&debugLock, 0); +} + +static void +Debug_Registers(int argc, const char *argv[]) +{ + TrapFrame *tf = frames[CPU()]; + + if (argc == 2) { + int cpuNo = Debug_StrToInt(argv[1]); + if (cpuNo >= MAX_CPUS) { + kprintf("Invalid CPU number\n"); + return; + } + tf = frames[cpuNo]; + } + +} + +REGISTER_DBGCMD(registers, "Show CPU registers", Debug_Registers); + +static void +Debug_Backtrace(int argc, const char *argv[]) +{ + TrapFrame *tf = frames[CPU()]; + uint64_t *ptr; + uint64_t rip; + uint64_t rbp; + + if (argc == 2) { + int cpuNo = Debug_StrToInt(argv[1]); + if (cpuNo >= MAX_CPUS) { + kprintf("Invalid CPU number\n"); + return; + } + tf = frames[cpuNo]; + } + + rip = 0; //tf->rip; + rbp = 0; //tf->rbp; + + kprintf("%-16s %-16s\n", "IP Pointer", "Base Pointer"); + while (3) { + kprintf("%016llx %016llx\n", rip, rbp); + ptr = (uint64_t *)rbp; + if (rbp == 0ULL || rip == 0ULL) { + break; + } + rbp = ptr[0]; + rip = ptr[1]; + } +} + +REGISTER_DBGCMD(backtrace, "Print backtrace", Debug_Backtrace); + +static void +Debug_SetBreakpoint(int argc, const char *argv[]) +{ + if (argc != 2) { + kprintf("bkpt [ADDR]"); + return; + } + + uint64_t addr = Debug_StrToInt(argv[1]); + + kprintf("NOT IMPLEMENTED\n"); +} + +REGISTER_DBGCMD(bkpt, "Set breakpoint", Debug_SetBreakpoint); + +static void +Debug_ClearBreakpoint(int argc, const char *argv[]) +{ + if (argc != 2) { + kprintf("clrbkpt [0-3]"); + return; + } + + kprintf("NOT IMPLEMENTED\n"); +} + +REGISTER_DBGCMD(clrbkpt, "Clear breakpoint", Debug_ClearBreakpoint); + +static void +Debug_ListBreakpoints(int argc, const char *argv[]) +{ + kprintf("NOT IMPLEMENTED\n"); +} + +REGISTER_DBGCMD(bkpts, "List breakpoint", Debug_ListBreakpoints); + +static void +Debug_Reboot(int argc, const char *argv[]) +{ + kprintf("NOT IMPLEMENTED\n"); +} + +REGISTER_DBGCMD(reboot, "Reboot computer", Debug_Reboot); + diff --git a/sys/arm64/disasm.c b/sys/arm64/disasm.c new file mode 100644 index 0000000..6aacbf7 --- /dev/null +++ b/sys/arm64/disasm.c @@ -0,0 +1,1627 @@ +/*- + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Instruction disassembler. + */ + +#include +#include +#include + +#include +#include + +/* + * Missing from headers + */ +#define DB_STGY_ANY 0 +#define DB_STGY_XTRN 1 +#define DB_STGY_PROC 2 +#define TRUE 1 +#define FALSE 0 + +/* + * Size attributes + */ +#define BYTE 0 +#define WORD 1 +#define LONG 2 +#define QUAD 3 +#define SNGL 4 +#define DBLR 5 +#define EXTR 6 +#define SDEP 7 +#define ADEP 8 +#define ESC 9 +#define NONE 10 + +/* + * REX prefix and bits + */ +#define REX_B 1 +#define REX_X 2 +#define REX_R 4 +#define REX_W 8 +#define REX 0x40 + +/* + * Addressing modes + */ +#define E 1 /* general effective address */ +#define Eind 2 /* indirect address (jump, call) */ +#define Ew 3 /* address, word size */ +#define Eb 4 /* address, byte size */ +#define R 5 /* register, in 'reg' field */ +#define Rw 6 /* word register, in 'reg' field */ +#define Rq 39 /* quad register, in 'reg' field */ +#define Ri 7 /* register in instruction */ +#define S 8 /* segment reg, in 'reg' field */ +#define Si 9 /* segment reg, in instruction */ +#define A 10 /* accumulator */ +#define BX 11 /* (bx) */ +#define CL 12 /* cl, for shifts */ +#define DX 13 /* dx, for IO */ +#define SI 14 /* si */ +#define DI 15 /* di */ +#define CR 16 /* control register */ +#define DR 17 /* debug register */ +#define TR 18 /* test register */ +#define I 19 /* immediate, unsigned */ +#define Is 20 /* immediate, signed */ +#define Ib 21 /* byte immediate, unsigned */ +#define Ibs 22 /* byte immediate, signed */ +#define Iw 23 /* word immediate, unsigned */ +#define Ilq 24 /* long/quad immediate, unsigned */ +#define O 25 /* direct address */ +#define Db 26 /* byte displacement from EIP */ +#define Dl 27 /* long displacement from EIP */ +#define o1 28 /* constant 1 */ +#define o3 29 /* constant 3 */ +#define OS 30 /* immediate offset/segment */ +#define ST 31 /* FP stack top */ +#define STI 32 /* FP stack */ +#define X 33 /* extended FP op */ +#define XA 34 /* for 'fstcw %ax' */ +#define El 35 /* address, long/quad size */ +#define Ril 36 /* long register in instruction */ +#define Iba 37 /* byte immediate, don't print if 0xa */ +#define EL 38 /* address, explicitly long size */ + +struct inst { + const char * i_name; /* name */ + short i_has_modrm; /* has regmodrm byte */ + short i_size; /* operand size */ + int i_mode; /* addressing modes */ + const void * i_extra; /* pointer to extra opcode table */ +}; + +#define op1(x) (x) +#define op2(x,y) ((x)|((y)<<8)) +#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16)) + +struct finst { + const char * f_name; /* name for memory instruction */ + int f_size; /* size for memory instruction */ + int f_rrmode; /* mode for rr instruction */ + const void * f_rrname; /* name for rr instruction + (or pointer to table) */ +}; + +static const struct inst db_inst_0f388x[] = { +/*80*/ { "", TRUE, SDEP, op2(E, Rq), "invept" }, +/*81*/ { "", TRUE, SDEP, op2(E, Rq), "invvpid" }, +/*82*/ { "", TRUE, SDEP, op2(E, Rq), "invpcid" }, +/*83*/ { "", FALSE, NONE, 0, 0 }, +/*84*/ { "", FALSE, NONE, 0, 0 }, +/*85*/ { "", FALSE, NONE, 0, 0 }, +/*86*/ { "", FALSE, NONE, 0, 0 }, +/*87*/ { "", FALSE, NONE, 0, 0 }, + +/*88*/ { "", FALSE, NONE, 0, 0 }, +/*89*/ { "", FALSE, NONE, 0, 0 }, +/*8a*/ { "", FALSE, NONE, 0, 0 }, +/*8b*/ { "", FALSE, NONE, 0, 0 }, +/*8c*/ { "", FALSE, NONE, 0, 0 }, +/*8d*/ { "", FALSE, NONE, 0, 0 }, +/*8e*/ { "", FALSE, NONE, 0, 0 }, +/*8f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst * const db_inst_0f38[] = { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + db_inst_0f388x, + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +static const char * const db_Grp6[] = { + "sldt", + "str", + "lldt", + "ltr", + "verr", + "verw", + "", + "" +}; + +static const char * const db_Grp7[] = { + "sgdt", + "sidt", + "lgdt", + "lidt", + "smsw", + "", + "lmsw", + "invlpg" +}; + +static const char * const db_Grp8[] = { + "", + "", + "", + "", + "bt", + "bts", + "btr", + "btc" +}; + +static const char * const db_Grp9[] = { + "", + "cmpxchg8b", + "", + "", + "", + "", + "vmptrld", + "vmptrst" +}; + +static const char * const db_Grp15[] = { + "fxsave", + "fxrstor", + "ldmxcsr", + "stmxcsr", + "xsave", + "xrstor", + "xsaveopt", + "clflush" +}; + +static const char * const db_Grp15b[] = { + "", + "", + "", + "", + "", + "lfence", + "mfence", + "sfence" +}; + +static const struct inst db_inst_0f0x[] = { +/*00*/ { "", TRUE, NONE, op1(Ew), db_Grp6 }, +/*01*/ { "", TRUE, NONE, op1(Ew), db_Grp7 }, +/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 }, +/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 }, +/*04*/ { "", FALSE, NONE, 0, 0 }, +/*05*/ { "syscall",FALSE,NONE, 0, 0 }, +/*06*/ { "clts", FALSE, NONE, 0, 0 }, +/*07*/ { "sysret",FALSE, NONE, 0, 0 }, + +/*08*/ { "invd", FALSE, NONE, 0, 0 }, +/*09*/ { "wbinvd",FALSE, NONE, 0, 0 }, +/*0a*/ { "", FALSE, NONE, 0, 0 }, +/*0b*/ { "", FALSE, NONE, 0, 0 }, +/*0c*/ { "", FALSE, NONE, 0, 0 }, +/*0d*/ { "", FALSE, NONE, 0, 0 }, +/*0e*/ { "", FALSE, NONE, 0, 0 }, +/*0f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst db_inst_0f2x[] = { +/*20*/ { "mov", TRUE, LONG, op2(CR,El), 0 }, +/*21*/ { "mov", TRUE, LONG, op2(DR,El), 0 }, +/*22*/ { "mov", TRUE, LONG, op2(El,CR), 0 }, +/*23*/ { "mov", TRUE, LONG, op2(El,DR), 0 }, +/*24*/ { "mov", TRUE, LONG, op2(TR,El), 0 }, +/*25*/ { "", FALSE, NONE, 0, 0 }, +/*26*/ { "mov", TRUE, LONG, op2(El,TR), 0 }, +/*27*/ { "", FALSE, NONE, 0, 0 }, + +/*28*/ { "", FALSE, NONE, 0, 0 }, +/*29*/ { "", FALSE, NONE, 0, 0 }, +/*2a*/ { "", FALSE, NONE, 0, 0 }, +/*2b*/ { "", FALSE, NONE, 0, 0 }, +/*2c*/ { "", FALSE, NONE, 0, 0 }, +/*2d*/ { "", FALSE, NONE, 0, 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst db_inst_0f3x[] = { +/*30*/ { "wrmsr", FALSE, NONE, 0, 0 }, +/*31*/ { "rdtsc", FALSE, NONE, 0, 0 }, +/*32*/ { "rdmsr", FALSE, NONE, 0, 0 }, +/*33*/ { "rdpmc", FALSE, NONE, 0, 0 }, +/*34*/ { "sysenter",FALSE,NONE, 0, 0 }, +/*35*/ { "sysexit",FALSE,NONE, 0, 0 }, +/*36*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "getsec",FALSE, NONE, 0, 0 }, + +/*38*/ { "", FALSE, ESC, 0, db_inst_0f38 }, +/*39*/ { "", FALSE, NONE, 0, 0 }, +/*3a*/ { "", FALSE, NONE, 0, 0 }, +/*3b*/ { "", FALSE, NONE, 0, 0 }, +/*3c*/ { "", FALSE, NONE, 0, 0 }, +/*3d*/ { "", FALSE, NONE, 0, 0 }, +/*3e*/ { "", FALSE, NONE, 0, 0 }, +/*3f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst db_inst_0f4x[] = { +/*40*/ { "cmovo", TRUE, NONE, op2(E, R), 0 }, +/*41*/ { "cmovno", TRUE, NONE, op2(E, R), 0 }, +/*42*/ { "cmovb", TRUE, NONE, op2(E, R), 0 }, +/*43*/ { "cmovnb", TRUE, NONE, op2(E, R), 0 }, +/*44*/ { "cmovz", TRUE, NONE, op2(E, R), 0 }, +/*45*/ { "cmovnz", TRUE, NONE, op2(E, R), 0 }, +/*46*/ { "cmovbe", TRUE, NONE, op2(E, R), 0 }, +/*47*/ { "cmovnbe",TRUE, NONE, op2(E, R), 0 }, + +/*48*/ { "cmovs", TRUE, NONE, op2(E, R), 0 }, +/*49*/ { "cmovns", TRUE, NONE, op2(E, R), 0 }, +/*4a*/ { "cmovp", TRUE, NONE, op2(E, R), 0 }, +/*4b*/ { "cmovnp", TRUE, NONE, op2(E, R), 0 }, +/*4c*/ { "cmovl", TRUE, NONE, op2(E, R), 0 }, +/*4d*/ { "cmovnl", TRUE, NONE, op2(E, R), 0 }, +/*4e*/ { "cmovle", TRUE, NONE, op2(E, R), 0 }, +/*4f*/ { "cmovnle",TRUE, NONE, op2(E, R), 0 }, +}; + +static const struct inst db_inst_0f7x[] = { +/*70*/ { "", FALSE, NONE, 0, 0 }, +/*71*/ { "", FALSE, NONE, 0, 0 }, +/*72*/ { "", FALSE, NONE, 0, 0 }, +/*73*/ { "", FALSE, NONE, 0, 0 }, +/*74*/ { "", FALSE, NONE, 0, 0 }, +/*75*/ { "", FALSE, NONE, 0, 0 }, +/*76*/ { "", FALSE, NONE, 0, 0 }, +/*77*/ { "", FALSE, NONE, 0, 0 }, + +/*78*/ { "vmread", TRUE, NONE, op2(Rq, E), 0 }, +/*79*/ { "vmwrite",TRUE, NONE, op2(E, Rq), 0 }, +/*7a*/ { "", FALSE, NONE, 0, 0 }, +/*7b*/ { "", FALSE, NONE, 0, 0 }, +/*7c*/ { "", FALSE, NONE, 0, 0 }, +/*7d*/ { "", FALSE, NONE, 0, 0 }, +/*7e*/ { "", FALSE, NONE, 0, 0 }, +/*7f*/ { "", FALSE, NONE, 0, 0 }, +}; + +static const struct inst db_inst_0f8x[] = { +/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 }, +/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 }, +/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 }, +/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 }, +/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 }, +/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 }, +/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 }, +/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 }, + +/*88*/ { "js", FALSE, NONE, op1(Dl), 0 }, +/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 }, +/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 }, +/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 }, +/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 }, +/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 }, +/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 }, +/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 }, +}; + +static const struct inst db_inst_0f9x[] = { +/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 }, +/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 }, +/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 }, +/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 }, +/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 }, +/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 }, +/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 }, +/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 }, + +/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 }, +/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 }, +/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 }, +/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 }, +/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 }, +/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 }, +/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 }, +/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 }, +}; + +static const struct inst db_inst_0fax[] = { +/*a0*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*a2*/ { "cpuid", FALSE, NONE, 0, 0 }, +/*a3*/ { "bt", TRUE, LONG, op2(R,E), 0 }, +/*a4*/ { "shld", TRUE, LONG, op3(Ib,R,E), 0 }, +/*a5*/ { "shld", TRUE, LONG, op3(CL,R,E), 0 }, +/*a6*/ { "", FALSE, NONE, 0, 0 }, +/*a7*/ { "", FALSE, NONE, 0, 0 }, + +/*a8*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 }, +/*aa*/ { "rsm", FALSE, NONE, 0, 0 }, +/*ab*/ { "bts", TRUE, LONG, op2(R,E), 0 }, +/*ac*/ { "shrd", TRUE, LONG, op3(Ib,R,E), 0 }, +/*ad*/ { "shrd", TRUE, LONG, op3(CL,R,E), 0 }, +/*ae*/ { "", TRUE, LONG, op1(E), db_Grp15 }, +/*af*/ { "imul", TRUE, LONG, op2(E,R), 0 }, +}; + +static const struct inst db_inst_0fbx[] = { +/*b0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 }, +/*b0*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 }, +/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 }, +/*b3*/ { "btr", TRUE, LONG, op2(R, E), 0 }, +/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 }, +/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 }, +/*b6*/ { "movzb", TRUE, LONG, op2(Eb, R), 0 }, +/*b7*/ { "movzw", TRUE, LONG, op2(Ew, R), 0 }, + +/*b8*/ { "", FALSE, NONE, 0, 0 }, +/*b9*/ { "", FALSE, NONE, 0, 0 }, +/*ba*/ { "", TRUE, LONG, op2(Ib, E), db_Grp8 }, +/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 }, +/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 }, +/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 }, +/*be*/ { "movsb", TRUE, LONG, op2(Eb, R), 0 }, +/*bf*/ { "movsw", TRUE, LONG, op2(Ew, R), 0 }, +}; + +static const struct inst db_inst_0fcx[] = { +/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 }, +/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 }, +/*c2*/ { "", FALSE, NONE, 0, 0 }, +/*c3*/ { "", FALSE, NONE, 0, 0 }, +/*c4*/ { "", FALSE, NONE, 0, 0 }, +/*c5*/ { "", FALSE, NONE, 0, 0 }, +/*c6*/ { "", FALSE, NONE, 0, 0 }, +/*c7*/ { "", TRUE, NONE, op1(E), db_Grp9 }, +/*c8*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*c9*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*ca*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cb*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cc*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cd*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*ce*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +/*cf*/ { "bswap", FALSE, LONG, op1(Ril), 0 }, +}; + +static const struct inst * const db_inst_0f[] = { + db_inst_0f0x, + 0, + db_inst_0f2x, + db_inst_0f3x, + db_inst_0f4x, + 0, + 0, + db_inst_0f7x, + db_inst_0f8x, + db_inst_0f9x, + db_inst_0fax, + db_inst_0fbx, + db_inst_0fcx, + 0, + 0, + 0 +}; + +static const char * const db_Esc92[] = { + "fnop", "", "", "", "", "", "", "" +}; +static const char * const db_Esc94[] = { + "fchs", "fabs", "", "", "ftst", "fxam", "", "" +}; +static const char * const db_Esc95[] = { + "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","" +}; +static const char * const db_Esc96[] = { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp", + "fincstp" +}; +static const char * const db_Esc97[] = { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos" +}; + +static const char * const db_Esca5[] = { + "", "fucompp","", "", "", "", "", "" +}; + +static const char * const db_Escb4[] = { + "fneni","fndisi", "fnclex","fninit","fsetpm", "", "", "" +}; + +static const char * const db_Esce3[] = { + "", "fcompp","", "", "", "", "", "" +}; + +static const char * const db_Escf4[] = { + "fnstsw","", "", "", "", "", "", "" +}; + +static const struct finst db_Esc8[] = { +/*0*/ { "fadd", SNGL, op2(STI,ST), 0 }, +/*1*/ { "fmul", SNGL, op2(STI,ST), 0 }, +/*2*/ { "fcom", SNGL, op2(STI,ST), 0 }, +/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 }, +/*4*/ { "fsub", SNGL, op2(STI,ST), 0 }, +/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 }, +/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 }, +/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 }, +}; + +static const struct finst db_Esc9[] = { +/*0*/ { "fld", SNGL, op1(STI), 0 }, +/*1*/ { "", NONE, op1(STI), "fxch" }, +/*2*/ { "fst", SNGL, op1(X), db_Esc92 }, +/*3*/ { "fstp", SNGL, 0, 0 }, +/*4*/ { "fldenv", NONE, op1(X), db_Esc94 }, +/*5*/ { "fldcw", NONE, op1(X), db_Esc95 }, +/*6*/ { "fnstenv",NONE, op1(X), db_Esc96 }, +/*7*/ { "fnstcw", NONE, op1(X), db_Esc97 }, +}; + +static const struct finst db_Esca[] = { +/*0*/ { "fiadd", LONG, 0, 0 }, +/*1*/ { "fimul", LONG, 0, 0 }, +/*2*/ { "ficom", LONG, 0, 0 }, +/*3*/ { "ficomp", LONG, 0, 0 }, +/*4*/ { "fisub", LONG, 0, 0 }, +/*5*/ { "fisubr", LONG, op1(X), db_Esca5 }, +/*6*/ { "fidiv", LONG, 0, 0 }, +/*7*/ { "fidivr", LONG, 0, 0 } +}; + +static const struct finst db_Escb[] = { +/*0*/ { "fild", LONG, 0, 0 }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fist", LONG, 0, 0 }, +/*3*/ { "fistp", LONG, 0, 0 }, +/*4*/ { "", WORD, op1(X), db_Escb4 }, +/*5*/ { "fld", EXTR, 0, 0 }, +/*6*/ { "", WORD, 0, 0 }, +/*7*/ { "fstp", EXTR, 0, 0 }, +}; + +static const struct finst db_Escc[] = { +/*0*/ { "fadd", DBLR, op2(ST,STI), 0 }, +/*1*/ { "fmul", DBLR, op2(ST,STI), 0 }, +/*2*/ { "fcom", DBLR, 0, 0 }, +/*3*/ { "fcomp", DBLR, 0, 0 }, +/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" }, +/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" }, +/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" }, +/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" }, +}; + +static const struct finst db_Escd[] = { +/*0*/ { "fld", DBLR, op1(STI), "ffree" }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fst", DBLR, op1(STI), 0 }, +/*3*/ { "fstp", DBLR, op1(STI), 0 }, +/*4*/ { "frstor", NONE, op1(STI), "fucom" }, +/*5*/ { "", NONE, op1(STI), "fucomp" }, +/*6*/ { "fnsave", NONE, 0, 0 }, +/*7*/ { "fnstsw", NONE, 0, 0 }, +}; + +static const struct finst db_Esce[] = { +/*0*/ { "fiadd", WORD, op2(ST,STI), "faddp" }, +/*1*/ { "fimul", WORD, op2(ST,STI), "fmulp" }, +/*2*/ { "ficom", WORD, 0, 0 }, +/*3*/ { "ficomp", WORD, op1(X), db_Esce3 }, +/*4*/ { "fisub", WORD, op2(ST,STI), "fsubrp" }, +/*5*/ { "fisubr", WORD, op2(ST,STI), "fsubp" }, +/*6*/ { "fidiv", WORD, op2(ST,STI), "fdivrp" }, +/*7*/ { "fidivr", WORD, op2(ST,STI), "fdivp" }, +}; + +static const struct finst db_Escf[] = { +/*0*/ { "fild", WORD, 0, 0 }, +/*1*/ { "", NONE, 0, 0 }, +/*2*/ { "fist", WORD, 0, 0 }, +/*3*/ { "fistp", WORD, 0, 0 }, +/*4*/ { "fbld", NONE, op1(XA), db_Escf4 }, +/*5*/ { "fild", QUAD, 0, 0 }, +/*6*/ { "fbstp", NONE, 0, 0 }, +/*7*/ { "fistp", QUAD, 0, 0 }, +}; + +static const struct finst * const db_Esc_inst[] = { + db_Esc8, db_Esc9, db_Esca, db_Escb, + db_Escc, db_Escd, db_Esce, db_Escf +}; + +static const char * const db_Grp1[] = { + "add", + "or", + "adc", + "sbb", + "and", + "sub", + "xor", + "cmp" +}; + +static const char * const db_Grp2[] = { + "rol", + "ror", + "rcl", + "rcr", + "shl", + "shr", + "shl", + "sar" +}; + +static const struct inst db_Grp3[] = { + { "test", TRUE, NONE, op2(I,E), 0 }, + { "test", TRUE, NONE, op2(I,E), 0 }, + { "not", TRUE, NONE, op1(E), 0 }, + { "neg", TRUE, NONE, op1(E), 0 }, + { "mul", TRUE, NONE, op2(E,A), 0 }, + { "imul", TRUE, NONE, op2(E,A), 0 }, + { "div", TRUE, NONE, op2(E,A), 0 }, + { "idiv", TRUE, NONE, op2(E,A), 0 }, +}; + +static const struct inst db_Grp4[] = { + { "inc", TRUE, BYTE, op1(E), 0 }, + { "dec", TRUE, BYTE, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +static const struct inst db_Grp5[] = { + { "inc", TRUE, LONG, op1(E), 0 }, + { "dec", TRUE, LONG, op1(E), 0 }, + { "call", TRUE, LONG, op1(Eind),0 }, + { "lcall", TRUE, LONG, op1(Eind),0 }, + { "jmp", TRUE, LONG, op1(Eind),0 }, + { "ljmp", TRUE, LONG, op1(Eind),0 }, + { "push", TRUE, LONG, op1(E), 0 }, + { "", TRUE, NONE, 0, 0 } +}; + +static const struct inst db_inst_table[256] = { +/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 }, +/*01*/ { "add", TRUE, LONG, op2(R, E), 0 }, +/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 }, +/*03*/ { "add", TRUE, LONG, op2(E, R), 0 }, +/*04*/ { "add", FALSE, BYTE, op2(I, A), 0 }, +/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 }, +/*06*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*07*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 }, +/*09*/ { "or", TRUE, LONG, op2(R, E), 0 }, +/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 }, +/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 }, +/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 }, +/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 }, +/*0e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*0f*/ { "", FALSE, ESC, 0, db_inst_0f }, + +/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 }, +/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 }, +/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 }, +/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 }, +/*14*/ { "adc", FALSE, BYTE, op2(I, A), 0 }, +/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 }, +/*16*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*17*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 }, +/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 }, +/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 }, +/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 }, +/*1c*/ { "sbb", FALSE, BYTE, op2(I, A), 0 }, +/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 }, +/*1e*/ { "push", FALSE, NONE, op1(Si), 0 }, +/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 }, + +/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 }, +/*21*/ { "and", TRUE, LONG, op2(R, E), 0 }, +/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 }, +/*23*/ { "and", TRUE, LONG, op2(E, R), 0 }, +/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 }, +/*25*/ { "and", FALSE, LONG, op2(I, A), 0 }, +/*26*/ { "", FALSE, NONE, 0, 0 }, +/*27*/ { "daa", FALSE, NONE, 0, 0 }, + +/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 }, +/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 }, +/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 }, +/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 }, +/*2c*/ { "sub", FALSE, BYTE, op2(I, A), 0 }, +/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 }, +/*2e*/ { "", FALSE, NONE, 0, 0 }, +/*2f*/ { "das", FALSE, NONE, 0, 0 }, + +/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 }, +/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 }, +/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 }, +/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 }, +/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 }, +/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 }, +/*36*/ { "", FALSE, NONE, 0, 0 }, +/*37*/ { "aaa", FALSE, NONE, 0, 0 }, + +/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 }, +/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 }, +/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 }, +/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 }, +/*3c*/ { "cmp", FALSE, BYTE, op2(I, A), 0 }, +/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 }, +/*3e*/ { "", FALSE, NONE, 0, 0 }, +/*3f*/ { "aas", FALSE, NONE, 0, 0 }, + +/*40*/ { "rex", FALSE, NONE, 0, 0 }, +/*41*/ { "rex.b", FALSE, NONE, 0, 0 }, +/*42*/ { "rex.x", FALSE, NONE, 0, 0 }, +/*43*/ { "rex.xb", FALSE, NONE, 0, 0 }, +/*44*/ { "rex.r", FALSE, NONE, 0, 0 }, +/*45*/ { "rex.rb", FALSE, NONE, 0, 0 }, +/*46*/ { "rex.rx", FALSE, NONE, 0, 0 }, +/*47*/ { "rex.rxb", FALSE, NONE, 0, 0 }, + +/*48*/ { "rex.w", FALSE, NONE, 0, 0 }, +/*49*/ { "rex.wb", FALSE, NONE, 0, 0 }, +/*4a*/ { "rex.wx", FALSE, NONE, 0, 0 }, +/*4b*/ { "rex.wxb", FALSE, NONE, 0, 0 }, +/*4c*/ { "rex.wr", FALSE, NONE, 0, 0 }, +/*4d*/ { "rex.wrb", FALSE, NONE, 0, 0 }, +/*4e*/ { "rex.wrx", FALSE, NONE, 0, 0 }, +/*4f*/ { "rex.wrxb", FALSE, NONE, 0, 0 }, + +/*50*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*51*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*52*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*53*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*54*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*55*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*56*/ { "push", FALSE, LONG, op1(Ri), 0 }, +/*57*/ { "push", FALSE, LONG, op1(Ri), 0 }, + +/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 }, +/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 }, + +/*60*/ { "pusha", FALSE, LONG, 0, 0 }, +/*61*/ { "popa", FALSE, LONG, 0, 0 }, +/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 }, +/*63*/ { "movslq", TRUE, NONE, op2(EL,R), 0 }, + +/*64*/ { "", FALSE, NONE, 0, 0 }, +/*65*/ { "", FALSE, NONE, 0, 0 }, +/*66*/ { "", FALSE, NONE, 0, 0 }, +/*67*/ { "", FALSE, NONE, 0, 0 }, + +/*68*/ { "push", FALSE, LONG, op1(I), 0 }, +/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 }, +/*6a*/ { "push", FALSE, LONG, op1(Ibs), 0 }, +/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 }, +/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 }, +/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 }, +/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 }, +/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 }, + +/*70*/ { "jo", FALSE, NONE, op1(Db), 0 }, +/*71*/ { "jno", FALSE, NONE, op1(Db), 0 }, +/*72*/ { "jb", FALSE, NONE, op1(Db), 0 }, +/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 }, +/*74*/ { "jz", FALSE, NONE, op1(Db), 0 }, +/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 }, +/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 }, +/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 }, + +/*78*/ { "js", FALSE, NONE, op1(Db), 0 }, +/*79*/ { "jns", FALSE, NONE, op1(Db), 0 }, +/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 }, +/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 }, +/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 }, +/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 }, +/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 }, +/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 }, + +/*80*/ { "", TRUE, BYTE, op2(I, E), db_Grp1 }, +/*81*/ { "", TRUE, LONG, op2(I, E), db_Grp1 }, +/*82*/ { "", TRUE, BYTE, op2(I, E), db_Grp1 }, +/*83*/ { "", TRUE, LONG, op2(Ibs,E), db_Grp1 }, +/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 }, +/*85*/ { "test", TRUE, LONG, op2(R, E), 0 }, +/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 }, +/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 }, + +/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 }, +/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 }, +/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 }, +/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 }, +/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 }, +/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 }, +/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 }, +/*8f*/ { "pop", TRUE, LONG, op1(E), 0 }, + +/*90*/ { "nop", FALSE, NONE, 0, 0 }, +/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, +/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 }, + +/*98*/ { "cwde", FALSE, SDEP, 0, "cbw" }, +/*99*/ { "cdq", FALSE, SDEP, 0, "cwd" }, +/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 }, +/*9b*/ { "wait", FALSE, NONE, 0, 0 }, +/*9c*/ { "pushf", FALSE, LONG, 0, 0 }, +/*9d*/ { "popf", FALSE, LONG, 0, 0 }, +/*9e*/ { "sahf", FALSE, NONE, 0, 0 }, +/*9f*/ { "lahf", FALSE, NONE, 0, 0 }, + +/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 }, +/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 }, +/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 }, +/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 }, +/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 }, +/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 }, +/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 }, +/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 }, + +/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 }, +/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 }, +/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 }, +/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 }, +/*ac*/ { "lods", FALSE, BYTE, op1(SI), 0 }, +/*ad*/ { "lods", FALSE, LONG, op1(SI), 0 }, +/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 }, +/*af*/ { "scas", FALSE, LONG, op1(SI), 0 }, + +/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, +/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 }, + +/*b8*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, +/*b9*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, +/*ba*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, +/*bb*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, +/*bc*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, +/*bd*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, +/*be*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, +/*bf*/ { "mov", FALSE, LONG, op2(Ilq, Ri), 0 }, + +/*c0*/ { "", TRUE, BYTE, op2(Ib, E), db_Grp2 }, +/*c1*/ { "", TRUE, LONG, op2(Ib, E), db_Grp2 }, +/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 }, +/*c3*/ { "ret", FALSE, NONE, 0, 0 }, +/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 }, +/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 }, +/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 }, +/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 }, + +/*c8*/ { "enter", FALSE, NONE, op2(Iw, Ib), 0 }, +/*c9*/ { "leave", FALSE, NONE, 0, 0 }, +/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 }, +/*cb*/ { "lret", FALSE, NONE, 0, 0 }, +/*cc*/ { "int", FALSE, NONE, op1(o3), 0 }, +/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 }, +/*ce*/ { "into", FALSE, NONE, 0, 0 }, +/*cf*/ { "iret", FALSE, NONE, 0, 0 }, + +/*d0*/ { "", TRUE, BYTE, op2(o1, E), db_Grp2 }, +/*d1*/ { "", TRUE, LONG, op2(o1, E), db_Grp2 }, +/*d2*/ { "", TRUE, BYTE, op2(CL, E), db_Grp2 }, +/*d3*/ { "", TRUE, LONG, op2(CL, E), db_Grp2 }, +/*d4*/ { "aam", FALSE, NONE, op1(Iba), 0 }, +/*d5*/ { "aad", FALSE, NONE, op1(Iba), 0 }, +/*d6*/ { ".byte\t0xd6", FALSE, NONE, 0, 0 }, +/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 }, + +/*d8*/ { "", TRUE, NONE, 0, db_Esc8 }, +/*d9*/ { "", TRUE, NONE, 0, db_Esc9 }, +/*da*/ { "", TRUE, NONE, 0, db_Esca }, +/*db*/ { "", TRUE, NONE, 0, db_Escb }, +/*dc*/ { "", TRUE, NONE, 0, db_Escc }, +/*dd*/ { "", TRUE, NONE, 0, db_Escd }, +/*de*/ { "", TRUE, NONE, 0, db_Esce }, +/*df*/ { "", TRUE, NONE, 0, db_Escf }, + +/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 }, +/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 }, +/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 }, +/*e3*/ { "jrcxz", FALSE, ADEP, op1(Db), "jecxz" }, +/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 }, +/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 }, +/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 }, +/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 }, + +/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 }, +/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 }, +/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 }, +/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 }, +/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 }, +/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 }, +/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 }, +/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 }, + +/*f0*/ { "", FALSE, NONE, 0, 0 }, +/*f1*/ { ".byte\t0xf1", FALSE, NONE, 0, 0 }, +/*f2*/ { "", FALSE, NONE, 0, 0 }, +/*f3*/ { "", FALSE, NONE, 0, 0 }, +/*f4*/ { "hlt", FALSE, NONE, 0, 0 }, +/*f5*/ { "cmc", FALSE, NONE, 0, 0 }, +/*f6*/ { "", TRUE, BYTE, 0, db_Grp3 }, +/*f7*/ { "", TRUE, LONG, 0, db_Grp3 }, + +/*f8*/ { "clc", FALSE, NONE, 0, 0 }, +/*f9*/ { "stc", FALSE, NONE, 0, 0 }, +/*fa*/ { "cli", FALSE, NONE, 0, 0 }, +/*fb*/ { "sti", FALSE, NONE, 0, 0 }, +/*fc*/ { "cld", FALSE, NONE, 0, 0 }, +/*fd*/ { "std", FALSE, NONE, 0, 0 }, +/*fe*/ { "", TRUE, NONE, 0, db_Grp4 }, +/*ff*/ { "", TRUE, NONE, 0, db_Grp5 }, +}; + +static const struct inst db_bad_inst = + { "???", FALSE, NONE, 0, 0 } +; + +#define f_mod(rex, byte) ((byte)>>6) +#define f_reg(rex, byte) ((((byte)>>3)&0x7) | (rex & REX_R ? 0x8 : 0x0)) +#define f_rm(rex, byte) (((byte)&0x7) | (rex & REX_B ? 0x8 : 0x0)) + +#define sib_ss(rex, byte) ((byte)>>6) +#define sib_index(rex, byte) ((((byte)>>3)&0x7) | (rex & REX_X ? 0x8 : 0x0)) +#define sib_base(rex, byte) (((byte)&0x7) | (rex & REX_B ? 0x8 : 0x0)) + +struct i_addr { + int is_reg; /* if reg, reg number is in 'disp' */ + int disp; + const char * base; + const char * index; + int ss; +}; + +static const char * const db_reg[2][4][16] = { + + {{"%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" }, + { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" }, + { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" }, + { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" }}, + + {{"%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" }, + { "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" }, + { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" }, + { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" }} +}; + +static const char * const db_seg_reg[8] = { + "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", "" +}; + +/* + * lengths for size attributes + */ +static const int db_lengths[] = { + 1, /* BYTE */ + 2, /* WORD */ + 4, /* LONG */ + 8, /* QUAD */ + 4, /* SNGL */ + 8, /* DBLR */ + 10, /* EXTR */ +}; + +#define get_value_inc(result, loc, size, is_signed) \ + result = Debug_GetValue((loc), (size), (is_signed)); \ + (loc) += (size); + +static uintptr_t + db_disasm_esc(uintptr_t loc, int inst, int rex, int short_addr, + int size, const char *seg); +static void db_print_address(const char *seg, int size, int rex, + struct i_addr *addrp); +static uintptr_t + db_read_address(uintptr_t loc, int short_addr, int rex, int regmodrm, + struct i_addr *addrp); + +/* + * Read address at location and return updated location. + */ +static uintptr_t +db_read_address(uintptr_t loc, int short_addr, int rex, int regmodrm, struct i_addr *addrp) +{ + int mod, rm, sib, index, disp, size, have_sib; + + mod = f_mod(rex, regmodrm); + rm = f_rm(rex, regmodrm); + + if (mod == 3) { + addrp->is_reg = TRUE; + addrp->disp = rm; + return (loc); + } + addrp->is_reg = FALSE; + addrp->index = 0; + + if (short_addr) + size = LONG; + else + size = QUAD; + + if ((rm & 0x7) == 4) { + get_value_inc(sib, loc, 1, FALSE); + rm = sib_base(rex, sib); + index = sib_index(rex, sib); + if (index != 4) + addrp->index = db_reg[1][size][index]; + addrp->ss = sib_ss(rex, sib); + have_sib = 1; + } else + have_sib = 0; + + switch (mod) { + case 0: + if (rm == 5) { + get_value_inc(addrp->disp, loc, 4, FALSE); + if (have_sib) + addrp->base = 0; + else if (short_addr) + addrp->base = "%eip"; + else + addrp->base = "%rip"; + } else { + addrp->disp = 0; + addrp->base = db_reg[1][size][rm]; + } + break; + + case 1: + get_value_inc(disp, loc, 1, TRUE); + addrp->disp = disp; + addrp->base = db_reg[1][size][rm]; + break; + + case 2: + get_value_inc(disp, loc, 4, FALSE); + addrp->disp = disp; + addrp->base = db_reg[1][size][rm]; + break; + } + return (loc); +} + +static void +db_print_address(const char *seg, int size, int rex, struct i_addr *addrp) +{ + if (addrp->is_reg) { + kprintf("%s", db_reg[rex != 0 ? 1 : 0][(size == LONG && (rex & REX_W)) ? QUAD : size][addrp->disp]); + return; + } + + if (seg) { + kprintf("%s:", seg); + } + + if (addrp->disp != 0 || (addrp->base == 0 && addrp->index == 0)) + Debug_PrintSymbol((uintptr_t)addrp->disp, DB_STGY_ANY); + if (addrp->base != 0 || addrp->index != 0) { + kprintf("("); + if (addrp->base) + kprintf("%s", addrp->base); + if (addrp->index) + kprintf(",%s,%d", addrp->index, 1<ss); + kprintf(")"); + } +} + +/* + * Disassemble floating-point ("escape") instruction + * and return updated location. + */ +static uintptr_t +db_disasm_esc(uintptr_t loc, int inst, int rex, int short_addr, int size, const char *seg) +{ + int regmodrm; + const struct finst * fp; + int mod; + struct i_addr address; + const char * name; + + get_value_inc(regmodrm, loc, 1, FALSE); + fp = &db_Esc_inst[inst - 0xd8][f_reg(rex, regmodrm)]; + mod = f_mod(rex, regmodrm); + if (mod != 3) { + if (*fp->f_name == '\0') { + kprintf(""); + return (loc); + } + /* + * Normal address modes. + */ + loc = db_read_address(loc, short_addr, rex, regmodrm, &address); + kprintf("%s", fp->f_name); + switch(fp->f_size) { + case SNGL: + kprintf("s"); + break; + case DBLR: + kprintf("l"); + break; + case EXTR: + kprintf("t"); + break; + case WORD: + kprintf("s"); + break; + case LONG: + kprintf("l"); + break; + case QUAD: + kprintf("q"); + break; + default: + break; + } + kprintf("\t"); + db_print_address(seg, BYTE, rex, &address); + } + else { + /* + * 'reg-reg' - special formats + */ + switch (fp->f_rrmode) { + case op2(ST,STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + kprintf("%s\t%%st,%%st(%d)",name,f_rm(rex, regmodrm)); + break; + case op2(STI,ST): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + kprintf("%s\t%%st(%d),%%st",name, f_rm(rex, regmodrm)); + break; + case op1(STI): + name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; + kprintf("%s\t%%st(%d)",name, f_rm(rex, regmodrm)); + break; + case op1(X): + name = ((const char * const *)fp->f_rrname)[f_rm(rex, regmodrm)]; + if (*name == '\0') + goto bad; + kprintf("%s", name); + break; + case op1(XA): + name = ((const char * const *)fp->f_rrname)[f_rm(rex, regmodrm)]; + if (*name == '\0') + goto bad; + kprintf("%s\t%%ax", name); + break; + default: + bad: + kprintf(""); + break; + } + } + + return (loc); +} + +/* + * Disassemble instruction at 'loc'. 'altfmt' specifies an + * (optional) alternate format. Return address of start of + * next instruction. + */ +uintptr_t +db_disasm(uintptr_t loc, bool altfmt) +{ + int inst; + int size; + int short_addr; + const char * seg; + const struct inst * ip; + const char * i_name; + int i_size; + int i_mode; + int rex = 0; + int regmodrm = 0; + bool first; + int displ; + int prefix; + int rep; + int imm; + int imm2; + long imm64; + int len; + struct i_addr address; + + get_value_inc(inst, loc, 1, FALSE); + short_addr = FALSE; + size = LONG; + seg = 0; + + /* + * Get prefixes + */ + rep = FALSE; + prefix = TRUE; + do { + switch (inst) { + case 0x66: /* data16 */ + size = WORD; + break; + case 0x67: + short_addr = TRUE; + break; + case 0x26: + seg = "%es"; + break; + case 0x36: + seg = "%ss"; + break; + case 0x2e: + seg = "%cs"; + break; + case 0x3e: + seg = "%ds"; + break; + case 0x64: + seg = "%fs"; + break; + case 0x65: + seg = "%gs"; + break; + case 0xf0: + kprintf("lock "); + break; + case 0xf2: + kprintf("repne "); + break; + case 0xf3: + rep = TRUE; + break; + default: + prefix = FALSE; + break; + } + if (inst >= 0x40 && inst < 0x50) { + rex = inst; + prefix = TRUE; + } + if (prefix) { + get_value_inc(inst, loc, 1, FALSE); + } + } while (prefix); + + if (inst >= 0xd8 && inst <= 0xdf) { + loc = db_disasm_esc(loc, inst, rex, short_addr, size, seg); + kprintf("\n"); + return (loc); + } + + ip = &db_inst_table[inst]; + while (ip->i_size == ESC) { + get_value_inc(inst, loc, 1, FALSE); + ip = ((const struct inst * const *)ip->i_extra)[inst>>4]; + if (ip == 0) { + ip = &db_bad_inst; + } + else { + ip = &ip[inst&0xf]; + } + } + + if (ip->i_has_modrm) { + get_value_inc(regmodrm, loc, 1, FALSE); + loc = db_read_address(loc, short_addr, rex, regmodrm, &address); + } + + i_name = ip->i_name; + i_size = ip->i_size; + i_mode = ip->i_mode; + + if (ip->i_extra == db_Grp1 || ip->i_extra == db_Grp2 || + ip->i_extra == db_Grp6 || ip->i_extra == db_Grp7 || + ip->i_extra == db_Grp8 || ip->i_extra == db_Grp9 || + ip->i_extra == db_Grp15) { + i_name = ((const char * const *)ip->i_extra)[f_reg(rex, regmodrm)]; + } + else if (ip->i_extra == db_Grp3) { + ip = ip->i_extra; + ip = &ip[f_reg(rex, regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + } + else if (ip->i_extra == db_Grp4 || ip->i_extra == db_Grp5) { + ip = ip->i_extra; + ip = &ip[f_reg(rex, regmodrm)]; + i_name = ip->i_name; + i_mode = ip->i_mode; + i_size = ip->i_size; + } + + /* Special cases that don't fit well in the tables. */ + if (ip->i_extra == db_Grp7 && f_mod(rex, regmodrm) == 3) { + switch (regmodrm) { + case 0xc1: + i_name = "vmcall"; + i_size = NONE; + i_mode = 0; + break; + case 0xc2: + i_name = "vmlaunch"; + i_size = NONE; + i_mode = 0; + break; + case 0xc3: + i_name = "vmresume"; + i_size = NONE; + i_mode = 0; + break; + case 0xc4: + i_name = "vmxoff"; + i_size = NONE; + i_mode = 0; + break; + case 0xc8: + i_name = "monitor"; + i_size = NONE; + i_mode = 0; + break; + case 0xc9: + i_name = "mwait"; + i_size = NONE; + i_mode = 0; + break; + case 0xd0: + i_name = "xgetbv"; + i_size = NONE; + i_mode = 0; + break; + case 0xd1: + i_name = "xsetbv"; + i_size = NONE; + i_mode = 0; + break; + case 0xf8: + i_name = "swapgs"; + i_size = NONE; + i_mode = 0; + break; + case 0xf9: + i_name = "rdtscp"; + i_size = NONE; + i_mode = 0; + break; + } + } + if (ip->i_extra == db_Grp15 && f_mod(rex, regmodrm) == 3) { + i_name = db_Grp15b[f_reg(rex, regmodrm)]; + i_size = NONE; + i_mode = 0; + } + + /* Handle instructions identified by mandatory prefixes. */ + if (rep == TRUE) { + if (inst == 0x90) { + i_name = "pause"; + i_size = NONE; + i_mode = 0; + rep = FALSE; + } else if (ip->i_extra == db_Grp9 && f_mod(rex, regmodrm) != 3 && + f_reg(rex, regmodrm) == 0x6) { + i_name = "vmxon"; + rep = FALSE; + } + } + if (size == WORD) { + if (ip->i_extra == db_Grp9 && f_mod(rex, regmodrm) != 3 && + f_reg(rex, regmodrm) == 0x6) { + i_name = "vmclear"; + } + } + if (rex & REX_W) { + if (strcmp(i_name, "cwde") == 0) + i_name = "cdqe"; + else if (strcmp(i_name, "cmpxchg8b") == 0) + i_name = "cmpxchg16b"; + } + + if (rep == TRUE) + kprintf("repe "); /* XXX repe VS rep */ + + if (i_size == SDEP) { + if (size == LONG) + kprintf("%s", i_name); + else + kprintf("%s", (const char *)ip->i_extra); + } else if (i_size == ADEP) { + if (short_addr == FALSE) + kprintf("%s", i_name); + else + kprintf("%s", (const char *)ip->i_extra); + } + else { + kprintf("%s", i_name); + if ((inst >= 0x50 && inst <= 0x5f) || inst == 0x68 || inst == 0x6a) { + i_size = NONE; + kprintf("q"); + } + if (i_size != NONE) { + if (i_size == BYTE) { + kprintf("b"); + size = BYTE; + } + else if (i_size == WORD) { + kprintf("w"); + size = WORD; + } + else if (size == WORD) + kprintf("w"); + else { + if (rex & REX_W) + kprintf("q"); + else + kprintf("l"); + } + } + } + kprintf("\t"); + for (first = TRUE; + i_mode != 0; + i_mode >>= 8, first = FALSE) + { + if (!first) + kprintf(","); + + switch (i_mode & 0xFF) { + + case E: + db_print_address(seg, size, rex, &address); + break; + + case Eind: + kprintf("*"); + db_print_address(seg, size, rex, &address); + break; + + case El: + db_print_address(seg, (rex & REX_W) ? QUAD : LONG, rex, &address); + break; + + case EL: + db_print_address(seg, LONG, 0, &address); + break; + + case Ew: + db_print_address(seg, WORD, rex, &address); + break; + + case Eb: + db_print_address(seg, BYTE, rex, &address); + break; + + case R: + kprintf("%s", db_reg[rex != 0 ? 1 : 0][(size == LONG && (rex & REX_W)) ? QUAD : size][f_reg(rex, regmodrm)]); + break; + + case Rw: + kprintf("%s", db_reg[rex != 0 ? 1 : 0][WORD][f_reg(rex, regmodrm)]); + break; + + case Rq: + kprintf("%s", db_reg[rex != 0 ? 1 : 0][QUAD][f_reg(rex, regmodrm)]); + break; + + case Ri: + kprintf("%s", db_reg[0][QUAD][f_rm(rex, inst)]); + break; + + case Ril: + kprintf("%s", db_reg[rex != 0 ? 1 : 0][(rex & REX_R) ? QUAD : LONG][f_rm(rex, inst)]); + break; + + case S: + kprintf("%s", db_seg_reg[f_reg(rex, regmodrm)]); + break; + + case Si: + kprintf("%s", db_seg_reg[f_reg(rex, inst)]); + break; + + case A: + kprintf("%s", db_reg[rex != 0 ? 1 : 0][size][0]); /* acc */ + break; + + case BX: + if (seg) + kprintf("%s:", seg); + kprintf("(%s)", short_addr ? "%bx" : "%ebx"); + break; + + case CL: + kprintf("%%cl"); + break; + + case DX: + kprintf("%%dx"); + break; + + case SI: + if (seg) + kprintf("%s:", seg); + kprintf("(%s)", short_addr ? "%si" : "%rsi"); + break; + + case DI: + kprintf("%%es:(%s)", short_addr ? "%di" : "%rdi"); + break; + + case CR: + kprintf("%%cr%d", f_reg(rex, regmodrm)); + break; + + case DR: + kprintf("%%dr%d", f_reg(rex, regmodrm)); + break; + + case TR: + kprintf("%%tr%d", f_reg(rex, regmodrm)); + break; + + case I: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE); + kprintf("$%d", imm); + break; + + case Is: + len = db_lengths[(size == LONG && (rex & REX_W)) ? QUAD : size]; + get_value_inc(imm, loc, len, FALSE); + kprintf("$%d", imm); + break; + + case Ib: + get_value_inc(imm, loc, 1, FALSE); + kprintf("$%d", imm); + break; + + case Iba: + get_value_inc(imm, loc, 1, FALSE); + if (imm != 0x0a) + kprintf("$%d", imm); + break; + + case Ibs: + get_value_inc(imm, loc, 1, TRUE); + if (size == WORD) + imm &= 0xFFFF; + kprintf("$%d", imm); + break; + + case Iw: + get_value_inc(imm, loc, 2, FALSE); + kprintf("$%d", imm); + break; + + case Ilq: + len = db_lengths[rex & REX_W ? QUAD : LONG]; + get_value_inc(imm64, loc, len, FALSE); + kprintf("$%#lr", imm64); + break; + + case O: + len = (short_addr ? 2 : 4); + get_value_inc(displ, loc, len, FALSE); + if (seg) + kprintf("%s:%d",seg, displ); + else + Debug_PrintSymbol((uintptr_t)displ, DB_STGY_ANY); + break; + + case Db: + get_value_inc(displ, loc, 1, TRUE); + displ += loc; + if (size == WORD) + displ &= 0xFFFF; + Debug_PrintSymbol((uintptr_t)displ, DB_STGY_XTRN); + break; + + case Dl: + len = db_lengths[(size == LONG && (rex & REX_W)) ? QUAD : size]; + get_value_inc(displ, loc, len, FALSE); + displ += loc; + if (size == WORD) + displ &= 0xFFFF; + Debug_PrintSymbol((uintptr_t)displ, DB_STGY_XTRN); + break; + + case o1: + kprintf("$1"); + break; + + case o3: + kprintf("$3"); + break; + + case OS: + len = db_lengths[size]; + get_value_inc(imm, loc, len, FALSE); /* offset */ + get_value_inc(imm2, loc, 2, FALSE); /* segment */ + kprintf("$%d,%d", imm2, imm); + break; + } + } + kprintf("\n"); + return (loc); +} diff --git a/sys/arm64/include/asm.h b/sys/arm64/include/asm.h new file mode 100644 index 0000000..bbaf86e --- /dev/null +++ b/sys/arm64/include/asm.h @@ -0,0 +1,10 @@ +/* + * Assembly Macros + */ + +#define FUNC_BEGIN(fname) .p2align 4, 0x90; .global fname; \ + .type fname, @function; \ + fname: + +#define FUNC_END(fname) .size fname, . - fname + diff --git a/sys/arm64/include/atomic.h b/sys/arm64/include/atomic.h new file mode 100644 index 0000000..d9cbb3b --- /dev/null +++ b/sys/arm64/include/atomic.h @@ -0,0 +1,38 @@ + +#ifndef __ATOMIC_H__ +#define __ATOMIC_H__ + +static INLINE uint64_t +atomic_swap_uint32(volatile uint32_t *dst, uint32_t newval) +{ + uint32_t retval; + + asm volatile(".arch_extension lse; swp %w2, %w0, [%w1]; .arch_extension nolse;" + : "=r" (retval) + : "r" (dst), "r" (newval) + : "memory"); + + return newval; +} + +static INLINE uint64_t +atomic_swap_uint64(volatile uint64_t *dst, uint64_t newval) +{ + uint64_t retval; + + asm volatile(".arch_extension lse; swp %2, %0, [%1]; .arch_extension nolse;" + : "=r" (retval) + : "r" (dst), "r" (newval) + : "memory"); + + return retval; +} + +static inline void +atomic_set_uint64(volatile uint64_t *dst, uint64_t newval) +{ + *dst = newval; +} + +#endif /* __ATOMIC_H__ */ + diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h new file mode 100644 index 0000000..ecfa3f4 --- /dev/null +++ b/sys/arm64/include/cpu.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013-2018 Ali Mashtizadeh + * All rights reserved. + */ + +#ifndef __AMD64_H__ +#define __AMD64_H__ + +#include + +/* + * Page Tables + */ + +#define PGNUMMASK 0xFFFFFFFFFFFFF000ULL + +#define PGIDXSHIFT 9 +#define PGIDXMASK (512 - 1) + +#define PGSHIFT 12 +#define PGSIZE (1 << PGSHIFT) +#define PGMASK (PGSIZE - 1) + +#define LARGE_PGSHIFT 21 +#define LARGE_PGSIZE (1 << LARGE_PGSHIFT) +#define LARGE_PGMASK (LARGE_PGSIZE - 1) + +#define HUGE_PGSHIFT 30 +#define HUGE_PGSIZE (1 << HUGE_PGSHIFT) +#define HUGE_PGMASK (HUGE_PGSIZE - 1) + +#define ROUNDUP_PGSIZE(x) (((x) + LARGE_PGSIZE - 1) & ~LARGE_PGMASK) +#define ROUNDDOWN_PGSIZE(x) ((x) & ~LARGE_PGMASK) + +#define PAGETABLE_ENTRIES 512 + +typedef uint64_t PageEntry; + +typedef struct PageTable { + PageEntry entries[PAGETABLE_ENTRIES]; +} PageTable; + +#include "cpuop.h" + +#endif /* __AMD64_H__ */ + diff --git a/sys/arm64/include/cpuop.h b/sys/arm64/include/cpuop.h new file mode 100644 index 0000000..a2bc85e --- /dev/null +++ b/sys/arm64/include/cpuop.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013-2023 Ali Mashtizadeh + * All rights reserved. + */ + +#ifndef __ARM64OP_H__ +#define __ARM64OP_H__ + +static INLINE void enable_interrupts() +{ + asm volatile("msr daifclr, #(0x0002)\n"); +} + +static INLINE void disable_interrupts() +{ + asm volatile("msr daifset, #(0x0002)\n"); +} + +static INLINE void hlt() +{ + asm volatile(""); +} + +static INLINE void pause() +{ + asm volatile(""); +} + +static INLINE void breakpoint() +{ + asm volatile("brk #0"); +} + +#endif /* __ARM64OP_H__ */ + diff --git a/sys/arm64/include/ioapic.h b/sys/arm64/include/ioapic.h new file mode 100644 index 0000000..d519988 --- /dev/null +++ b/sys/arm64/include/ioapic.h @@ -0,0 +1,13 @@ +/* + * IOAPIC Header + */ + +#ifndef __IOAPIC_H__ +#define __IOAPIC_H__ + +void IOAPIC_Init(); +void IOAPIC_Enable(int irq); +void IOAPIC_Disable(int irq); + +#endif /* __IOAPIC_H__ */ + diff --git a/sys/arm64/include/mp.h b/sys/arm64/include/mp.h new file mode 100644 index 0000000..f7dd93e --- /dev/null +++ b/sys/arm64/include/mp.h @@ -0,0 +1,23 @@ + +#ifndef __MACHINE_MP_H__ +#define __MACHINE_MP_H__ + +#define CPUSTATE_NOT_PRESENT 0 +#define CPUSTATE_BOOTED 1 +#define CPUSTATE_HALTED 2 +#define CPUSTATE_MAX 2 + +void MP_Init(); +void MP_InitAP(); +void MP_SetState(int state); +int MP_GetCPUs(); + +/* Cross Calls */ +typedef int (*CrossCallCB)(void *); +void MP_CrossCallTrap(); +int MP_CrossCall(CrossCallCB cb, void *arg); + +uint32_t LAPIC_CPU(); + +#endif /* __MACHINE_MP__ */ + diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h new file mode 100644 index 0000000..67909b1 --- /dev/null +++ b/sys/arm64/include/pmap.h @@ -0,0 +1,81 @@ + +#ifndef __PMAP_H__ +#define __PMAP_H__ + +#include + +/* + * +----------------------+ + * | Zero Page (Unmapped) | + * +----------------------+ 0x00000000_00000100 User Space Start + * | | + * | User Space | + * . + * . + * . + * | | + * +----------------------+ 0x00008000_00000000 User Space End + * | | + * | Non-canonical | + * . + * . + * . + * | | + * +----------------------+ 0xFFFF8000_00000000 Direct Map + * | Direct Map | + * +----------------------+ 0xFFFF8100_00000000 XMap Start + * | XMap | + * +----------------------+ 0xFFFF8120_00000000 XMap Top + * + * + */ +#define MEM_USERSPACE_BASE 0x0000000000000000ULL +#define MEM_USERSPACE_LEN 0x0000800000000000ULL +#define MEM_USERSPACE_TOP (MEM_USERSPACE_BASE + MEM_USERSPACE_LEN) + +#define MEM_USERSPACE_STKBASE 0x0000000070000000ULL +#define MEM_USERSPACE_STKLEN 0x0000000000010000ULL +#define MEM_USERSPACE_STKTOP (MEM_USERSPACE_STKBASE + MEM_USERSPACE_STKLEN) + +#define MEM_DIRECTMAP_BASE 0xFFFF800000000000ULL +#define MEM_DIRECTMAP_LEN 0x0000010000000000ULL +#define MEM_XMAP_BASE 0xFFFF810000000000ULL +#define MEM_XMAP_LEN 0x0000002000000000ULL + +#define PPN2DMVA(ppn) (((ppn) << PGSIZE) + MEM_DIRECTMAP_BASE) +#define DMVA2PPN(dmva) (((dmva) - MEM_DIRECTMAP_BASE) >> PGSIZE) +#define DMVA2PA(dmva) ((dmva) - MEM_DIRECTMAP_BASE) +#define DMPA2VA(pa) ((pa) + MEM_DIRECTMAP_BASE) +#define VA2PA(va) PMap_Translate(PMap_CurrentAS(), va) + +typedef struct AS +{ + PageTable *root; + uint64_t tables; + uint64_t mappings; +} AS; + +void PMap_Init(); +void PMap_InitAP(); + +AS* PMap_NewAS(); +void PMap_DestroyAS(AS *space); +AS* PMap_CurrentAS(); +void PMap_LoadAS(AS *space); +void PMap_Dump(AS *space); + +uintptr_t PMap_Translate(AS *space, uintptr_t va); + +// Manipulate User Memory +bool PMap_Map(AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags); +bool PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags); +bool PMap_Unmap(AS *as, uint64_t virt, uint64_t pages); + +// Manipulate Kernel Memory +void PMap_SystemLookup(uint64_t va, PageEntry **entry, int size); +bool PMap_SystemLMap(uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags); +bool PMap_SystemMap(uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags); +bool PMap_SystemUnmap(uint64_t virt, uint64_t pages); + +#endif /* __PMAP_H__ */ + diff --git a/sys/arm64/include/thread.h b/sys/arm64/include/thread.h new file mode 100644 index 0000000..102d6e1 --- /dev/null +++ b/sys/arm64/include/thread.h @@ -0,0 +1,17 @@ + +#ifndef __MACHINE_THREAD_H__ +#define __MACHINE_THREAD_H__ + +#include +#include + +typedef struct ThreadArchStackFrame { +} ThreadArchStackFrame; + +typedef struct ThreadArch { + bool useFP; + uint64_t rsp; +} ThreadArch; + +#endif /* __MACHINE_THREAD_H__ */ + diff --git a/sys/arm64/include/trap.h b/sys/arm64/include/trap.h new file mode 100644 index 0000000..6e409e2 --- /dev/null +++ b/sys/arm64/include/trap.h @@ -0,0 +1,91 @@ + +#ifndef __TRAP_H__ +#define __TRAP_H__ + +#define T_DE 0 /* Divide Error Exception */ +#define T_DB 1 /* Debug Exception */ +#define T_NMI 2 /* NMI Interrupt */ +#define T_BP 3 /* Breakpoint Exception */ +#define T_OF 4 /* Overflow Exception */ +#define T_BR 5 /* BOUND Range Exceeded Exception */ +#define T_UD 6 /* Invalid Opcode Exception */ +#define T_NM 7 /* Device Not Available Exception */ +#define T_DF 8 /* Double Fault Exception */ +#define T_TS 10 /* Invalid TSS Exception */ +#define T_NP 11 /* Segment Not Present */ +#define T_SS 12 /* Stack Fault Exception */ +#define T_GP 13 /* General Protection Exception */ +#define T_PF 14 /* Page-Fault Exception */ +#define T_MF 16 /* x87 FPU Floating-Point Error */ +#define T_AC 17 /* Alignment Check Exception */ +#define T_MC 18 /* Machine-Check Exception */ +#define T_XF 19 /* SIMB Floating-Point Exception */ +#define T_VE 20 /* Virtualization Exception */ + +#define T_CPU_LAST T_VE + +// IRQs +#define T_IRQ_BASE 32 +#define T_IRQ_LEN 24 +#define T_IRQ_MAX (T_IRQ_BASE + T_IRQ_LEN - 1) + +#define T_IRQ_TIMER (T_IRQ_BASE + 0) +#define T_IRQ_KBD (T_IRQ_BASE + 1) +#define T_IRQ_COM1 (T_IRQ_BASE + 4) +#define T_IRQ_MOUSE (T_IRQ_BASE + 12) + +// LAPIC Special Vectors +#define T_IRQ_SPURIOUS (T_IRQ_BASE + 24) +#define T_IRQ_ERROR (T_IRQ_BASE + 25) +#define T_IRQ_THERMAL (T_IRQ_BASE + 26) + +#define T_SYSCALL 60 /* System Call */ +#define T_CROSSCALL 61 /* Cross Call (IPI) */ +#define T_DEBUGIPI 62 /* Kernel Debugger Halt (IPI) */ + +#define T_UNKNOWN 63 /* Unknown Trap */ + +#define T_MAX 64 + +typedef struct TrapFrame +{ + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rbp; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t ds; + uint64_t rax; + + uint64_t vector; + uint32_t errcode; + uint32_t _unused0; + uint64_t rip; + uint16_t cs; + uint16_t _unused1; + uint16_t _unused2; + uint16_t _unused3; + uint64_t rflags; + uint64_t rsp; + uint16_t ss; + uint16_t _unused4; + uint16_t _unused5; + uint16_t _unused6; +} TrapFrame; + +void Trap_Init(); +void Trap_InitAP(); +void Trap_Dump(TrapFrame *tf); +void Trap_Pop(TrapFrame *tf); + +#endif /* __TRAP_H__ */ + diff --git a/sys/arm64/irq.c b/sys/arm64/irq.c new file mode 100644 index 0000000..4cd8ebc --- /dev/null +++ b/sys/arm64/irq.c @@ -0,0 +1,53 @@ + +#include + +#include +#include + +#include +#include + +LIST_HEAD(IRQHandlerList, IRQHandler); +struct IRQHandlerList handlers[T_IRQ_LEN]; + +void +IRQ_Init() +{ + int i; + + for (i = 0; i < T_IRQ_LEN; i++) + { + LIST_INIT(&handlers[i]); + } +} + +void +IRQ_Handler(int irq) +{ + struct IRQHandler *h; + LIST_FOREACH(h, &handlers[irq], link) + { + h->cb(h->arg); + } +} + +void +IRQ_Register(int irq, struct IRQHandler *h) +{ + ASSERT(irq < T_IRQ_LEN); + + LIST_INSERT_HEAD(&handlers[irq], h, link); + + //IOAPIC_Enable(irq); +} + +void +IRQ_Unregister(int irq, struct IRQHandler *h) +{ + LIST_REMOVE(h, link); + + if (LIST_EMPTY(&handlers[irq])) { + //IOAPIC_Disable(irq); + } +} + diff --git a/sys/arm64/kernel.lds b/sys/arm64/kernel.lds new file mode 100644 index 0000000..7bf53ed --- /dev/null +++ b/sys/arm64/kernel.lds @@ -0,0 +1,227 @@ +/*OUTPUT_FORMAT("elf64-arm64-freebsd", + "elf64-arm64-freebsd", + "elf64-arm64-freebsd")*/ + +OUTPUT_ARCH(arm:arm64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", + 0xFFFF800000400000)); + . = SEGMENT_START("text-segment", 0xFFFF800000400000) + SIZEOF_HEADERS; + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } + .plt : { *(.plt) *(.iplt) } + .init : + { + KEEP (*(.init)) + } + .fini : + { + KEEP (*(.fini)) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.init : { *(.rela.init) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rela.fini : { *(.rela.fini) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.got : { *(.rela.got) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rela.ldata : { *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) } + .rela.lbss : { *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) } + .rela.lrodata : { *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) } + .rela.ifunc : { *(.rela.ifunc) } + .rela.plt : + { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table + .gcc_except_table.*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges + .exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = .; + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(.init_array.* .ctors.*)) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array.* .dtors.*)) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + /* Kernel Debugger */ + .kdbgcmd ALIGN(CONSTANT(COMMONPAGESIZE)) : + { + __kdbgcmd_start = .; + *(.kdbgcmd) + __kdbgcmd_end = .; + } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/sys/arm64/machine.c b/sys/arm64/machine.c new file mode 100644 index 0000000..4d23a88 --- /dev/null +++ b/sys/arm64/machine.c @@ -0,0 +1,170 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../dev/console.h" + +extern void KTime_Init(); +extern void KTimer_Init(); +extern void RTC_Init(); +extern void PCI_Init(); +extern void MachineBoot_AddMem(); +extern void Loader_LoadInit(); +extern void PAlloc_LateInit(); + +/** + * Machine_SyscallInit -- + * + * Configure the model specific registers (MSRs) that specify how to transfer + * control to the operating system when the system call instruction is invoked. + */ +static void +Machine_SyscallInit() +{ + kprintf("Initializing Syscall... "); + + NOT_IMPLEMENTED(); + + kprintf("Done!\n"); +} + +/** + * Machine_EarlyInit -- + * + * Initializes early kernel state. + */ +void +Machine_EarlyInit() +{ + Spinlock_EarlyInit(); + Critical_Init(); + Critical_Enter(); + WaitChannel_EarlyInit(); + Console_Init(); + PAlloc_Init(); +} + +static void +Machine_IdleThread(void *test) +{ + while (1) { enable_interrupts(); hlt(); } +} + +/** + * Machine_Init -- + * + * At this point the assembly startup code has setup temporary processor data + * structures sufficient to execute C code and make it through this + * initialization routine. + */ +void Machine_Init() +{ + /* + * Initialize Processor State + */ + //Trap_Init(); + Machine_SyscallInit(); + + /* + * Initialize Memory Allocation and Virtual Memory + */ + //PAlloc_AddRegion(DMPA2VA(16*1024*1024), 16*1024*1024); + PMap_Init(); + XMem_Init(); + PAlloc_LateInit(); + MachineBoot_AddMem(); + + /* + * Initialize Time Keeping + */ + KTime_Init(); + RTC_Init(); // Finishes initializing KTime + + /* + * Initialize Interrupts + */ + IRQ_Init(); + // GICv3 + Thread_Init(); + + KTimer_Init(); // Depends on RTC and KTime + + /* + * Initialize Additional Processors + */ + MP_Init(); + + /* + * Initialize Basic Devices + */ + PCI_Init(); // PCI BUS + BufCache_Init(); + + /* + * Open the primary disk and mount the root file system + */ + Disk *root = Disk_GetByID(0, 0); + if (!root) + Panic("No boot disk!"); + VFS_MountRoot(root); + + Critical_Exit(); + + /* + * Create the idle thread + */ + Thread *thr = Thread_KThreadCreate(&Machine_IdleThread, NULL); + if (thr == NULL) { + kprintf("Couldn't create idle thread!\n"); + } + Sched_SetRunnable(thr); + + /* + * Load the init processor + */ + Loader_LoadInit(); + + breakpoint(); +} + +/** + * Machine_InitAP -- + * + * Shorter initialization routine for co-processors. + */ +void Machine_InitAP() +{ + Critical_Enter(); + + // Setup CPU state + Trap_InitAP(); + PMap_InitAP(); + Machine_SyscallInit(); + + // Setup LAPIC + + // Boot processor + MP_InitAP(); + Thread_InitAP(); + Critical_Exit(); + + Machine_IdleThread(NULL); +} + diff --git a/sys/arm64/mbentry.c b/sys/arm64/mbentry.c new file mode 100644 index 0000000..a537a57 --- /dev/null +++ b/sys/arm64/mbentry.c @@ -0,0 +1,61 @@ +/* + * Multiboot C Entry + */ + +#include +#include + +#include +#include + +#include "../dev/console.h" + +#include + +void MachineBoot_Entry(unsigned long magic, unsigned long addr); + +#define PAGE_ALIGN __attribute__((aligned(PGSIZE))) +#define DATA_SECTION __attribute__((section(".data"))) + +extern void Machine_EarlyInit(); +extern void Machine_Init(); +extern void PAlloc_AddRegion(uintptr_t start, uintptr_t len); + +#define MAX_REGIONS 16 +static uintptr_t memRegionStart[MAX_REGIONS]; +static uintptr_t memRegionLen[MAX_REGIONS]; +static int memRegionIdx; + +void +MachineBoot_Entry(unsigned long magic, unsigned long addr) +{ + // Main initialization + Machine_Init(); + + return; +} + +void +MachineBoot_AddMem() +{ + int i; + uintptr_t initRamEnd = 32*1024*1024; + + for (i = 0; i < memRegionIdx; i++) + { + uintptr_t start = memRegionStart[i]; + uintptr_t len = memRegionLen[i]; + + if (start + len < initRamEnd) + continue; + + if (start < initRamEnd) { + len = initRamEnd - start; + start = initRamEnd; + } + + kprintf("AddRegion: %08llx %08llx\n", start, len); + PAlloc_AddRegion(start + MEM_DIRECTMAP_BASE, len); + } +} + diff --git a/sys/arm64/mp.c b/sys/arm64/mp.c new file mode 100644 index 0000000..07131f6 --- /dev/null +++ b/sys/arm64/mp.c @@ -0,0 +1,213 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern uint8_t mpstart_begin[]; +extern uint8_t mpstart_end[]; + +extern AS systemAS; + +#define MP_WAITTIME 250000000ULL + +typedef struct CrossCallFrame { + CrossCallCB cb; + void *arg; + volatile int count; + volatile int done[MAX_CPUS]; + volatile int status[MAX_CPUS]; +} CrossCallFrame; + +const char *CPUStateToString[] = { + "NOT PRESENT", + "BOOTED", + "HALTED", +}; + +typedef struct CPUState { + int state; + UnixEpochNS heartbeat; + CrossCallFrame *frame; +} CPUState; + +volatile static bool booted; +volatile static int lastCPU; +volatile static CPUState cpus[MAX_CPUS]; + +void +MP_Init() +{ + int i; + kprintf("Booting on CPU %u\n", CPU()); + + cpus[CPU()].state = CPUSTATE_BOOTED; + cpus[CPU()].frame = NULL; + + for (i = 1; i < MAX_CPUS; i++) { + cpus[i].state = CPUSTATE_NOT_PRESENT; + cpus[i].frame = NULL; + } + + /* + * XXX: We really should read from the MP Table, but this appears to be + * reliable for now. + */ + lastCPU = 0; + /* + for (i = 1; i < MAX_CPUS; i++) { + if (MPBootAP(i) < 0) + break; + + lastCPU = i; + } + */ + lastCPU++; +} + +void +MP_InitAP() +{ + kprintf("AP %d booted!\n", CPU()); + cpus[CPU()].state = CPUSTATE_BOOTED; + booted = 1; +} + +void +MP_SetState(int state) +{ + ASSERT(state > 0 && state <= CPUSTATE_MAX); + cpus[CPU()].state = state; +} + +int +MP_GetCPUs() +{ + return lastCPU; +} + +void +MP_CrossCallTrap() +{ + int c; + + Critical_Enter(); + + for (c = 0; c <= lastCPU; c++) { + CrossCallFrame *frame = cpus[c].frame; + if (frame == NULL) + continue; + + if (frame->done[CPU()] == 1) + continue; + + frame->status[CPU()] = (frame->cb)(frame->arg); + frame->done[CPU()] = 1; + + // Increment + __sync_add_and_fetch(&frame->count, 1); + } + + Critical_Exit(); +} + +// XXX: The thread should not be migrated in the middle of this call. +int +MP_CrossCall(CrossCallCB cb, void *arg) +{ + volatile CrossCallFrame frame; + + // Setup frame + memset((void *)&frame, 0, sizeof(frame)); + frame.cb = cb; + frame.arg = arg; + frame.count = 1; + + Critical_Enter(); + + cpus[CPU()].frame = (CrossCallFrame *)&frame; + + /* + if (LAPIC_Broadcast(T_CROSSCALL) < 0) + return -1; + */ + + // Run on the local CPU + frame.status[CPU()] = cb(arg); + frame.done[CPU()] = 1; + + // Wait for all to respond + while (frame.count < lastCPU) { + // Check for timeout + + // XXX: Should dump the crosscall frame + } + cpus[CPU()].frame = NULL; + + Critical_Exit(); + + return 0; +} + +static int +MPPing(void *arg) +{ + //kprintf("CPU %d Ack\n", CPU()); + return 0; +} + +static void +Debug_CrossCall(int argc, const char *argv[]) +{ + int i; + UnixEpochNS startTS, stopTS; + + startTS = KTime_GetEpochNS(); + for (i = 0; i < 32; i++) { + MP_CrossCall(&MPPing, NULL); + } + stopTS = KTime_GetEpochNS(); + + // XXX: Print min and max + kprintf("Average CrossCall Latency: %llu ns\n", + (stopTS - startTS) / 32ULL); + + return; +} + +REGISTER_DBGCMD(crosscall, "Ping crosscall", Debug_CrossCall); + +static void +Debug_CPUS(int argc, const char *argv[]) +{ + int c; + + for (c = 0; c < MAX_CPUS; c++) { + if (cpus[c].state != CPUSTATE_NOT_PRESENT) { + kprintf("CPU %d: %s\n", c, CPUStateToString[cpus[c].state]); + } + } +} + +REGISTER_DBGCMD(cpus, "Show MP information", Debug_CPUS); + +static void +Debug_CPU(int argc, const char *argv[]) +{ + kprintf("CPU %d\n", CPU()); +} + +REGISTER_DBGCMD(cpu, "Current CPU number", Debug_CPU); + diff --git a/sys/arm64/multiboot.S b/sys/arm64/multiboot.S new file mode 100644 index 0000000..12e1c16 --- /dev/null +++ b/sys/arm64/multiboot.S @@ -0,0 +1,30 @@ +/* + * Multiboot Entry + */ + +#define STACK_SIZE 0x4000 + +#define KERNEL_BASE 0xFFFF800000000000 +#define LOWMEM(_x) (_x - KERNEL_BASE) + +.extern mb_entry + +.text + +/** + * _start -- + * + * ELF entry point. + */ +.globl _start +_start: + #call MachineBoot_Entry +loop: + #hlt + #jmp loop + +// Boot stack +.p2align 12 +.globl stack +.comm stack, STACK_SIZE + diff --git a/sys/arm64/pci.c b/sys/arm64/pci.c new file mode 100644 index 0000000..ef5a84b --- /dev/null +++ b/sys/arm64/pci.c @@ -0,0 +1,77 @@ + +#include + +#include +#include + +#include +#include + +#define PCI_PORT_ADDR 0xCF8 +#define PCI_PORT_DATABASE 0xCFC + +static inline uint32_t +PCIGetAddr(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg) +{ + ASSERT(bus < 256 && slot < 64 && func < 8 && reg < 256); + return (1 << 31) | (bus << 16) | (slot << 11) | (func << 8) | (reg & 0x00fc); +} + +uint8_t +PCICfgRead8(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg) +{ + uint32_t addr = PCIGetAddr(bus, slot, func, reg); + uint16_t port = PCI_PORT_DATABASE + (reg & 0x3); + + return 0; +} + +uint16_t +PCICfgRead16(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg) +{ + uint32_t addr = PCIGetAddr(bus, slot, func, reg); + uint16_t port = PCI_PORT_DATABASE + (reg & 0x2); + + ASSERT((reg & 0x1) == 0); + + return 0; +} + +uint32_t +PCICfgRead32(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg) +{ + uint32_t addr = PCIGetAddr(bus, slot, func, reg); + uint16_t port = PCI_PORT_DATABASE; + + ASSERT((reg & 0x3) == 0); + + return 0; +} + +void +PCICfgWrite8(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg, + uint8_t data) +{ + uint32_t addr = PCIGetAddr(bus, slot, func, reg); + uint16_t port = PCI_PORT_DATABASE + (reg & 0x3); + +} + +void +PCICfgWrite16(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg, + uint16_t data) +{ + uint32_t addr = PCIGetAddr(bus, slot, func, reg); + uint16_t port = PCI_PORT_DATABASE + (reg & 0x3); + +} + +void +PCICfgWrite32(uint32_t bus, uint32_t slot, uint32_t func, uint32_t reg, + uint32_t data) +{ + uint32_t addr = PCIGetAddr(bus, slot, func, reg); + uint16_t port = PCI_PORT_DATABASE + (reg & 0x3); + +} + diff --git a/sys/arm64/pmap.c b/sys/arm64/pmap.c new file mode 100644 index 0000000..ef8d32e --- /dev/null +++ b/sys/arm64/pmap.c @@ -0,0 +1,323 @@ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +AS systemAS; +AS *currentAS[MAX_CPUS]; + +void +PMap_Init() +{ + int i, j; + + kprintf("Initializing PMAP ... "); + + // Setup global state + for (i = 0; i < MAX_CPUS; i++) { + currentAS[i] = 0; + } + + // Allocate system page table + systemAS.root = PAlloc_AllocPage(); + systemAS.tables = PAGETABLE_ENTRIES / 2 + 1; + systemAS.mappings = 0; + + if (!systemAS.root) + PANIC("Cannot allocate system page table"); + + // Setup system mappings + PMap_SystemLMap(0x0, MEM_DIRECTMAP_BASE + 0x0, + 3*512, 0); // 3GB RWX + PMap_SystemLMap(0xC0000000, MEM_DIRECTMAP_BASE + 0xC0000000, + 512, 0); // 1GB RW + PCD + PMap_SystemLMap(0x100000000, MEM_DIRECTMAP_BASE + 0x100000000, + 60*512, 0); // 60GB RWX + + PMap_LoadAS(&systemAS); + + kprintf("Done!\n"); +} + +void +PMap_InitAP() +{ + PMap_LoadAS(&systemAS); +} + +/** + * PMap_NewAS -- + * + * Create a new address space. + * + * @return Newly created address space. + */ +AS* +PMap_NewAS() +{ + int i; + AS *as = PAlloc_AllocPage(); + + if (!as) + return NULL; + + as->root = PAlloc_AllocPage(); + as->tables = 1; + as->mappings = 0; + + // NOT IMPLEMENTED + + return as; +} + +/** + * PMap_DestroyAS -- + * + * Destroys an address space and releases the physical pages. + * + * @param [in] space Address space to destroy. + */ +void +PMap_DestroyAS(AS *space) +{ +} + +/** + * PMap_CurrentAS -- + * + * Get the current address space on this CPU. + * + * @return Current address space. + */ +AS * +PMap_CurrentAS() +{ + return currentAS[CPU()]; +} + +/** + * PMap_LoadAS -- + * + * Load an address space into the CPU. Reloads the CR3 register in x86-64 that + * points the physical page tables and flushes the TLB entries. + * + * @param [in] space Address space to load. + */ +void +PMap_LoadAS(AS *space) +{ + // Flush TLB + currentAS[CPU()] = space; +} + +/** + * PMapAllocPageTable -- + * + * Allocates and initializes a page table. + * + * @return Newly created PageTable. + */ +static PageTable * +PMapAllocPageTable() +{ + NOT_IMPLEMENTED(); + return NULL; +} + +/** + * PMap_Translate -- + * + * Translates a virtual address to physical address for a given address space. + * + * @param [in] space Address space we wish to lookup a mapping in. + * @param [in] va Virtual address we wish to translate. + */ +uintptr_t +PMap_Translate(AS *space, uintptr_t va) +{ + NOT_IMPLEMENTED(); + return 0; +} + +/** + * PMapLookupEntry -- + * + * Lookup a virtual address in a page table and return a pointer to the page + * entry. This function allocates page tables as necessary to fill in the + * 4-level heirarchy. + * + * @param [in] space Address space to search. + * @param [in] va Virtual address to lookup. + * @param [out] entry Pointer will point to the PageEntry. + * @param [in] size Page size we want to use. + */ +static void +PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size) +{ + NOT_IMPLEMENTED(); + return; +} + +/** + * PMap_Map -- + * + * Map a physical to virtual mapping in an address space. + * + * @param [in] as Address space. + * @param [in] phys Physical address. + * @param [in] virt Virtual address. + * @param [in] pages Pages to map in. + * @param [in] flags Flags to apply to the mapping. + * + * @retval true On success + * @retval false On failure + */ +bool +PMap_Map(AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags) +{ + NOT_IMPLEMENTED(); + return true; +} + +/** + * PMap_Unmap -- + * + * Unmap a range of addresses. + * + * @param [in] as Address space. + * @param [in] va Virtual address. + * @param [in] pages Pages to map in. + * + * @retval true On success + * @retval false On failure + */ +bool +PMap_Unmap(AS *as, uint64_t va, uint64_t pages) +{ + NOT_IMPLEMENTED(); + return true; +} + +/** + * PMap_AllocMap -- + * + * Map a virtual mapping in an address space and back it by newly allocated + * memory. + * + * @param [in] as Address space. + * @param [in] virt Virtual address. + * @param [in] pages Pages to map in. + * @param [in] flags Flags to apply to the mapping. + * + * @retval true On success + * @retval false On failure + */ +bool +PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags) +{ + NOT_IMPLEMENTED(); + return true; +} + +/** + * PMap_SystemLookup -- + * + * Lookup a kernel virtual address in a page table and return a pointer to the + * page entry. This function allocates page tables as necessary to fill in the + * 4-level heirarchy. + * + * @param [in] va Virtual address to lookup. + * @param [out] entry Pointer will point to the PageEntry. + * @param [in] size Page size we want to use. + */ +void +PMap_SystemLookup(uint64_t va, PageEntry **entry, int size) +{ + PMapLookupEntry(&systemAS, va, entry, size); +} + +/** + * PMap_SystemLMap -- + * + * Map a range of large (2MB) physical pages to virtual pages in the kernel + * address space that is shared by all processes. + * + * @param [in] phys Physical address. + * @param [in] virt Virtual address. + * @param [in] lpages Large pages to map in. + * @param [in] flags Flags to apply to the mapping. + * + * @retval true On success + * @retval false On failure + */ +bool +PMap_SystemLMap(uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags) +{ + NOT_IMPLEMENTED(); + return true; +} + +/** + * PMap_SystemLMap -- + * + * Map a range of physical pages to virtual pages in the kernel address space + * that is shared by all processes. + * + * @param [in] phys Physical address. + * @param [in] virt Virtual address. + * @param [in] pages Pages to map in. + * @param [in] flags Flags to apply to the mapping. + * + * @retval true On success + * @retval false On failure + */ +bool +PMap_SystemMap(uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags) +{ + NOT_IMPLEMENTED(); + return true; +} + +/** + * PMap_SystemUnmap -- + * + * We do not currently use this! + */ +bool +PMap_SystemUnmap(uint64_t virt, uint64_t pages) +{ + NOT_IMPLEMENTED(); + return false; +} + +static uint64_t +AddrFromIJKL(uint64_t i, uint64_t j, uint64_t k, uint64_t l) +{ + return (i << 39) | (j << HUGE_PGSHIFT) | (k << LARGE_PGSHIFT) | (l << PGSHIFT); +} + +void +PMap_Dump(AS *space) +{ + return; +} + +static void +Debug_PMapDump(int argc, const char *argv[]) +{ + PMap_Dump(currentAS[CPU()]); +} + +REGISTER_DBGCMD(pmapdump, "Dump memory mappings", Debug_PMapDump); + + diff --git a/sys/arm64/support.S b/sys/arm64/support.S new file mode 100644 index 0000000..3949db0 --- /dev/null +++ b/sys/arm64/support.S @@ -0,0 +1,26 @@ +/* + * Support Functions + */ + +#include +#include + +.text + +// copy_unsafe(to, from, len) +FUNC_BEGIN(copy_unsafe) +.globl copy_unsafe_done +copy_unsafe_done: +.globl copy_unsafe_fault +copy_unsafe_fault: +FUNC_END(copy_unsafe) + +// copystr_unsafe(to, from, len) +FUNC_BEGIN(copystr_unsafe) +.globl copystr_unsafe_done +copystr_unsafe_done: +.globl copystr_unsafe_fault +copystr_unsafe_fault: +.globl copystr_unsafe_toolong +FUNC_END(copystr_unsafe) + diff --git a/sys/arm64/switch.S b/sys/arm64/switch.S new file mode 100644 index 0000000..6093111 --- /dev/null +++ b/sys/arm64/switch.S @@ -0,0 +1,19 @@ +/* + * Trap Handlers + */ + +#include + +.text + +# switch(uint64_t *oldsp, uint64_t newsp) +# %rdi: oldsp +# %rsi: newsp +FUNC_BEGIN(switchstack) + # Save callee saved registers of old thread + + # Switch stack from old to new thread + + # Restore callee saved registers of new thread +FUNC_END(switchstack) + diff --git a/sys/arm64/thread.c b/sys/arm64/thread.c new file mode 100644 index 0000000..f7f58f3 --- /dev/null +++ b/sys/arm64/thread.c @@ -0,0 +1,68 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern void ThreadKThreadEntry(TrapFrame *tf); +extern void switchstack(uint64_t *oldrsp, uint64_t rsp); + +void +Thread_InitArch(Thread *thr) +{ + thr->arch.useFP = true; +} + +void +Thread_SetupKThread(Thread *thr, void (*f)(), + uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) +{ + // Initialize stack + uint64_t stacktop = thr->kstack + PGSIZE; + ThreadArchStackFrame *sf; + TrapFrame *tf; + + tf = (TrapFrame *)(stacktop - sizeof(*tf)); + sf = (ThreadArchStackFrame *)(stacktop - sizeof(*tf) - sizeof(*sf)); + + memset(tf, 0, sizeof(*tf)); + memset(sf, 0, sizeof(*sf)); + + // Setup thread exit function on stack + +} + +static void +ThreadEnterUserLevelCB(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) +{ + TrapFrame tf; + + memset(&tf, 0, sizeof(tf)); + + Trap_Pop(&tf); +} + +void +Thread_SetupUThread(Thread *thr, uintptr_t rip, uintptr_t arg) +{ + Thread_SetupKThread(thr, ThreadEnterUserLevelCB, rip, + thr->ustack, arg); +} + +void +Thread_SwitchArch(Thread *oldthr, Thread *newthr) +{ + // Jump to trapframe + switchstack(&oldthr->arch.rsp, newthr->arch.rsp); +} + diff --git a/sys/arm64/time.c b/sys/arm64/time.c new file mode 100644 index 0000000..8eec58a --- /dev/null +++ b/sys/arm64/time.c @@ -0,0 +1,25 @@ + +#include +#include + +#include +#include +#include + +#include +#include + +uint64_t +Time_GetTSC() +{ + return 0; +} + +static void +Debug_ReadTSC(int argc, const char *argv[]) +{ + kprintf("RDTSC: %lld\n", Time_GetTSC()); +} + +REGISTER_DBGCMD(readtsc, "Print current timestamp", Debug_ReadTSC); + diff --git a/sys/arm64/trap.c b/sys/arm64/trap.c new file mode 100644 index 0000000..d9a256a --- /dev/null +++ b/sys/arm64/trap.c @@ -0,0 +1,121 @@ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +extern uint64_t trap_table[T_MAX]; +extern void trap_pop(TrapFrame *tf); +extern void Debug_Breakpoint(TrapFrame *tf); +extern void Debug_HaltIPI(TrapFrame *tf); +extern void KTimer_Process(); + +static uint64_t intStats[256]; + +void +Trap_Init() +{ + int i; + + kprintf("Initializing IDT... "); + + for (i = 0; i < 256; i++) { + intStats[i] = 0; + } + + kprintf("Done!\n"); +} + +void +Trap_InitAP() +{ +} + +void +Trap_Dump(TrapFrame *tf) +{ + kprintf("CPU %d\n", CPU()); + kprintf("Interrupt %d Error Code: %016llx\n", + tf->vector, tf->errcode); +} + +void +Trap_StackDump(TrapFrame *tf) +{ + uint64_t rsp; + uint64_t *data; + + // XXX: This should use safe copy + for (rsp = tf->rsp; (rsp & 0xFFF) != 0; rsp += 8) { + data = (uint64_t *)rsp; + kprintf("%016llx: %016llx\n", rsp, *data); + } +} + +extern int copy_unsafe(void *to, void *from, uintptr_t len); +extern void copy_unsafe_done(void); +extern void copy_unsafe_fault(void); + +extern int copystr_unsafe(void *to, void *from, uintptr_t len); +extern void copystr_unsafe_done(void); +extern void copystr_unsafe_fault(void); + +void +trap_entry(TrapFrame *tf) +{ + // XXX: USE ATOMIC! + intStats[tf->vector]++; + + // Debug NMI + + // Kernel + // Kernel Debugger + + // User IO + + // Halt on kernel errors + + // User space exceptions + + // IRQs + + // Debug IPI + + // Cross calls + + kprintf("Unhandled Interrupt 0x%x!\n", tf->vector); + Trap_Dump(tf); + while (1) + hlt(); +} + +static void +Debug_Traps(int argc, const char *argv[]) +{ + int i; + + kprintf("Trap Interrupts Trap Interrupts\n"); + for (i = 0; i < T_MAX / 2; i++) + { + kprintf("%-4d %-12d %-4d %-12d\n", + i, intStats[i], + T_MAX / 2 + i, intStats[T_MAX / 2 + i]); + } +} + +REGISTER_DBGCMD(traps, "Print trap statistics", Debug_Traps); + diff --git a/sys/arm64/trapentry.S b/sys/arm64/trapentry.S new file mode 100644 index 0000000..4609d4d --- /dev/null +++ b/sys/arm64/trapentry.S @@ -0,0 +1,38 @@ +/* + * Trap Handlers + */ + +.extern trap_entry + +.text + +.macro TRAP_NOEC TRAPNUM +trap\TRAPNUM: + # Push top of the trap frame +.endm + +.macro TRAP_EC TRAPNUM +trap\TRAPNUM: + # Push top of the trap frame +.endm + +.globl trap_table +trap_table: +.quad trap0 + +TRAP_NOEC 0 // DE + +trap_common: + # Create the rest of the trap frame + + # Pass the trap frame as an argument to trap_entry +.globl trap_return +trap_return: + + # Skip error code and vector number + + # Return to userspace + +.globl Trap_Pop +Trap_Pop: + diff --git a/sys/include/mp.h b/sys/include/mp.h index 2fda7c0..2634641 100644 --- a/sys/include/mp.h +++ b/sys/include/mp.h @@ -2,9 +2,17 @@ #ifndef __MP_H__ #define __MP_H__ +#if defined(__x86_64__) uint32_t LAPIC_CPU(); #define CPU LAPIC_CPU +#elif defined(__aarch64__) +static inline int ARM_CPU() +{ + return 0; +} +#define CPU ARM_CPU +#endif #endif /* __MP_H__ */