├── .gitignore ├── 2012009-李彦泽-PA1报告.pdf ├── Makefile ├── README.md ├── abstract-machine ├── .gitignore ├── LICENSE ├── Makefile ├── README ├── am │ ├── Makefile │ ├── include │ │ ├── am.h │ │ ├── amdev.h │ │ └── arch │ │ │ ├── mips32-nemu.h │ │ │ ├── native.h │ │ │ ├── riscv32-nemu.h │ │ │ ├── riscv64-nemu.h │ │ │ ├── riscv64-npc.h │ │ │ ├── spike.h │ │ │ ├── x86-nemu.h │ │ │ ├── x86-qemu.h │ │ │ └── x86_64-qemu.h │ └── src │ │ ├── mips │ │ ├── mips32.h │ │ └── nemu │ │ │ ├── cte.c │ │ │ ├── start.S │ │ │ ├── trap.S │ │ │ └── vme.c │ │ ├── native │ │ ├── cte.c │ │ ├── ioe.c │ │ ├── ioe │ │ │ ├── audio.c │ │ │ ├── disk.c │ │ │ ├── gpu.c │ │ │ ├── input.c │ │ │ └── timer.c │ │ ├── mpe.c │ │ ├── platform.c │ │ ├── platform.h │ │ ├── trap.S │ │ ├── trm.c │ │ └── vme.c │ │ ├── platform │ │ ├── dummy │ │ │ ├── cte.c │ │ │ ├── ioe.c │ │ │ ├── mpe.c │ │ │ ├── trm.c │ │ │ └── vme.c │ │ └── nemu │ │ │ ├── include │ │ │ └── nemu.h │ │ │ ├── ioe │ │ │ ├── audio.c │ │ │ ├── disk.c │ │ │ ├── gpu.c │ │ │ ├── input.c │ │ │ ├── ioe.c │ │ │ └── timer.c │ │ │ ├── mpe.c │ │ │ └── trm.c │ │ ├── riscv │ │ ├── nemu │ │ │ ├── cte.c │ │ │ ├── start.S │ │ │ ├── trap.S │ │ │ └── vme.c │ │ ├── npc │ │ │ ├── cte.c │ │ │ ├── input.c │ │ │ ├── ioe.c │ │ │ ├── mpe.c │ │ │ ├── start.S │ │ │ ├── timer.c │ │ │ ├── trap.S │ │ │ ├── trm.c │ │ │ └── vme.c │ │ ├── riscv.h │ │ └── spike │ │ │ ├── atomic.h │ │ │ ├── htif.c │ │ │ ├── htif.h │ │ │ ├── ioe.c │ │ │ ├── linker.ld │ │ │ ├── start.S │ │ │ ├── timer.c │ │ │ └── trm.c │ │ └── x86 │ │ ├── nemu │ │ ├── cte.c │ │ ├── start.S │ │ ├── trap.S │ │ └── vme.c │ │ ├── qemu │ │ ├── boot │ │ │ ├── Makefile │ │ │ ├── genboot.py │ │ │ ├── main.c │ │ │ └── start.S │ │ ├── cte.c │ │ ├── ioe.c │ │ ├── mpe.c │ │ ├── start32.S │ │ ├── start64.S │ │ ├── trap32.S │ │ ├── trap64.S │ │ ├── trm.c │ │ ├── vme.c │ │ └── x86-qemu.h │ │ └── x86.h ├── klib │ ├── Makefile │ ├── include │ │ ├── klib-macros.h │ │ └── klib.h │ └── src │ │ ├── cpp.c │ │ ├── int64.c │ │ ├── stdio.c │ │ ├── stdlib.c │ │ └── string.c └── scripts │ ├── isa │ ├── mips32.mk │ ├── riscv32.mk │ ├── riscv64.mk │ ├── x86.mk │ └── x86_64.mk │ ├── linker.ld │ ├── mips32-nemu.mk │ ├── native.mk │ ├── platform │ ├── nemu.mk │ └── qemu.mk │ ├── riscv32-nemu.mk │ ├── riscv64-nemu.mk │ ├── riscv64-npc.mk │ ├── spike.mk │ ├── x86-nemu.mk │ ├── x86-qemu.mk │ └── x86_64-qemu.mk ├── init.sh └── nemu ├── .gitignore ├── Kconfig ├── Makefile ├── README.md ├── configs ├── .gitignore ├── riscv32-am_defconfig └── riscv64-am_defconfig ├── include ├── common.h ├── cpu │ ├── cpu.h │ ├── decode.h │ ├── difftest.h │ └── ifetch.h ├── debug.h ├── device │ ├── alarm.h │ ├── map.h │ └── mmio.h ├── difftest-def.h ├── isa.h ├── macro.h ├── memory │ ├── host.h │ ├── paddr.h │ └── vaddr.h └── utils.h ├── resource ├── debian │ └── README.md ├── mips-elf │ └── README.md └── sdcard │ ├── README.md │ └── nemu.c ├── scripts ├── build.mk ├── config.mk └── native.mk ├── src ├── am-bin.S ├── cpu │ ├── cpu-exec.c │ └── difftest │ │ ├── dut.c │ │ └── ref.c ├── device │ ├── Kconfig │ ├── alarm.c │ ├── audio.c │ ├── device.c │ ├── disk.c │ ├── filelist.mk │ ├── intr.c │ ├── io │ │ ├── map.c │ │ ├── mmio.c │ │ └── port-io.c │ ├── keyboard.c │ ├── mmc.h │ ├── sdcard.c │ ├── serial.c │ ├── timer.c │ └── vga.c ├── engine │ ├── filelist.mk │ └── interpreter │ │ ├── hostcall.c │ │ └── init.c ├── filelist.mk ├── isa │ ├── filelist.mk │ ├── riscv32 │ │ ├── difftest │ │ │ └── dut.c │ │ ├── include │ │ │ └── isa-def.h │ │ ├── init.c │ │ ├── inst.c │ │ ├── local-include │ │ │ └── reg.h │ │ ├── logo.c │ │ ├── reg.c │ │ └── system │ │ │ ├── intr.c │ │ │ └── mmu.c │ └── riscv64 │ │ ├── difftest │ │ └── dut.c │ │ ├── include │ │ └── isa-def.h │ │ ├── init.c │ │ ├── inst.c │ │ ├── local-include │ │ └── reg.h │ │ ├── logo.c │ │ ├── reg.c │ │ └── system │ │ ├── intr.c │ │ └── mmu.c ├── memory │ ├── Kconfig │ ├── paddr.c │ └── vaddr.c ├── monitor │ ├── monitor.c │ └── sdb │ │ ├── expr.c │ │ ├── sdb.c │ │ ├── watchpoint.c │ │ └── watchpoint.h ├── nemu-main.c └── utils │ ├── disasm.cc │ ├── filelist.mk │ ├── log.c │ ├── rand.c │ ├── state.c │ └── timer.c └── tools ├── difftest.mk ├── fixdep ├── Makefile └── fixdep.c ├── gen-expr ├── .gitignore ├── Makefile └── gen-expr.c ├── kconfig ├── .gitignore ├── Makefile ├── conf.c ├── confdata.c ├── expr.c ├── expr.h ├── lexer.l ├── list.h ├── lkc.h ├── lkc_proto.h ├── lxdialog │ ├── checklist.c │ ├── dialog.h │ ├── inputbox.c │ ├── menubox.c │ ├── textbox.c │ ├── util.c │ └── yesno.c ├── mconf.c ├── menu.c ├── parser.y ├── preprocess.c ├── symbol.c └── util.c ├── kvm-diff ├── Makefile ├── include │ └── paddr.h └── src │ └── kvm.c ├── qemu-diff ├── Makefile ├── include │ ├── common.h │ ├── isa.h │ └── protocol.h └── src │ ├── diff-test.c │ ├── gdb-host.c │ ├── isa.c │ └── protocol.c └── spike-diff ├── .gitignore ├── Makefile └── difftest.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !/nemu/* 5 | !/nexus-am/* 6 | !/nanos-lite/* 7 | !/navy-apps/* 8 | !Makefile 9 | !README.md 10 | !.gitignore 11 | !init.sh 12 | /fceux-am 13 | /am-kernels 14 | -------------------------------------------------------------------------------- /2012009-李彦泽-PA1报告.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PPPPPardon233/ics2022/c0b5223c03b116c44f23b9d72068b21219b47204/2012009-李彦泽-PA1报告.pdf -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | STUID = 2012009 2 | STUNAME = lyz 3 | 4 | # DO NOT modify the following code!!! 5 | 6 | GITFLAGS = -q --author='tracer-ics2022 ' --no-verify --allow-empty 7 | 8 | # prototype: git_commit(msg) 9 | define git_commit 10 | -@git add $(NEMU_HOME)/.. -A --ignore-errors 11 | -@while (test -e .git/index.lock); do sleep 0.1; done 12 | -@(echo "> $(1)" && echo $(STUID) $(STUNAME) && uname -a && uptime) | git commit -F - $(GITFLAGS) 13 | -@sync 14 | endef 15 | 16 | _default: 17 | @echo "Please run 'make' under subprojects." 18 | 19 | submit: 20 | git gc 21 | STUID=$(STUID) STUNAME=$(STUNAME) bash -c "$$(curl -s http://why.ink:8080/static/submit.sh)" 22 | 23 | .PHONY: default submit 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ICS2022 Programming Assignment 2 | 3 | This project is the programming assignment of the class ICS(Introduction to Computer System) 4 | in Department of Computer Science and Technology, Nanjing University. 5 | 6 | For the guide of this programming assignment, 7 | refer to https://nju-projectn.github.io/ics-pa-gitbook/ics2022/ 8 | 9 | To initialize, run 10 | ```bash 11 | bash init.sh subproject-name 12 | ``` 13 | See `init.sh` for more details. 14 | 15 | The following subprojects/components are included. Some of them are not fully implemented. 16 | * [NEMU](https://github.com/NJU-ProjectN/nemu) 17 | * [Abstract-Machine](https://github.com/NJU-ProjectN/abstract-machine) 18 | * [Nanos-lite](https://github.com/NJU-ProjectN/nanos-lite) 19 | * [Navy-apps](https://github.com/NJU-ProjectN/navy-apps) 20 | -------------------------------------------------------------------------------- /abstract-machine/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !*.h 4 | !*.c 5 | !*.cc 6 | !*.S 7 | !*.ld 8 | !*.sh 9 | !*.py 10 | !*.mk 11 | !Makefile 12 | !README 13 | !LICENSE 14 | .* 15 | _* 16 | *~ 17 | build/ 18 | !.gitignore 19 | .vscode -------------------------------------------------------------------------------- /abstract-machine/LICENSE: -------------------------------------------------------------------------------- 1 | The AbstractMachine software is: 2 | 3 | Copyright (c) 2018-2021 Yanyan Jiang and Zihao Yu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /abstract-machine/README: -------------------------------------------------------------------------------- 1 | AbstractMachine is a minimal, modularized, and machine-independent 2 | abstraction layer of the computer hardware: 3 | 4 | * physical memory and direct execution (The "Turing Machine"); 5 | * basic model for input and output devices (I/O Extension); 6 | * interrupt/exception and processor context management (Context Extension); 7 | * virtual memory and protection (Virtual Memory Extension); 8 | * multiprocessing (Multiprocessing Extension). 9 | 10 | CONTACTS 11 | 12 | Bug reports and suggestions go to Yanyan Jiang (jyy@nju.edu.cn) and Zihao 13 | Yu (yuzihao@ict.ac.cn). 14 | -------------------------------------------------------------------------------- /abstract-machine/am/Makefile: -------------------------------------------------------------------------------- 1 | NAME := am 2 | SRCS = $(addprefix src/, $(AM_SRCS)) 3 | INC_PATH += $(AM_HOME)/am/src 4 | 5 | include $(AM_HOME)/Makefile 6 | -------------------------------------------------------------------------------- /abstract-machine/am/include/am.h: -------------------------------------------------------------------------------- 1 | #ifndef AM_H__ 2 | #define AM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include ARCH_H // this macro is defined in $CFLAGS 8 | // examples: "arch/x86-qemu.h", "arch/native.h", ... 9 | 10 | // Memory protection flags 11 | #define MMAP_NONE 0x00000000 // no access 12 | #define MMAP_READ 0x00000001 // can read 13 | #define MMAP_WRITE 0x00000002 // can write 14 | 15 | // Memory area for [@start, @end) 16 | typedef struct { 17 | void *start, *end; 18 | } Area; 19 | 20 | // Arch-dependent processor context 21 | typedef struct Context Context; 22 | 23 | // An event of type @event, caused by @cause of pointer @ref 24 | typedef struct { 25 | enum { 26 | EVENT_NULL = 0, 27 | EVENT_YIELD, EVENT_SYSCALL, EVENT_PAGEFAULT, EVENT_ERROR, 28 | EVENT_IRQ_TIMER, EVENT_IRQ_IODEV, 29 | } event; 30 | uintptr_t cause, ref; 31 | const char *msg; 32 | } Event; 33 | 34 | // A protected address space with user memory @area 35 | // and arch-dependent @ptr 36 | typedef struct { 37 | int pgsize; 38 | Area area; 39 | void *ptr; 40 | } AddrSpace; 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | // ----------------------- TRM: Turing Machine ----------------------- 47 | extern Area heap; 48 | void putch (char ch); 49 | void halt (int code) __attribute__((__noreturn__)); 50 | 51 | // -------------------- IOE: Input/Output Devices -------------------- 52 | bool ioe_init (void); 53 | void ioe_read (int reg, void *buf); 54 | void ioe_write (int reg, void *buf); 55 | #include "amdev.h" 56 | 57 | // ---------- CTE: Interrupt Handling and Context Switching ---------- 58 | bool cte_init (Context *(*handler)(Event ev, Context *ctx)); 59 | void yield (void); 60 | bool ienabled (void); 61 | void iset (bool enable); 62 | Context *kcontext (Area kstack, void (*entry)(void *), void *arg); 63 | 64 | // ----------------------- VME: Virtual Memory ----------------------- 65 | bool vme_init (void *(*pgalloc)(int), void (*pgfree)(void *)); 66 | void protect (AddrSpace *as); 67 | void unprotect (AddrSpace *as); 68 | void map (AddrSpace *as, void *vaddr, void *paddr, int prot); 69 | Context *ucontext (AddrSpace *as, Area kstack, void *entry); 70 | 71 | // ---------------------- MPE: Multi-Processing ---------------------- 72 | bool mpe_init (void (*entry)()); 73 | int cpu_count (void); 74 | int cpu_current (void); 75 | int atomic_xchg (int *addr, int newval); 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/mips32-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_H__ 2 | #define __ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t hi, gpr[32], epc, cause, lo, status; 7 | void *pdir; 8 | }; 9 | 10 | #define GPR1 gpr[2] // v0 11 | #define GPR2 gpr[0] 12 | #define GPR3 gpr[0] 13 | #define GPR4 gpr[0] 14 | #define GPRx gpr[0] 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/native.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | #ifndef __USE_GNU 5 | # define __USE_GNU 6 | #endif 7 | 8 | #include 9 | 10 | struct Context { 11 | uintptr_t ksp; 12 | void *vm_head; 13 | ucontext_t uc; 14 | // skip the red zone of the stack frame, see the amd64 ABI manual for details 15 | uint8_t redzone[128]; 16 | }; 17 | 18 | #define GPR1 uc.uc_mcontext.gregs[REG_RDI] 19 | #define GPR2 uc.uc_mcontext.gregs[REG_RSI] 20 | #define GPR3 uc.uc_mcontext.gregs[REG_RDX] 21 | #define GPR4 uc.uc_mcontext.gregs[REG_RCX] 22 | #define GPRx uc.uc_mcontext.gregs[REG_RAX] 23 | 24 | #undef __USE_GNU 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/riscv32-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t mepc, mcause, gpr[32], mstatus; 7 | void *pdir; 8 | }; 9 | 10 | #define GPR1 gpr[17] // a7 11 | #define GPR2 gpr[0] 12 | #define GPR3 gpr[0] 13 | #define GPR4 gpr[0] 14 | #define GPRx gpr[0] 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/riscv64-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t mepc, mcause, gpr[32], mstatus; 7 | void *pdir; 8 | }; 9 | 10 | #define GPR1 gpr[17] // a7 11 | #define GPR2 gpr[0] 12 | #define GPR3 gpr[0] 13 | #define GPR4 gpr[0] 14 | #define GPRx gpr[0] 15 | #endif 16 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/riscv64-npc.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t mepc, mcause, gpr[32], mstatus; 7 | }; 8 | 9 | #define GPR1 gpr[17] // a7 10 | #define GPR2 gpr[0] 11 | #define GPR3 gpr[0] 12 | #define GPR4 gpr[0] 13 | #define GPRx gpr[0] 14 | #endif 15 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/spike.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | uintptr_t gpr[1]; 6 | }; 7 | 8 | #define GPR1 gpr[0] 9 | #define GPR2 gpr[0] 10 | #define GPR3 gpr[0] 11 | #define GPR4 gpr[0] 12 | #define GPRx gpr[0] 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/x86-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t esi, ebx, eax, eip, edx, eflags, ecx, cs, esp, edi, ebp; 7 | void *cr3; 8 | int irq; 9 | }; 10 | 11 | #define GPR1 eax 12 | #define GPR2 eip 13 | #define GPR3 eip 14 | #define GPR4 eip 15 | #define GPRx eip 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/x86-qemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | void *cr3; 6 | uint32_t ds, eax, ebx, ecx, edx, 7 | esp0, esi, edi, ebp, 8 | eip, cs, eflags, esp, ss3; 9 | }; 10 | 11 | #define GPR1 eax 12 | #define GPR2 ebx 13 | #define GPR3 ecx 14 | #define GPR4 edx 15 | #define GPRx eax 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/x86_64-qemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | void *cr3; 6 | uint64_t rax, rbx, rcx, rdx, 7 | rbp, rsi, rdi, 8 | r8, r9, r10, r11, 9 | r12, r13, r14, r15, 10 | rip, cs, rflags, 11 | rsp, ss, rsp0; 12 | }; 13 | 14 | 15 | #define GPR1 rdi 16 | #define GPR2 rsi 17 | #define GPR3 rdx 18 | #define GPR4 rcx 19 | #define GPRx rax 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /abstract-machine/am/src/mips/mips32.h: -------------------------------------------------------------------------------- 1 | #ifndef MIPS32_H__ 2 | #define MIPS32_H__ 3 | 4 | #include 5 | 6 | static inline uint8_t inb(uintptr_t addr) { return *(volatile uint8_t *)addr; } 7 | static inline uint16_t inw(uintptr_t addr) { return *(volatile uint16_t *)addr; } 8 | static inline uint32_t inl(uintptr_t addr) { return *(volatile uint32_t *)addr; } 9 | 10 | static inline void outb(uintptr_t addr, uint8_t data) { *(volatile uint8_t *)addr = data; } 11 | static inline void outw(uintptr_t addr, uint16_t data) { *(volatile uint16_t *)addr = data; } 12 | static inline void outl(uintptr_t addr, uint32_t data) { *(volatile uint32_t *)addr = data; } 13 | 14 | #define PTE_V 0x2 15 | #define PTE_D 0x4 16 | 17 | // Page directory and page table constants 18 | #define PTXSHFT 12 // Offset of PTX in a linear address 19 | #define PDXSHFT 22 // Offset of PDX in a linear address 20 | 21 | #define PDX(va) (((uint32_t)(va) >> PDXSHFT) & 0x3ff) 22 | #define PTX(va) (((uint32_t)(va) >> PTXSHFT) & 0x3ff) 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /abstract-machine/am/src/mips/nemu/cte.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static Context* (*user_handler)(Event, Context*) = NULL; 6 | 7 | static inline bool get_CU0(Context *c) { return (c->status >> 28) & 0x1; } 8 | 9 | Context* __am_irq_handle(Context *c) { 10 | if (user_handler) { 11 | Event ev = {0}; 12 | uint32_t ex_code = 0; 13 | switch (ex_code) { 14 | default: ev.event = EVENT_ERROR; break; 15 | } 16 | 17 | c = user_handler(ev, c); 18 | assert(c != NULL); 19 | } 20 | 21 | return c; 22 | } 23 | 24 | extern void __am_asm_trap(void); 25 | 26 | #define EX_ENTRY 0x80000180 27 | 28 | bool cte_init(Context*(*handler)(Event, Context*)) { 29 | // initialize exception entry 30 | const uint32_t j_opcode = 0x08000000; 31 | uint32_t instr = j_opcode | (((uint32_t)__am_asm_trap >> 2) & 0x3ffffff); 32 | *(uint32_t *)EX_ENTRY = instr; 33 | *(uint32_t *)(EX_ENTRY + 4) = 0; // delay slot 34 | *(uint32_t *)0x80000000 = instr; // TLB refill exception 35 | *(uint32_t *)(0x80000000 + 4) = 0; // delay slot 36 | 37 | // register event handler 38 | user_handler = handler; 39 | 40 | return true; 41 | } 42 | 43 | Context *kcontext(Area kstack, void (*entry)(void *), void *arg) { 44 | return NULL; 45 | } 46 | 47 | void yield() { 48 | asm volatile("syscall 1"); 49 | } 50 | 51 | bool ienabled() { 52 | return false; 53 | } 54 | 55 | void iset(bool enable) { 56 | } 57 | -------------------------------------------------------------------------------- /abstract-machine/am/src/mips/nemu/start.S: -------------------------------------------------------------------------------- 1 | .section entry, "ax" 2 | .globl _start 3 | .type _start, @function 4 | 5 | _start: 6 | move $fp, $zero 7 | la $sp, _stack_pointer 8 | jal _trm_init 9 | 10 | .fill 0x200 11 | -------------------------------------------------------------------------------- /abstract-machine/am/src/mips/nemu/trap.S: -------------------------------------------------------------------------------- 1 | 2 | #define MAP(c, f) c(f) 3 | 4 | #define REGS(f) \ 5 | f( 1) f( 2) f( 3) f( 4) f( 5) f( 6) f( 7) f( 8) f( 9) \ 6 | f(10) f(11) f(12) f(13) f(14) f(15) f(16) f(17) f(18) f(19) \ 7 | f(20) f(21) f(22) f(23) f(24) f(25) f(28) \ 8 | f(30) f(31) 9 | 10 | #define PUSH(n) sw $n, (n * 4)($sp); 11 | #define POP(n) lw $n, (n * 4)($sp); 12 | 13 | #define CONTEXT_SIZE ((31 + 6) * 4) 14 | #define OFFSET_SP (29 * 4) 15 | #define OFFSET_LO (32 * 4) 16 | #define OFFSET_HI (33 * 4) 17 | #define OFFSET_CAUSE (34 * 4) 18 | #define OFFSET_STATUS (35 * 4) 19 | #define OFFSET_EPC (36 * 4) 20 | 21 | #define CP0_STATUS 12 22 | #define CP0_CAUSE 13 23 | #define CP0_EPC 14 24 | 25 | 26 | .set noat 27 | .globl __am_asm_trap 28 | __am_asm_trap: 29 | move $k1, $sp 30 | addiu $sp, $sp, -CONTEXT_SIZE 31 | 32 | MAP(REGS, PUSH) 33 | 34 | sw $k1, OFFSET_SP($sp) 35 | 36 | mflo $t0 37 | mfhi $t1 38 | mfc0 $t2, $CP0_CAUSE 39 | mfc0 $t3, $CP0_STATUS 40 | mfc0 $t4, $CP0_EPC 41 | sw $t0, OFFSET_LO($sp) 42 | sw $t1, OFFSET_HI($sp) 43 | sw $t2, OFFSET_CAUSE($sp) 44 | sw $t3, OFFSET_STATUS($sp) 45 | sw $t4, OFFSET_EPC($sp) 46 | 47 | # allow nested exception 48 | li $a0, ~0x3 49 | and $t3, $t3, $a0 # clear status.exl and status.ie 50 | mtc0 $t3, $CP0_STATUS 51 | 52 | move $a0, $sp 53 | jal __am_irq_handle 54 | 55 | lw $t0, OFFSET_LO($sp) 56 | lw $t1, OFFSET_HI($sp) 57 | lw $t3, OFFSET_STATUS($sp) 58 | lw $t4, OFFSET_EPC($sp) 59 | 60 | # set status.exl 61 | ori $t3, $t3, 0x2 62 | 63 | mtlo $t0 64 | mthi $t1 65 | mtc0 $t3, $CP0_STATUS 66 | mtc0 $t4, $CP0_EPC 67 | 68 | MAP(REGS, POP) 69 | 70 | addiu $sp, $sp, CONTEXT_SIZE 71 | eret 72 | -------------------------------------------------------------------------------- /abstract-machine/am/src/mips/nemu/vme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define USER_SPACE RANGE(0x40000000, 0x80000000) 5 | 6 | static void* (*pgalloc_usr)(int) = NULL; 7 | static void (*pgfree_usr)(void*) = NULL; 8 | static int vme_enable = 0; 9 | 10 | bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { 11 | pgalloc_usr = pgalloc_f; 12 | pgfree_usr = pgfree_f; 13 | vme_enable = 1; 14 | 15 | return true; 16 | } 17 | 18 | void protect(AddrSpace *as) { 19 | as->ptr = (PTE*)(pgalloc_usr(PGSIZE)); 20 | as->pgsize = PGSIZE; 21 | as->area = USER_SPACE; 22 | } 23 | 24 | void unprotect(AddrSpace *as) { 25 | } 26 | 27 | static PTE *cur_pdir = NULL; 28 | void __am_get_cur_as(Context *c) { 29 | c->pdir = cur_pdir; 30 | } 31 | 32 | void __am_switch(Context *c) { 33 | if (vme_enable && c->pdir != NULL) { 34 | cur_pdir = c->pdir; 35 | } 36 | } 37 | 38 | void map(AddrSpace *as, void *va, void *pa, int prot) { 39 | } 40 | 41 | Context *ucontext(AddrSpace *as, Area kstack, void *entry) { 42 | return NULL; 43 | } 44 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool __am_has_ioe = false; 5 | static bool ioe_init_done = false; 6 | 7 | void __am_timer_init(); 8 | void __am_gpu_init(); 9 | void __am_input_init(); 10 | void __am_audio_init(); 11 | void __am_disk_init(); 12 | void __am_input_config(AM_INPUT_CONFIG_T *); 13 | void __am_timer_config(AM_TIMER_CONFIG_T *); 14 | void __am_timer_rtc(AM_TIMER_RTC_T *); 15 | void __am_timer_uptime(AM_TIMER_UPTIME_T *); 16 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *); 17 | void __am_gpu_config(AM_GPU_CONFIG_T *); 18 | void __am_gpu_status(AM_GPU_STATUS_T *); 19 | void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *); 20 | void __am_audio_config(AM_AUDIO_CONFIG_T *); 21 | void __am_audio_ctrl(AM_AUDIO_CTRL_T *); 22 | void __am_audio_status(AM_AUDIO_STATUS_T *); 23 | void __am_audio_play(AM_AUDIO_PLAY_T *); 24 | void __am_disk_config(AM_DISK_CONFIG_T *cfg); 25 | void __am_disk_status(AM_DISK_STATUS_T *stat); 26 | void __am_disk_blkio(AM_DISK_BLKIO_T *io); 27 | static void __am_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = false; } 28 | static void __am_net_config (AM_NET_CONFIG_T *cfg) { cfg->present = false; } 29 | 30 | typedef void (*handler_t)(void *buf); 31 | static void *lut[128] = { 32 | [AM_TIMER_CONFIG] = __am_timer_config, 33 | [AM_TIMER_RTC ] = __am_timer_rtc, 34 | [AM_TIMER_UPTIME] = __am_timer_uptime, 35 | [AM_INPUT_CONFIG] = __am_input_config, 36 | [AM_INPUT_KEYBRD] = __am_input_keybrd, 37 | [AM_GPU_CONFIG ] = __am_gpu_config, 38 | [AM_GPU_FBDRAW ] = __am_gpu_fbdraw, 39 | [AM_GPU_STATUS ] = __am_gpu_status, 40 | [AM_UART_CONFIG ] = __am_uart_config, 41 | [AM_AUDIO_CONFIG] = __am_audio_config, 42 | [AM_AUDIO_CTRL ] = __am_audio_ctrl, 43 | [AM_AUDIO_STATUS] = __am_audio_status, 44 | [AM_AUDIO_PLAY ] = __am_audio_play, 45 | [AM_DISK_CONFIG ] = __am_disk_config, 46 | [AM_DISK_STATUS ] = __am_disk_status, 47 | [AM_DISK_BLKIO ] = __am_disk_blkio, 48 | [AM_NET_CONFIG ] = __am_net_config, 49 | }; 50 | 51 | bool ioe_init() { 52 | panic_on(cpu_current() != 0, "call ioe_init() in other CPUs"); 53 | panic_on(ioe_init_done, "double-initialization"); 54 | __am_has_ioe = true; 55 | return true; 56 | } 57 | 58 | static void fail(void *buf) { panic("access nonexist register"); } 59 | 60 | void __am_ioe_init() { 61 | for (int i = 0; i < LENGTH(lut); i++) 62 | if (!lut[i]) lut[i] = fail; 63 | __am_timer_init(); 64 | __am_gpu_init(); 65 | __am_input_init(); 66 | __am_audio_init(); 67 | __am_disk_init(); 68 | ioe_init_done = true; 69 | } 70 | 71 | static void do_io(int reg, void *buf) { 72 | if (!ioe_init_done) { 73 | __am_ioe_init(); 74 | } 75 | ((handler_t)lut[reg])(buf); 76 | } 77 | 78 | void ioe_read (int reg, void *buf) { do_io(reg, buf); } 79 | void ioe_write(int reg, void *buf) { do_io(reg, buf); } 80 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/audio.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static int rfd = -1, wfd = -1; 8 | static volatile int count = 0; 9 | 10 | void __am_audio_init() { 11 | int fds[2]; 12 | int ret = pipe2(fds, O_NONBLOCK); 13 | assert(ret == 0); 14 | rfd = fds[0]; 15 | wfd = fds[1]; 16 | } 17 | 18 | static void audio_play(void *userdata, uint8_t *stream, int len) { 19 | int nread = len; 20 | if (count < len) nread = count; 21 | int b = 0; 22 | while (b < nread) { 23 | int n = read(rfd, stream, nread); 24 | if (n > 0) b += n; 25 | } 26 | 27 | count -= nread; 28 | if (len > nread) { 29 | memset(stream + nread, 0, len - nread); 30 | } 31 | } 32 | 33 | static void audio_write(uint8_t *buf, int len) { 34 | int nwrite = 0; 35 | while (nwrite < len) { 36 | int n = write(wfd, buf, len); 37 | if (n == -1) n = 0; 38 | count += n; 39 | nwrite += n; 40 | } 41 | } 42 | 43 | void __am_audio_ctrl(AM_AUDIO_CTRL_T *ctrl) { 44 | SDL_AudioSpec s = {}; 45 | s.freq = ctrl->freq; 46 | s.format = AUDIO_S16SYS; 47 | s.channels = ctrl->channels; 48 | s.samples = ctrl->samples; 49 | s.callback = audio_play; 50 | s.userdata = NULL; 51 | 52 | count = 0; 53 | int ret = SDL_InitSubSystem(SDL_INIT_AUDIO); 54 | if (ret == 0) { 55 | SDL_OpenAudio(&s, NULL); 56 | SDL_PauseAudio(0); 57 | } 58 | } 59 | 60 | void __am_audio_status(AM_AUDIO_STATUS_T *stat) { 61 | stat->count = count; 62 | } 63 | 64 | void __am_audio_play(AM_AUDIO_PLAY_T *ctl) { 65 | int len = ctl->buf.end - ctl->buf.start; 66 | audio_write(ctl->buf.start, len); 67 | } 68 | 69 | void __am_audio_config(AM_AUDIO_CONFIG_T *cfg) { 70 | cfg->present = true; 71 | cfg->bufsize = fcntl(rfd, F_GETPIPE_SZ); 72 | } 73 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/disk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define BLKSZ 512 7 | 8 | static int disk_size = 0; 9 | static FILE *fp = NULL; 10 | 11 | void __am_disk_init() { 12 | const char *diskimg = getenv("diskimg"); 13 | if (diskimg) { 14 | fp = fopen(diskimg, "r+"); 15 | if (fp) { 16 | fseek(fp, 0, SEEK_END); 17 | disk_size = (ftell(fp) + 511) / 512; 18 | rewind(fp); 19 | } 20 | } 21 | } 22 | 23 | void __am_disk_config(AM_DISK_CONFIG_T *cfg) { 24 | cfg->present = (fp != NULL); 25 | cfg->blksz = BLKSZ; 26 | cfg->blkcnt = disk_size; 27 | } 28 | 29 | void __am_disk_status(AM_DISK_STATUS_T *stat) { 30 | stat->ready = 1; 31 | } 32 | 33 | void __am_disk_blkio(AM_DISK_BLKIO_T *io) { 34 | if (fp) { 35 | fseek(fp, io->blkno * BLKSZ, SEEK_SET); 36 | int ret; 37 | if (io->write) ret = fwrite(io->buf, io->blkcnt * BLKSZ, 1, fp); 38 | else ret = fread(io->buf, io->blkcnt * BLKSZ, 1, fp); 39 | assert(ret == 1); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/gpu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#define MODE_800x600 6 | #ifdef MODE_800x600 7 | # define W 800 8 | # define H 600 9 | #else 10 | # define W 400 11 | # define H 300 12 | #endif 13 | 14 | #define FPS 60 15 | 16 | #define RMASK 0x00ff0000 17 | #define GMASK 0x0000ff00 18 | #define BMASK 0x000000ff 19 | #define AMASK 0x00000000 20 | 21 | static SDL_Window *window = NULL; 22 | static SDL_Surface *surface = NULL; 23 | 24 | static Uint32 texture_sync(Uint32 interval, void *param) { 25 | SDL_BlitScaled(surface, NULL, SDL_GetWindowSurface(window), NULL); 26 | SDL_UpdateWindowSurface(window); 27 | return interval; 28 | } 29 | 30 | void __am_gpu_init() { 31 | SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); 32 | window = SDL_CreateWindow("Native Application", 33 | SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 34 | #ifdef MODE_800x600 35 | W, H, 36 | #else 37 | W * 2, H * 2, 38 | #endif 39 | SDL_WINDOW_SHOWN); 40 | surface = SDL_CreateRGBSurface(SDL_SWSURFACE, W, H, 32, 41 | RMASK, GMASK, BMASK, AMASK); 42 | SDL_AddTimer(1000 / FPS, texture_sync, NULL); 43 | } 44 | 45 | void __am_gpu_config(AM_GPU_CONFIG_T *cfg) { 46 | *cfg = (AM_GPU_CONFIG_T) { 47 | .present = true, .has_accel = false, 48 | .width = W, .height = H, 49 | .vmemsz = 0 50 | }; 51 | } 52 | 53 | void __am_gpu_status(AM_GPU_STATUS_T *stat) { 54 | stat->ready = true; 55 | } 56 | 57 | void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *ctl) { 58 | int x = ctl->x, y = ctl->y, w = ctl->w, h = ctl->h; 59 | if (w == 0 || h == 0) return; 60 | feclearexcept(-1); 61 | SDL_Surface *s = SDL_CreateRGBSurfaceFrom(ctl->pixels, w, h, 32, w * sizeof(uint32_t), 62 | RMASK, GMASK, BMASK, AMASK); 63 | SDL_Rect rect = { .x = x, .y = y }; 64 | SDL_BlitSurface(s, NULL, surface, &rect); 65 | SDL_FreeSurface(s); 66 | } 67 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define KEYDOWN_MASK 0x8000 5 | 6 | #define KEY_QUEUE_LEN 1024 7 | static int key_queue[KEY_QUEUE_LEN] = {}; 8 | static int key_f = 0, key_r = 0; 9 | static SDL_mutex *key_queue_lock = NULL; 10 | 11 | #define XX(k) [SDL_SCANCODE_##k] = AM_KEY_##k, 12 | static int keymap[256] = { 13 | AM_KEYS(XX) 14 | }; 15 | 16 | static int event_thread(void *args) { 17 | SDL_Event event; 18 | while (1) { 19 | SDL_WaitEvent(&event); 20 | switch (event.type) { 21 | case SDL_QUIT: halt(0); 22 | case SDL_KEYDOWN: 23 | case SDL_KEYUP: { 24 | SDL_Keysym k = event.key.keysym; 25 | int keydown = event.key.type == SDL_KEYDOWN; 26 | int scancode = k.scancode; 27 | if (keymap[scancode] != 0) { 28 | int am_code = keymap[scancode] | (keydown ? KEYDOWN_MASK : 0); 29 | SDL_LockMutex(key_queue_lock); 30 | key_queue[key_r] = am_code; 31 | key_r = (key_r + 1) % KEY_QUEUE_LEN; 32 | SDL_UnlockMutex(key_queue_lock); 33 | void __am_send_kbd_intr(); 34 | __am_send_kbd_intr(); 35 | } 36 | break; 37 | } 38 | } 39 | } 40 | } 41 | 42 | void __am_input_init() { 43 | key_queue_lock = SDL_CreateMutex(); 44 | SDL_CreateThread(event_thread, "event thread", NULL); 45 | } 46 | 47 | void __am_input_config(AM_INPUT_CONFIG_T *cfg) { 48 | cfg->present = true; 49 | } 50 | 51 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) { 52 | int k = AM_KEY_NONE; 53 | 54 | SDL_LockMutex(key_queue_lock); 55 | if (key_f != key_r) { 56 | k = key_queue[key_f]; 57 | key_f = (key_f + 1) % KEY_QUEUE_LEN; 58 | } 59 | SDL_UnlockMutex(key_queue_lock); 60 | 61 | kbd->keydown = (k & KEYDOWN_MASK ? true : false); 62 | kbd->keycode = k & ~KEYDOWN_MASK; 63 | } 64 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static struct timeval boot_time = {}; 6 | 7 | void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { 8 | cfg->present = cfg->has_rtc = true; 9 | } 10 | 11 | void __am_timer_rtc(AM_TIMER_RTC_T *rtc) { 12 | time_t t = time(NULL); 13 | struct tm *tm = localtime(&t); 14 | rtc->second = tm->tm_sec; 15 | rtc->minute = tm->tm_min; 16 | rtc->hour = tm->tm_hour; 17 | rtc->day = tm->tm_mday; 18 | rtc->month = tm->tm_mon + 1; 19 | rtc->year = tm->tm_year + 1900; 20 | } 21 | 22 | void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { 23 | struct timeval now; 24 | gettimeofday(&now, NULL); 25 | long seconds = now.tv_sec - boot_time.tv_sec; 26 | long useconds = now.tv_usec - boot_time.tv_usec; 27 | uptime->us = seconds * 1000000 + (useconds + 500); 28 | } 29 | 30 | void __am_timer_init() { 31 | gettimeofday(&boot_time, NULL); 32 | } 33 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/mpe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "platform.h" 3 | 4 | int __am_mpe_init = 0; 5 | extern bool __am_has_ioe; 6 | void __am_ioe_init(); 7 | 8 | bool mpe_init(void (*entry)()) { 9 | __am_mpe_init = 1; 10 | 11 | int sync_pipe[2]; 12 | assert(0 == pipe(sync_pipe)); 13 | 14 | for (int i = 1; i < cpu_count(); i++) { 15 | if (fork() == 0) { 16 | char ch; 17 | assert(read(sync_pipe[0], &ch, 1) == 1); 18 | assert(ch == '+'); 19 | close(sync_pipe[0]); close(sync_pipe[1]); 20 | 21 | thiscpu->cpuid = i; 22 | __am_init_timer_irq(); 23 | entry(); 24 | } 25 | } 26 | 27 | if (__am_has_ioe) { 28 | __am_ioe_init(); 29 | } 30 | 31 | for (int i = 1; i < cpu_count(); i++) { 32 | assert(write(sync_pipe[1], "+", 1) == 1); 33 | } 34 | close(sync_pipe[0]); close(sync_pipe[1]); 35 | 36 | entry(); 37 | panic("MP entry should not return\n"); 38 | } 39 | 40 | int cpu_count() { 41 | extern int __am_ncpu; 42 | return __am_ncpu; 43 | } 44 | 45 | int cpu_current() { 46 | return thiscpu->cpuid; 47 | } 48 | 49 | int atomic_xchg(int *addr, int newval) { 50 | return atomic_exchange((int *)addr, newval); 51 | } 52 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef __PLATFORM_H__ 2 | #define __PLATFORM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void __am_get_example_uc(Context *r); 11 | void __am_get_intr_sigmask(sigset_t *s); 12 | int __am_is_sigmask_sti(sigset_t *s); 13 | void __am_init_timer_irq(); 14 | void __am_pmem_map(void *va, void *pa, int prot); 15 | void __am_pmem_unmap(void *va); 16 | 17 | // per-cpu structure 18 | typedef struct { 19 | void *vm_head; 20 | uintptr_t ksp; 21 | int cpuid; 22 | Event ev; // similar to cause register in mips/riscv 23 | uint8_t sigstack[32768]; 24 | } __am_cpu_t; 25 | extern __am_cpu_t *__am_cpu_struct; 26 | #define thiscpu __am_cpu_struct 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/trap.S: -------------------------------------------------------------------------------- 1 | .global __am_kcontext_start 2 | __am_kcontext_start: 3 | // rdi = arg, rsi = entry 4 | 5 | // (rsp + 8) should be multiple of 16 when 6 | // control is transfered to the function entry point. 7 | // See amd64 ABI manual for more details 8 | andq $0xfffffffffffffff0, %rsp 9 | call *%rsi 10 | call __am_panic_on_return 11 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/trm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void __am_platform_dummy(); 6 | void __am_exit_platform(int code); 7 | 8 | void trm_init() { 9 | __am_platform_dummy(); 10 | } 11 | 12 | void putch(char ch) { 13 | putchar(ch); 14 | } 15 | 16 | void halt(int code) { 17 | const char *fmt = "Exit code = 40h\n"; 18 | for (const char *p = fmt; *p; p++) { 19 | char ch = *p; 20 | if (ch == '0' || ch == '4') { 21 | ch = "0123456789abcdef"[(code >> (ch - '0')) & 0xf]; 22 | } 23 | putch(ch); 24 | } 25 | __am_exit_platform(code); 26 | putstr("Should not reach here!\n"); 27 | while (1); 28 | } 29 | 30 | Area heap = {}; 31 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/dummy/cte.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool cte_init(Context*(*handler)(Event, Context*)) { 4 | return false; 5 | } 6 | 7 | Context *kcontext(Area kstack, void (*entry)(void *), void *arg) { 8 | return NULL; 9 | } 10 | 11 | void yield() { 12 | } 13 | 14 | bool ienabled() { 15 | return false; 16 | } 17 | 18 | void iset(bool enable) { 19 | } 20 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/dummy/ioe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static void fail(void *buf) { panic("access nonexist register"); } 5 | 6 | bool ioe_init() { 7 | return false; 8 | } 9 | 10 | void ioe_read (int reg, void *buf) { fail(buf); } 11 | void ioe_write(int reg, void *buf) { fail(buf); } 12 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/dummy/mpe.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool mpe_init(void (*entry)()) { 4 | return false; 5 | } 6 | 7 | int cpu_count() { 8 | return 1; 9 | } 10 | 11 | int cpu_current() { 12 | return 0; 13 | } 14 | 15 | int atomic_xchg(int *addr, int newval) { 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/dummy/trm.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Area heap = RANGE(NULL, NULL); 4 | 5 | void putch(char ch) { 6 | } 7 | 8 | void halt(int code) { 9 | while (1); 10 | } 11 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/dummy/vme.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { 4 | return false; 5 | } 6 | 7 | void protect(AddrSpace *as) { 8 | } 9 | 10 | void unprotect(AddrSpace *as) { 11 | } 12 | 13 | void map(AddrSpace *as, void *va, void *pa, int prot) { 14 | } 15 | 16 | Context *ucontext(AddrSpace *as, Area kstack, void *entry) { 17 | return NULL; 18 | } 19 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/include/nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef NEMU_H__ 2 | #define NEMU_H__ 3 | 4 | #include 5 | 6 | #include ISA_H // the macro `ISA_H` is defined in CFLAGS 7 | // it will be expanded as "x86/x86.h", "mips/mips32.h", ... 8 | 9 | #if defined(__ISA_X86__) 10 | # define nemu_trap(code) asm volatile ("int3" : :"a"(code)) 11 | #elif defined(__ISA_MIPS32__) 12 | # define nemu_trap(code) asm volatile ("move $v0, %0; sdbbp" : :"r"(code)) 13 | #elif defined(__ISA_RISCV32__) || defined(__ISA_RISCV64__) 14 | # define nemu_trap(code) asm volatile("mv a0, %0; ebreak" : :"r"(code)) 15 | #elif 16 | # error unsupported ISA __ISA__ 17 | #endif 18 | 19 | #if defined(__ARCH_X86_NEMU) 20 | # define DEVICE_BASE 0x0 21 | #else 22 | # define DEVICE_BASE 0xa0000000 23 | #endif 24 | 25 | #define MMIO_BASE 0xa0000000 26 | 27 | #define SERIAL_PORT (DEVICE_BASE + 0x00003f8) 28 | #define KBD_ADDR (DEVICE_BASE + 0x0000060) 29 | #define RTC_ADDR (DEVICE_BASE + 0x0000048) 30 | #define VGACTL_ADDR (DEVICE_BASE + 0x0000100) 31 | #define AUDIO_ADDR (DEVICE_BASE + 0x0000200) 32 | #define DISK_ADDR (DEVICE_BASE + 0x0000300) 33 | #define FB_ADDR (MMIO_BASE + 0x1000000) 34 | #define AUDIO_SBUF_ADDR (MMIO_BASE + 0x1200000) 35 | 36 | extern char _pmem_start; 37 | #define PMEM_SIZE (128 * 1024 * 1024) 38 | #define PMEM_END ((uintptr_t)&_pmem_start + PMEM_SIZE) 39 | #define NEMU_PADDR_SPACE \ 40 | RANGE(&_pmem_start, PMEM_END), \ 41 | RANGE(FB_ADDR, FB_ADDR + 0x200000), \ 42 | RANGE(MMIO_BASE, MMIO_BASE + 0x1000) /* serial, rtc, screen, keyboard */ 43 | 44 | typedef uintptr_t PTE; 45 | 46 | #define PGSIZE 4096 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/ioe/audio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define AUDIO_FREQ_ADDR (AUDIO_ADDR + 0x00) 5 | #define AUDIO_CHANNELS_ADDR (AUDIO_ADDR + 0x04) 6 | #define AUDIO_SAMPLES_ADDR (AUDIO_ADDR + 0x08) 7 | #define AUDIO_SBUF_SIZE_ADDR (AUDIO_ADDR + 0x0c) 8 | #define AUDIO_INIT_ADDR (AUDIO_ADDR + 0x10) 9 | #define AUDIO_COUNT_ADDR (AUDIO_ADDR + 0x14) 10 | 11 | void __am_audio_init() { 12 | } 13 | 14 | void __am_audio_config(AM_AUDIO_CONFIG_T *cfg) { 15 | cfg->present = false; 16 | } 17 | 18 | void __am_audio_ctrl(AM_AUDIO_CTRL_T *ctrl) { 19 | } 20 | 21 | void __am_audio_status(AM_AUDIO_STATUS_T *stat) { 22 | stat->count = 0; 23 | } 24 | 25 | void __am_audio_play(AM_AUDIO_PLAY_T *ctl) { 26 | } 27 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/ioe/disk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void __am_disk_config(AM_DISK_CONFIG_T *cfg) { 5 | cfg->present = false; 6 | } 7 | 8 | void __am_disk_status(AM_DISK_STATUS_T *stat) { 9 | } 10 | 11 | void __am_disk_blkio(AM_DISK_BLKIO_T *io) { 12 | } 13 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/ioe/gpu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SYNC_ADDR (VGACTL_ADDR + 4) 5 | 6 | void __am_gpu_init() { 7 | } 8 | 9 | void __am_gpu_config(AM_GPU_CONFIG_T *cfg) { 10 | *cfg = (AM_GPU_CONFIG_T) { 11 | .present = true, .has_accel = false, 12 | .width = 0, .height = 0, 13 | .vmemsz = 0 14 | }; 15 | } 16 | 17 | void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *ctl) { 18 | if (ctl->sync) { 19 | outl(SYNC_ADDR, 1); 20 | } 21 | } 22 | 23 | void __am_gpu_status(AM_GPU_STATUS_T *status) { 24 | status->ready = true; 25 | } 26 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/ioe/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define KEYDOWN_MASK 0x8000 5 | 6 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) { 7 | kbd->keydown = 0; 8 | kbd->keycode = AM_KEY_NONE; 9 | } 10 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/ioe/ioe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void __am_timer_init(); 5 | void __am_gpu_init(); 6 | void __am_audio_init(); 7 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *); 8 | void __am_timer_rtc(AM_TIMER_RTC_T *); 9 | void __am_timer_uptime(AM_TIMER_UPTIME_T *); 10 | void __am_gpu_config(AM_GPU_CONFIG_T *); 11 | void __am_gpu_status(AM_GPU_STATUS_T *); 12 | void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *); 13 | void __am_audio_config(AM_AUDIO_CONFIG_T *); 14 | void __am_audio_ctrl(AM_AUDIO_CTRL_T *); 15 | void __am_audio_status(AM_AUDIO_STATUS_T *); 16 | void __am_audio_play(AM_AUDIO_PLAY_T *); 17 | void __am_disk_config(AM_DISK_CONFIG_T *cfg); 18 | void __am_disk_status(AM_DISK_STATUS_T *stat); 19 | void __am_disk_blkio(AM_DISK_BLKIO_T *io); 20 | 21 | static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { cfg->present = true; cfg->has_rtc = true; } 22 | static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; } 23 | static void __am_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = false; } 24 | static void __am_net_config (AM_NET_CONFIG_T *cfg) { cfg->present = false; } 25 | 26 | typedef void (*handler_t)(void *buf); 27 | static void *lut[128] = { 28 | [AM_TIMER_CONFIG] = __am_timer_config, 29 | [AM_TIMER_RTC ] = __am_timer_rtc, 30 | [AM_TIMER_UPTIME] = __am_timer_uptime, 31 | [AM_INPUT_CONFIG] = __am_input_config, 32 | [AM_INPUT_KEYBRD] = __am_input_keybrd, 33 | [AM_GPU_CONFIG ] = __am_gpu_config, 34 | [AM_GPU_FBDRAW ] = __am_gpu_fbdraw, 35 | [AM_GPU_STATUS ] = __am_gpu_status, 36 | [AM_UART_CONFIG ] = __am_uart_config, 37 | [AM_AUDIO_CONFIG] = __am_audio_config, 38 | [AM_AUDIO_CTRL ] = __am_audio_ctrl, 39 | [AM_AUDIO_STATUS] = __am_audio_status, 40 | [AM_AUDIO_PLAY ] = __am_audio_play, 41 | [AM_DISK_CONFIG ] = __am_disk_config, 42 | [AM_DISK_STATUS ] = __am_disk_status, 43 | [AM_DISK_BLKIO ] = __am_disk_blkio, 44 | [AM_NET_CONFIG ] = __am_net_config, 45 | }; 46 | 47 | static void fail(void *buf) { panic("access nonexist register"); } 48 | 49 | bool ioe_init() { 50 | for (int i = 0; i < LENGTH(lut); i++) 51 | if (!lut[i]) lut[i] = fail; 52 | __am_gpu_init(); 53 | __am_timer_init(); 54 | __am_audio_init(); 55 | return true; 56 | } 57 | 58 | void ioe_read (int reg, void *buf) { ((handler_t)lut[reg])(buf); } 59 | void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); } 60 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/ioe/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void __am_timer_init() { 5 | } 6 | 7 | void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { 8 | uptime->us = 0; 9 | } 10 | 11 | void __am_timer_rtc(AM_TIMER_RTC_T *rtc) { 12 | rtc->second = 0; 13 | rtc->minute = 0; 14 | rtc->hour = 0; 15 | rtc->day = 0; 16 | rtc->month = 0; 17 | rtc->year = 1900; 18 | } 19 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/mpe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool mpe_init(void (*entry)()) { 6 | entry(); 7 | panic("MPE entry returns"); 8 | } 9 | 10 | int cpu_count() { 11 | return 1; 12 | } 13 | 14 | int cpu_current() { 15 | return 0; 16 | } 17 | 18 | int atomic_xchg(int *addr, int newval) { 19 | return atomic_exchange(addr, newval); 20 | } 21 | -------------------------------------------------------------------------------- /abstract-machine/am/src/platform/nemu/trm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern char _heap_start; 5 | int main(const char *args); 6 | 7 | Area heap = RANGE(&_heap_start, PMEM_END); 8 | #ifndef MAINARGS 9 | #define MAINARGS "" 10 | #endif 11 | static const char mainargs[] = MAINARGS; 12 | 13 | void putch(char ch) { 14 | outb(SERIAL_PORT, ch); 15 | } 16 | 17 | void halt(int code) { 18 | nemu_trap(code); 19 | 20 | // should not reach here 21 | while (1); 22 | } 23 | 24 | void _trm_init() { 25 | int ret = main(mainargs); 26 | halt(ret); 27 | } 28 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/nemu/cte.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static Context* (*user_handler)(Event, Context*) = NULL; 6 | 7 | Context* __am_irq_handle(Context *c) { 8 | if (user_handler) { 9 | Event ev = {0}; 10 | switch (c->mcause) { 11 | default: ev.event = EVENT_ERROR; break; 12 | } 13 | 14 | c = user_handler(ev, c); 15 | assert(c != NULL); 16 | } 17 | 18 | return c; 19 | } 20 | 21 | extern void __am_asm_trap(void); 22 | 23 | bool cte_init(Context*(*handler)(Event, Context*)) { 24 | // initialize exception entry 25 | asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap)); 26 | 27 | // register event handler 28 | user_handler = handler; 29 | 30 | return true; 31 | } 32 | 33 | Context *kcontext(Area kstack, void (*entry)(void *), void *arg) { 34 | return NULL; 35 | } 36 | 37 | void yield() { 38 | asm volatile("li a7, -1; ecall"); 39 | } 40 | 41 | bool ienabled() { 42 | return false; 43 | } 44 | 45 | void iset(bool enable) { 46 | } 47 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/nemu/start.S: -------------------------------------------------------------------------------- 1 | .section entry, "ax" 2 | .globl _start 3 | .type _start, @function 4 | 5 | _start: 6 | mv s0, zero 7 | la sp, _stack_pointer 8 | jal _trm_init 9 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/nemu/trap.S: -------------------------------------------------------------------------------- 1 | #define concat_temp(x, y) x ## y 2 | #define concat(x, y) concat_temp(x, y) 3 | #define MAP(c, f) c(f) 4 | 5 | #if __riscv_xlen == 32 6 | #define LOAD lw 7 | #define STORE sw 8 | #define XLEN 4 9 | #else 10 | #define LOAD ld 11 | #define STORE sd 12 | #define XLEN 8 13 | #endif 14 | 15 | #define REGS(f) \ 16 | f( 1) f( 3) f( 4) f( 5) f( 6) f( 7) f( 8) f( 9) \ 17 | f(10) f(11) f(12) f(13) f(14) f(15) f(16) f(17) f(18) f(19) \ 18 | f(20) f(21) f(22) f(23) f(24) f(25) f(26) f(27) f(28) f(29) \ 19 | f(30) f(31) 20 | 21 | #define PUSH(n) STORE concat(x, n), (n * XLEN)(sp); 22 | #define POP(n) LOAD concat(x, n), (n * XLEN)(sp); 23 | 24 | #define CONTEXT_SIZE ((32 + 3 + 1) * XLEN) 25 | #define OFFSET_SP ( 2 * XLEN) 26 | #define OFFSET_CAUSE (32 * XLEN) 27 | #define OFFSET_STATUS (33 * XLEN) 28 | #define OFFSET_EPC (34 * XLEN) 29 | 30 | .align 3 31 | .globl __am_asm_trap 32 | __am_asm_trap: 33 | addi sp, sp, -CONTEXT_SIZE 34 | 35 | MAP(REGS, PUSH) 36 | 37 | csrr t0, mcause 38 | csrr t1, mstatus 39 | csrr t2, mepc 40 | 41 | STORE t0, OFFSET_CAUSE(sp) 42 | STORE t1, OFFSET_STATUS(sp) 43 | STORE t2, OFFSET_EPC(sp) 44 | 45 | # set mstatus.MPRV to pass difftest 46 | li a0, (1 << 17) 47 | or t1, t1, a0 48 | csrw mstatus, t1 49 | 50 | mv a0, sp 51 | jal __am_irq_handle 52 | 53 | LOAD t1, OFFSET_STATUS(sp) 54 | LOAD t2, OFFSET_EPC(sp) 55 | csrw mstatus, t1 56 | csrw mepc, t2 57 | 58 | MAP(REGS, POP) 59 | 60 | addi sp, sp, CONTEXT_SIZE 61 | mret 62 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/nemu/vme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static AddrSpace kas = {}; 6 | static void* (*pgalloc_usr)(int) = NULL; 7 | static void (*pgfree_usr)(void*) = NULL; 8 | static int vme_enable = 0; 9 | 10 | static Area segments[] = { // Kernel memory mappings 11 | NEMU_PADDR_SPACE 12 | }; 13 | 14 | #define USER_SPACE RANGE(0x40000000, 0x80000000) 15 | 16 | static inline void set_satp(void *pdir) { 17 | uintptr_t mode = 1ul << (__riscv_xlen - 1); 18 | asm volatile("csrw satp, %0" : : "r"(mode | ((uintptr_t)pdir >> 12))); 19 | } 20 | 21 | static inline uintptr_t get_satp() { 22 | uintptr_t satp; 23 | asm volatile("csrr %0, satp" : "=r"(satp)); 24 | return satp << 12; 25 | } 26 | 27 | bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { 28 | pgalloc_usr = pgalloc_f; 29 | pgfree_usr = pgfree_f; 30 | 31 | kas.ptr = pgalloc_f(PGSIZE); 32 | 33 | int i; 34 | for (i = 0; i < LENGTH(segments); i ++) { 35 | void *va = segments[i].start; 36 | for (; va < segments[i].end; va += PGSIZE) { 37 | map(&kas, va, va, 0); 38 | } 39 | } 40 | 41 | set_satp(kas.ptr); 42 | vme_enable = 1; 43 | 44 | return true; 45 | } 46 | 47 | void protect(AddrSpace *as) { 48 | PTE *updir = (PTE*)(pgalloc_usr(PGSIZE)); 49 | as->ptr = updir; 50 | as->area = USER_SPACE; 51 | as->pgsize = PGSIZE; 52 | // map kernel space 53 | memcpy(updir, kas.ptr, PGSIZE); 54 | } 55 | 56 | void unprotect(AddrSpace *as) { 57 | } 58 | 59 | void __am_get_cur_as(Context *c) { 60 | c->pdir = (vme_enable ? (void *)get_satp() : NULL); 61 | } 62 | 63 | void __am_switch(Context *c) { 64 | if (vme_enable && c->pdir != NULL) { 65 | set_satp(c->pdir); 66 | } 67 | } 68 | 69 | void map(AddrSpace *as, void *va, void *pa, int prot) { 70 | } 71 | 72 | Context *ucontext(AddrSpace *as, Area kstack, void *entry) { 73 | return NULL; 74 | } 75 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/cte.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static Context* (*user_handler)(Event, Context*) = NULL; 5 | 6 | Context* __am_irq_handle(Context *c) { 7 | if (user_handler) { 8 | Event ev = {0}; 9 | switch (c->mcause) { 10 | default: ev.event = EVENT_ERROR; break; 11 | } 12 | 13 | c = user_handler(ev, c); 14 | assert(c != NULL); 15 | } 16 | 17 | return c; 18 | } 19 | 20 | extern void __am_asm_trap(void); 21 | 22 | bool cte_init(Context*(*handler)(Event, Context*)) { 23 | // initialize exception entry 24 | asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap)); 25 | 26 | // register event handler 27 | user_handler = handler; 28 | 29 | return true; 30 | } 31 | 32 | Context *kcontext(Area kstack, void (*entry)(void *), void *arg) { 33 | return NULL; 34 | } 35 | 36 | void yield() { 37 | asm volatile("li a7, -1; ecall"); 38 | } 39 | 40 | bool ienabled() { 41 | return false; 42 | } 43 | 44 | void iset(bool enable) { 45 | } 46 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) { 4 | kbd->keydown = 0; 5 | kbd->keycode = AM_KEY_NONE; 6 | } 7 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/ioe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void __am_timer_init(); 5 | 6 | void __am_timer_rtc(AM_TIMER_RTC_T *); 7 | void __am_timer_uptime(AM_TIMER_UPTIME_T *); 8 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *); 9 | void __am_timer_rtc(AM_TIMER_RTC_T *); 10 | 11 | static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { cfg->present = true; cfg->has_rtc = true; } 12 | static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; } 13 | 14 | typedef void (*handler_t)(void *buf); 15 | static void *lut[128] = { 16 | [AM_TIMER_CONFIG] = __am_timer_config, 17 | [AM_TIMER_RTC ] = __am_timer_rtc, 18 | [AM_TIMER_UPTIME] = __am_timer_uptime, 19 | [AM_INPUT_CONFIG] = __am_input_config, 20 | [AM_INPUT_KEYBRD] = __am_input_keybrd, 21 | }; 22 | 23 | static void fail(void *buf) { panic("access nonexist register"); } 24 | 25 | bool ioe_init() { 26 | for (int i = 0; i < LENGTH(lut); i++) 27 | if (!lut[i]) lut[i] = fail; 28 | __am_timer_init(); 29 | return true; 30 | } 31 | 32 | void ioe_read (int reg, void *buf) { ((handler_t)lut[reg])(buf); } 33 | void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); } 34 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/mpe.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool mpe_init(void (*entry)()) { 4 | return false; 5 | } 6 | 7 | int cpu_count() { 8 | return 1; 9 | } 10 | 11 | int cpu_current() { 12 | return 0; 13 | } 14 | 15 | int atomic_xchg(int *addr, int newval) { 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/start.S: -------------------------------------------------------------------------------- 1 | .section entry, "ax" 2 | .globl _start 3 | .type _start, @function 4 | 5 | _start: 6 | mv s0, zero 7 | la sp, _stack_pointer 8 | jal _trm_init 9 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void __am_timer_init() { 4 | } 5 | 6 | void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { 7 | uptime->us = 0; 8 | } 9 | 10 | void __am_timer_rtc(AM_TIMER_RTC_T *rtc) { 11 | rtc->second = 0; 12 | rtc->minute = 0; 13 | rtc->hour = 0; 14 | rtc->day = 0; 15 | rtc->month = 0; 16 | rtc->year = 1900; 17 | } 18 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/trap.S: -------------------------------------------------------------------------------- 1 | 2 | #define concat_temp(x, y) x ## y 3 | #define concat(x, y) concat_temp(x, y) 4 | #define MAP(c, f) c(f) 5 | 6 | #define REGS(f) \ 7 | f( 1) f( 3) f( 4) f( 5) f( 6) f( 7) f( 8) f( 9) \ 8 | f(10) f(11) f(12) f(13) f(14) f(15) f(16) f(17) f(18) f(19) \ 9 | f(20) f(21) f(22) f(23) f(24) f(25) f(26) f(27) f(28) f(29) \ 10 | f(30) f(31) 11 | 12 | #define PUSH(n) sd concat(x, n), (n * 8)(sp); 13 | #define POP(n) ld concat(x, n), (n * 8)(sp); 14 | 15 | #define CONTEXT_SIZE ((32 + 3) * 8) 16 | #define OFFSET_SP ( 2 * 8) 17 | #define OFFSET_CAUSE (32 * 8) 18 | #define OFFSET_STATUS (33 * 8) 19 | #define OFFSET_EPC (34 * 8) 20 | 21 | .globl __am_asm_trap 22 | __am_asm_trap: 23 | addi sp, sp, -CONTEXT_SIZE 24 | 25 | MAP(REGS, PUSH) 26 | 27 | mv t0, sp 28 | addi t0, t0, CONTEXT_SIZE 29 | sd t0, OFFSET_SP(sp) 30 | 31 | csrr t0, mcause 32 | csrr t1, mstatus 33 | csrr t2, mepc 34 | 35 | sd t0, OFFSET_CAUSE(sp) 36 | sd t1, OFFSET_STATUS(sp) 37 | sd t2, OFFSET_EPC(sp) 38 | 39 | mv a0, sp 40 | jal __am_irq_handle 41 | 42 | ld t1, OFFSET_STATUS(sp) 43 | ld t2, OFFSET_EPC(sp) 44 | csrw mstatus, t1 45 | csrw mepc, t2 46 | 47 | MAP(REGS, POP) 48 | 49 | addi sp, sp, CONTEXT_SIZE 50 | 51 | mret 52 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/trm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern char _heap_start; 5 | int main(const char *args); 6 | 7 | extern char _pmem_start; 8 | #define PMEM_SIZE (128 * 1024 * 1024) 9 | #define PMEM_END ((uintptr_t)&_pmem_start + PMEM_SIZE) 10 | 11 | Area heap = RANGE(&_heap_start, PMEM_END); 12 | #ifndef MAINARGS 13 | #define MAINARGS "" 14 | #endif 15 | static const char mainargs[] = MAINARGS; 16 | 17 | void putch(char ch) { 18 | } 19 | 20 | void halt(int code) { 21 | while (1); 22 | } 23 | 24 | void _trm_init() { 25 | int ret = main(mainargs); 26 | halt(ret); 27 | } 28 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/npc/vme.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { 4 | return false; 5 | } 6 | 7 | void protect(AddrSpace *as) { 8 | } 9 | 10 | void unprotect(AddrSpace *as) { 11 | } 12 | 13 | void map(AddrSpace *as, void *va, void *pa, int prot) { 14 | } 15 | 16 | Context *ucontext(AddrSpace *as, Area kstack, void *entry) { 17 | return NULL; 18 | } 19 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/riscv.h: -------------------------------------------------------------------------------- 1 | #ifndef RISCV_H__ 2 | #define RISCV_H__ 3 | 4 | #include 5 | 6 | static inline uint8_t inb(uintptr_t addr) { return *(volatile uint8_t *)addr; } 7 | static inline uint16_t inw(uintptr_t addr) { return *(volatile uint16_t *)addr; } 8 | static inline uint32_t inl(uintptr_t addr) { return *(volatile uint32_t *)addr; } 9 | 10 | static inline void outb(uintptr_t addr, uint8_t data) { *(volatile uint8_t *)addr = data; } 11 | static inline void outw(uintptr_t addr, uint16_t data) { *(volatile uint16_t *)addr = data; } 12 | static inline void outl(uintptr_t addr, uint32_t data) { *(volatile uint32_t *)addr = data; } 13 | 14 | #define PTE_V 0x01 15 | #define PTE_R 0x02 16 | #define PTE_W 0x04 17 | #define PTE_X 0x08 18 | #define PTE_U 0x10 19 | #define PTE_A 0x40 20 | #define PTE_D 0x80 21 | 22 | enum { MODE_U, MODE_S, MODE_M = 3 }; 23 | #define MSTATUS_MXR (1 << 19) 24 | #define MSTATUS_SUM (1 << 18) 25 | 26 | #if __riscv_xlen == 64 27 | #define MSTATUS_SXL (2ull << 34) 28 | #define MSTATUS_UXL (2ull << 32) 29 | #else 30 | #define MSTATUS_SXL 0 31 | #define MSTATUS_UXL 0 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/spike/atomic.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef _RISCV_ATOMIC_H 4 | #define _RISCV_ATOMIC_H 5 | 6 | //#include "config.h" 7 | //#include "encoding.h" 8 | 9 | // Currently, interrupts are always disabled in M-mode. 10 | #define disable_irqsave() (0) 11 | #define enable_irqrestore(flags) ((void) (flags)) 12 | 13 | typedef struct { int lock; } spinlock_t; 14 | #define SPINLOCK_INIT {0} 15 | 16 | #define mb() asm volatile ("fence" ::: "memory") 17 | #define atomic_set(ptr, val) (*(volatile typeof(*(ptr)) *)(ptr) = val) 18 | #define atomic_read(ptr) (*(volatile typeof(*(ptr)) *)(ptr)) 19 | 20 | #ifdef __riscv_atomic 21 | # define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc) 22 | # define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc) 23 | # define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp) 24 | # define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp) 25 | #else 26 | # define atomic_binop(ptr, inc, op) ({ \ 27 | long flags = disable_irqsave(); \ 28 | typeof(*(ptr)) res = atomic_read(ptr); \ 29 | atomic_set(ptr, op); \ 30 | enable_irqrestore(flags); \ 31 | res; }) 32 | # define atomic_add(ptr, inc) atomic_binop(ptr, inc, res + (inc)) 33 | # define atomic_or(ptr, inc) atomic_binop(ptr, inc, res | (inc)) 34 | # define atomic_swap(ptr, inc) atomic_binop(ptr, inc, (inc)) 35 | # define atomic_cas(ptr, cmp, swp) ({ \ 36 | long flags = disable_irqsave(); \ 37 | typeof(*(ptr)) res = *(volatile typeof(*(ptr)) *)(ptr); \ 38 | if (res == (cmp)) *(volatile typeof(ptr))(ptr) = (swp); \ 39 | enable_irqrestore(flags); \ 40 | res; }) 41 | #endif 42 | 43 | static inline int spinlock_trylock(spinlock_t* lock) 44 | { 45 | int res = atomic_swap(&lock->lock, -1); 46 | mb(); 47 | return res; 48 | } 49 | 50 | static inline void spinlock_lock(spinlock_t* lock) 51 | { 52 | do 53 | { 54 | while (atomic_read(&lock->lock)) 55 | ; 56 | } while (spinlock_trylock(lock)); 57 | } 58 | 59 | static inline void spinlock_unlock(spinlock_t* lock) 60 | { 61 | mb(); 62 | atomic_set(&lock->lock,0); 63 | } 64 | 65 | static inline long spinlock_lock_irqsave(spinlock_t* lock) 66 | { 67 | long flags = disable_irqsave(); 68 | spinlock_lock(lock); 69 | return flags; 70 | } 71 | 72 | static inline void spinlock_unlock_irqrestore(spinlock_t* lock, long flags) 73 | { 74 | spinlock_unlock(lock); 75 | enable_irqrestore(flags); 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/spike/htif.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef _RISCV_HTIF_H 4 | #define _RISCV_HTIF_H 5 | 6 | #include 7 | 8 | #if __riscv_xlen == 64 9 | # define TOHOST_CMD(dev, cmd, payload) \ 10 | (((uint64_t)(dev) << 56) | ((uint64_t)(cmd) << 48) | (uint64_t)(payload)) 11 | #else 12 | # define TOHOST_CMD(dev, cmd, payload) ({ \ 13 | if ((dev) || (cmd)) __builtin_trap(); \ 14 | (payload); }) 15 | #endif 16 | #define FROMHOST_DEV(fromhost_value) ((uint64_t)(fromhost_value) >> 56) 17 | #define FROMHOST_CMD(fromhost_value) ((uint64_t)(fromhost_value) << 8 >> 56) 18 | #define FROMHOST_DATA(fromhost_value) ((uint64_t)(fromhost_value) << 16 >> 16) 19 | 20 | void htif_console_putchar(uint8_t); 21 | int htif_console_getchar(); 22 | void htif_poweroff() __attribute__((noreturn)); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/spike/ioe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void __am_timer_init(); 5 | void __am_timer_rtc(AM_TIMER_RTC_T *); 6 | void __am_timer_uptime(AM_TIMER_UPTIME_T *); 7 | 8 | static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { cfg->present = true; cfg->has_rtc = true; } 9 | 10 | typedef void (*handler_t)(void *buf); 11 | static void *lut[128] = { 12 | [AM_TIMER_CONFIG] = __am_timer_config, 13 | [AM_TIMER_RTC ] = __am_timer_rtc, 14 | [AM_TIMER_UPTIME] = __am_timer_uptime, 15 | }; 16 | 17 | static void fail(void *buf) { panic("access nonexist register"); } 18 | 19 | bool ioe_init() { 20 | for (int i = 0; i < LENGTH(lut); i++) 21 | if (!lut[i]) lut[i] = fail; 22 | __am_timer_init(); 23 | return true; 24 | } 25 | 26 | void ioe_read (int reg, void *buf) { ((handler_t)lut[reg])(buf); } 27 | void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); } 28 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/spike/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS { 4 | . = 0x80000000; 5 | .text : { 6 | *(entry) 7 | *(.text*) 8 | } 9 | etext = .; 10 | _etext = .; 11 | .rodata : { 12 | *(.rodata*) 13 | } 14 | .htif : { 15 | PROVIDE(__htif_base = . ); 16 | *(.htif) 17 | } 18 | .data : { 19 | *(.data) 20 | } 21 | edata = .; 22 | _data = .; 23 | .bss : { 24 | _bss_start = .; 25 | *(.bss*) 26 | *(.sbss*) 27 | *(.scommon) 28 | } 29 | _stack_top = ALIGN(0x1000); 30 | . = _stack_top + 0x8000; 31 | _stack_pointer = .; 32 | end = .; 33 | _end = .; 34 | _heap_start = ALIGN(0x1000); 35 | } 36 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/spike/start.S: -------------------------------------------------------------------------------- 1 | .section entry, "ax" 2 | .globl _start 3 | .type _start, @function 4 | 5 | _start: 6 | mv s0, zero 7 | la sp, _stack_pointer 8 | jal _trm_init 9 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/spike/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static uint64_t boot_time = 0; 4 | 5 | #define CLINT_MMIO 0x2000000ul 6 | #define TIME_BASE 0xbff8 7 | 8 | static uint64_t read_time() { 9 | uint32_t lo = *(volatile uint32_t *)(CLINT_MMIO + TIME_BASE + 0); 10 | uint32_t hi = *(volatile uint32_t *)(CLINT_MMIO + TIME_BASE + 4); 11 | uint64_t time = ((uint64_t)hi << 32) | lo; 12 | return time / 10; 13 | } 14 | 15 | void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { 16 | uptime->us = read_time() - boot_time; 17 | } 18 | 19 | void __am_timer_init() { 20 | boot_time = read_time(); 21 | } 22 | 23 | void __am_timer_rtc(AM_TIMER_RTC_T *rtc) { 24 | rtc->second = 0; 25 | rtc->minute = 0; 26 | rtc->hour = 0; 27 | rtc->day = 0; 28 | rtc->month = 0; 29 | rtc->year = 1900; 30 | } 31 | -------------------------------------------------------------------------------- /abstract-machine/am/src/riscv/spike/trm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "htif.h" 5 | 6 | extern char _heap_start; 7 | int main(const char *args); 8 | 9 | extern char _pmem_start; 10 | #define PMEM_SIZE (128 * 1024 * 1024) 11 | #define PMEM_END ((uintptr_t)0x80000000 + PMEM_SIZE) 12 | 13 | Area heap = RANGE(&_heap_start, PMEM_END); 14 | #ifndef MAINARGS 15 | #define MAINARGS "" 16 | #endif 17 | static const char mainargs[] = MAINARGS; 18 | 19 | void putch(char ch) { 20 | htif_console_putchar(ch); 21 | } 22 | 23 | void halt(int code) { 24 | printf("Exit with code = %d\n", code); 25 | htif_poweroff(); 26 | 27 | // should not reach here 28 | while (1); 29 | } 30 | 31 | void _trm_init() { 32 | int ret = main(mainargs); 33 | halt(ret); 34 | } 35 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/cte.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NR_IRQ 256 // IDT size 6 | #define SEG_KCODE 1 7 | #define SEG_KDATA 2 8 | 9 | static Context* (*user_handler)(Event, Context*) = NULL; 10 | 11 | void __am_irq0(); 12 | void __am_vecsys(); 13 | void __am_vectrap(); 14 | void __am_vecnull(); 15 | 16 | 17 | Context* __am_irq_handle(Context *c) { 18 | if (user_handler) { 19 | Event ev = {0}; 20 | switch (c->irq) { 21 | default: ev.event = EVENT_ERROR; break; 22 | } 23 | 24 | c = user_handler(ev, c); 25 | assert(c != NULL); 26 | } 27 | 28 | return c; 29 | } 30 | 31 | bool cte_init(Context*(*handler)(Event, Context*)) { 32 | static GateDesc32 idt[NR_IRQ]; 33 | 34 | // initialize IDT 35 | for (unsigned int i = 0; i < NR_IRQ; i ++) { 36 | idt[i] = GATE32(STS_TG, KSEL(SEG_KCODE), __am_vecnull, DPL_KERN); 37 | } 38 | 39 | // ----------------------- interrupts ---------------------------- 40 | idt[32] = GATE32(STS_IG, KSEL(SEG_KCODE), __am_irq0, DPL_KERN); 41 | // ---------------------- system call ---------------------------- 42 | idt[0x80] = GATE32(STS_TG, KSEL(SEG_KCODE), __am_vecsys, DPL_USER); 43 | idt[0x81] = GATE32(STS_TG, KSEL(SEG_KCODE), __am_vectrap, DPL_KERN); 44 | 45 | set_idt(idt, sizeof(idt)); 46 | 47 | // register event handler 48 | user_handler = handler; 49 | 50 | return true; 51 | } 52 | 53 | 54 | Context* kcontext(Area kstack, void (*entry)(void *), void *arg) { 55 | return NULL; 56 | } 57 | 58 | void yield() { 59 | asm volatile("int $0x81"); 60 | } 61 | 62 | bool ienabled() { 63 | return false; 64 | } 65 | 66 | void iset(bool enable) { 67 | } 68 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/start.S: -------------------------------------------------------------------------------- 1 | .section entry, "ax" 2 | .globl _start 3 | .type _start, @function 4 | 5 | _start: 6 | mov $0, %ebp 7 | mov $_stack_pointer, %esp 8 | call _trm_init # never return 9 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/trap.S: -------------------------------------------------------------------------------- 1 | #----|------------entry------------|---irq id---|-----handler-----| 2 | .globl __am_vecsys; __am_vecsys: pushl $0x80; jmp __am_asm_trap 3 | .globl __am_vectrap; __am_vectrap: pushl $0x81; jmp __am_asm_trap 4 | .globl __am_irq0; __am_irq0: pushl $32; jmp __am_asm_trap 5 | .globl __am_vecnull; __am_vecnull: pushl $-1; jmp __am_asm_trap 6 | 7 | 8 | __am_asm_trap: 9 | pushal 10 | 11 | pushl $0 12 | 13 | pushl %esp 14 | call __am_irq_handle 15 | 16 | addl $4, %esp 17 | 18 | addl $4, %esp 19 | popal 20 | addl $4, %esp 21 | 22 | iret 23 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/vme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static AddrSpace kas = {}; 6 | static void* (*pgalloc_usr)(int) = NULL; 7 | static void (*pgfree_usr)(void*) = NULL; 8 | static int vme_enable = 0; 9 | 10 | static Area segments[] = { // Kernel memory mappings 11 | NEMU_PADDR_SPACE 12 | }; 13 | 14 | #define USER_SPACE RANGE(0x40000000, 0xc0000000) 15 | 16 | bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { 17 | pgalloc_usr = pgalloc_f; 18 | pgfree_usr = pgfree_f; 19 | 20 | kas.ptr = pgalloc_f(PGSIZE); 21 | 22 | int i; 23 | for (i = 0; i < LENGTH(segments); i ++) { 24 | void *va = segments[i].start; 25 | for (; va < segments[i].end; va += PGSIZE) { 26 | map(&kas, va, va, 0); 27 | } 28 | } 29 | 30 | set_cr3(kas.ptr); 31 | set_cr0(get_cr0() | CR0_PG); 32 | vme_enable = 1; 33 | 34 | return true; 35 | } 36 | 37 | void protect(AddrSpace *as) { 38 | PTE *updir = (PTE*)(pgalloc_usr(PGSIZE)); 39 | as->ptr = updir; 40 | as->area = USER_SPACE; 41 | as->pgsize = PGSIZE; 42 | // map kernel space 43 | memcpy(updir, kas.ptr, PGSIZE); 44 | } 45 | 46 | void unprotect(AddrSpace *as) { 47 | } 48 | 49 | void __am_get_cur_as(Context *c) { 50 | c->cr3 = (vme_enable ? (void *)get_cr3() : NULL); 51 | } 52 | 53 | void __am_switch(Context *c) { 54 | if (vme_enable && c->cr3 != NULL) { 55 | set_cr3(c->cr3); 56 | } 57 | } 58 | 59 | void map(AddrSpace *as, void *va, void *pa, int prot) { 60 | } 61 | 62 | Context* ucontext(AddrSpace *as, Area kstack, void *entry) { 63 | return NULL; 64 | } 65 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/Makefile: -------------------------------------------------------------------------------- 1 | SRCS := start.S main.c 2 | bootblock.o: $(SRCS) Makefile 3 | @echo + CC $(SRCS) 4 | @$(CROSS_COMPILE)gcc -static -m32 -fno-pic -Os -nostdlib -Ttext 0x7c00 -I$(AM_HOME)/am/src -o bootblock.o $(SRCS) 5 | @python3 genboot.py bootblock.o 6 | 7 | clean: 8 | rm -rf *.o 9 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/genboot.py: -------------------------------------------------------------------------------- 1 | import os, sys, pathlib, subprocess 2 | 3 | f = pathlib.Path(sys.argv[1]) 4 | try: 5 | objcopy = os.getenv('CROSS_COMPILE', '') + 'objcopy' 6 | data = subprocess.run( 7 | [objcopy, '-S', '-O', 'binary', '-j', '.text', f, '/dev/stdout'], 8 | capture_output=True).stdout 9 | assert len(data) <= 510 10 | data += b'\0' * (510 - len(data)) + b'\x55\xaa' 11 | f.write_bytes(data) 12 | except: 13 | f.unlink() 14 | raise 15 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define SECTSIZE 512 6 | #define ARGSIZE 1024 7 | 8 | static inline void wait_disk(void) { 9 | while ((inb(0x1f7) & 0xc0) != 0x40); 10 | } 11 | 12 | static inline void read_disk(void *buf, int sect) { 13 | wait_disk(); 14 | outb(0x1f2, 1); 15 | outb(0x1f3, sect); 16 | outb(0x1f4, sect >> 8); 17 | outb(0x1f5, sect >> 16); 18 | outb(0x1f6, (sect >> 24) | 0xE0); 19 | outb(0x1f7, 0x20); 20 | wait_disk(); 21 | for (int i = 0; i < SECTSIZE / 4; i ++) { 22 | ((uint32_t *)buf)[i] = inl(0x1f0); 23 | } 24 | } 25 | 26 | static inline void copy_from_disk(void *buf, int nbytes, int disk_offset) { 27 | uint32_t cur = (uint32_t)buf & ~(SECTSIZE - 1); 28 | uint32_t ed = (uint32_t)buf + nbytes; 29 | uint32_t sect = (disk_offset / SECTSIZE) + (ARGSIZE / SECTSIZE) + 1; 30 | for(; cur < ed; cur += SECTSIZE, sect ++) 31 | read_disk((void *)cur, sect); 32 | } 33 | 34 | static void load_program(uint32_t filesz, uint32_t memsz, uint32_t paddr, uint32_t offset) { 35 | copy_from_disk((void *)paddr, filesz, offset); 36 | char *bss = (void *)(paddr + filesz); 37 | for (uint32_t i = filesz; i != memsz; i++) { 38 | *bss++ = 0; 39 | } 40 | } 41 | 42 | static void load_elf64(Elf64_Ehdr *elf) { 43 | Elf64_Phdr *ph = (Elf64_Phdr *)((char *)elf + elf->e_phoff); 44 | for (int i = 0; i < elf->e_phnum; i++, ph++) { 45 | load_program( 46 | (uint32_t)ph->p_filesz, 47 | (uint32_t)ph->p_memsz, 48 | (uint32_t)ph->p_paddr, 49 | (uint32_t)ph->p_offset 50 | ); 51 | } 52 | } 53 | 54 | static void load_elf32(Elf32_Ehdr *elf) { 55 | Elf32_Phdr *ph = (Elf32_Phdr *)((char *)elf + elf->e_phoff); 56 | for (int i = 0; i < elf->e_phnum; i++, ph++) { 57 | load_program( 58 | (uint32_t)ph->p_filesz, 59 | (uint32_t)ph->p_memsz, 60 | (uint32_t)ph->p_paddr, 61 | (uint32_t)ph->p_offset 62 | ); 63 | } 64 | } 65 | 66 | void load_kernel(void) { 67 | Elf32_Ehdr *elf32 = (void *)0x8000; 68 | Elf64_Ehdr *elf64 = (void *)0x8000; 69 | int is_ap = boot_record()->is_ap; 70 | 71 | if (!is_ap) { 72 | // load argument (string) to memory 73 | copy_from_disk((void *)MAINARG_ADDR, 1024, -1024); 74 | // load elf header to memory 75 | copy_from_disk(elf32, 4096, 0); 76 | if (elf32->e_machine == EM_X86_64) { 77 | load_elf64(elf64); 78 | } else { 79 | load_elf32(elf32); 80 | } 81 | } else { 82 | // everything should be loaded 83 | } 84 | 85 | if (elf32->e_machine == EM_X86_64) { 86 | ((void(*)())(uint32_t)elf64->e_entry)(); 87 | } else { 88 | ((void(*)())(uint32_t)elf32->e_entry)(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/start.S: -------------------------------------------------------------------------------- 1 | #define CR0_PE 0x00000001 2 | 3 | #define GDT_ENTRY(n) \ 4 | ((n) << 3) 5 | 6 | #define SEG_NULLASM \ 7 | .word 0, 0; \ 8 | .byte 0, 0, 0, 0 9 | 10 | #define SEG_ASM(type, base, lim) \ 11 | .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ 12 | .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ 13 | (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) 14 | 15 | .code16 16 | .globl _start 17 | _start: 18 | cli 19 | 20 | xorw %ax, %ax 21 | movw %ax, %ds 22 | movw %ax, %es 23 | movw %ax, %ss 24 | 25 | # Set a 640 x 480 x 32 video mode 26 | mov $0x4f01, %ax 27 | mov $0x0112, %cx 28 | mov $0x4000, %di 29 | int $0x10 30 | 31 | mov $0x4f02, %ax 32 | mov $0x4112, %bx 33 | int $0x10 34 | 35 | lgdt gdtdesc 36 | movl %cr0, %eax 37 | orl $CR0_PE, %eax 38 | movl %eax, %cr0 39 | ljmp $GDT_ENTRY(1), $start32 40 | 41 | .code32 42 | start32: 43 | movw $GDT_ENTRY(2), %ax 44 | movw %ax, %ds 45 | movw %ax, %es 46 | movw %ax, %ss 47 | 48 | movl $0xa000, %esp 49 | call load_kernel 50 | 51 | # GDT 52 | .p2align 2 53 | gdt: 54 | SEG_NULLASM 55 | SEG_ASM(0xA, 0x0, 0xffffffff) 56 | SEG_ASM(0x2, 0x0, 0xffffffff) 57 | 58 | gdtdesc: 59 | .word (gdtdesc - gdt - 1) 60 | .long gdt 61 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/mpe.c: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | struct cpu_local __am_cpuinfo[MAX_CPU] = {}; 4 | static void (* volatile user_entry)(); 5 | static int ap_ready = 0; 6 | 7 | static void call_user_entry() { 8 | user_entry(); 9 | panic("MPE entry should not return"); 10 | } 11 | 12 | bool mpe_init(void (*entry)()) { 13 | user_entry = entry; 14 | boot_record()->jmp_code = 0x000bfde9; // (16-bit) jmp (0x7c00) 15 | for (int cpu = 1; cpu < __am_ncpu; cpu++) { 16 | boot_record()->is_ap = 1; 17 | __am_lapic_bootap(cpu, (void *)boot_record()); 18 | while (xchg(&ap_ready, 0) != 1) { 19 | pause(); 20 | } 21 | } 22 | call_user_entry(); 23 | return true; 24 | } 25 | 26 | static void othercpu_entry() { 27 | __am_percpu_init(); 28 | xchg(&ap_ready, 1); 29 | call_user_entry(); 30 | } 31 | 32 | void __am_othercpu_entry() { 33 | stack_switch_call(stack_top(&CPU->stack), othercpu_entry, 0); 34 | } 35 | 36 | int cpu_count() { 37 | return __am_ncpu; 38 | } 39 | 40 | int cpu_current(void) { 41 | return __am_lapic[8] >> 24; 42 | } 43 | 44 | int atomic_xchg(int *addr, int newval) { 45 | return xchg(addr, newval); 46 | } 47 | 48 | void __am_stop_the_world() { 49 | boot_record()->jmp_code = 0x0000feeb; // (16-bit) jmp . 50 | for (int cpu_ = 0; cpu_ < __am_ncpu; cpu_++) { 51 | if (cpu_ != cpu_current()) { 52 | __am_lapic_bootap(cpu_, (void *)boot_record()); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/start32.S: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | .globl _start 4 | _start: 5 | pushl $MAINARG_ADDR 6 | pushl $0 7 | jmp _start_c 8 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/start64.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include "x86-qemu.h" 3 | 4 | .code32 5 | .globl _start 6 | _start: 7 | movl $(PDPT_ADDR | PTE_P | PTE_W), %eax 8 | cmpl (PML4_ADDR), %eax 9 | je .long_mode_init 10 | 11 | movl $(PDPT_ADDR | PTE_P | PTE_W), %eax 12 | movl %eax, (PML4_ADDR) 13 | 14 | movl $0, %ecx 15 | movl $512, %esi // 512 pages 16 | // | 17 | .loop: // x 18 | movl %ecx, %eax // | 19 | shll $30, %eax // | 20 | orl $(PTE_P | PTE_W | PTE_PS), %eax // 1 GiB page 21 | movl %eax, PDPT_ADDR(, %ecx, 8) 22 | 23 | movl %ecx, %eax 24 | shrl $2, %eax 25 | movl %eax, PDPT_ADDR + 4(, %ecx, 8) 26 | 27 | inc %ecx 28 | cmp %esi, %ecx 29 | jne .loop 30 | 31 | .long_mode_init: 32 | movl $PML4_ADDR, %eax 33 | movl %eax, %cr3 // %cr3 = PML4 base 34 | movl $CR4_PAE, %eax 35 | movl %eax, %cr4 // %cr4.PAE = 1 36 | movl $0xc0000080, %ecx 37 | rdmsr 38 | orl $0x100, %eax 39 | wrmsr // %EFER.LME = 1 40 | movl %cr0, %eax 41 | orl $CR0_PG, %eax 42 | movl %eax, %cr0 // %cr0.PG = 1 43 | lgdt gdt_ptr // bootstrap GDT 44 | ljmp $8, $_start64 // should not return 45 | 46 | .code64 47 | _start64: 48 | movw $0, %ax 49 | movw %ax, %ds 50 | movw %ax, %es 51 | movw %ax, %ss 52 | movw %ax, %fs 53 | movw %ax, %gs 54 | 55 | movq $MAINARG_ADDR, %rdi 56 | pushq $0 57 | jmp _start_c 58 | 59 | .align 16 60 | gdt_ptr: 61 | .word gdt64_end - gdt64_begin - 1 62 | .quad gdt64_begin 63 | 64 | gdt64_begin: 65 | .long 0x00000000 // 0: null desc 66 | .long 0x00000000 67 | .long 0x00000000 // 1: code 68 | .long 0x00209800 69 | gdt64_end: 70 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/trap32.S: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | .globl __am_kcontext_start 4 | __am_kcontext_start: 5 | // eax = arg, ebx = entry 6 | pushl %eax 7 | pushl $__am_panic_on_return 8 | jmpl *%ebx 9 | 10 | trap: 11 | cli 12 | 13 | subl $20, %esp 14 | pushl %ebp 15 | pushl %edi 16 | pushl %esi 17 | pushl $0 18 | pushl %edx 19 | pushl %ecx 20 | pushl %ebx 21 | pushl %eax 22 | movw %ds, %ax 23 | pushl %eax 24 | pushl $0 25 | 26 | movw $KSEL(SEG_KDATA), %ax 27 | movw %ax, %ds 28 | movw %ax, %es 29 | movw %ax, %ss 30 | 31 | pushl %esp 32 | call __am_irq_handle 33 | 34 | .globl __am_iret 35 | __am_iret: 36 | addl $4, %esp 37 | popl %eax 38 | movl %eax, %esp 39 | 40 | addl $4, %esp 41 | popl %eax 42 | movw %ax, %ds 43 | movw %ax, %es 44 | 45 | cmpw $KSEL(SEG_KCODE), 36(%esp) 46 | je .kernel_iret 47 | 48 | .user_iret: 49 | popl %eax 50 | popl %ebx 51 | popl %ecx 52 | popl %edx 53 | addl $4, %esp 54 | popl %esi 55 | popl %edi 56 | popl %ebp 57 | iret 58 | 59 | .kernel_iret: 60 | popl %eax 61 | popl %ebx 62 | popl %ecx 63 | popl %edx 64 | addl $4, %esp 65 | 66 | /* stack frame: 67 | 28 ss 68 | 24 esp (not popped by iret when returning to ring0) 69 | 20 eflags ---> move to new-esp 70 | 16 cs 71 | 12 eip 72 | 8 ebp 73 | 4 edi 74 | 0 esi <--- %esp 75 | */ 76 | 77 | movl %esp, %ebp 78 | movl 24(%ebp), %edi // %edi is new-esp 79 | 80 | movl 20(%ebp), %esi; movl %esi, -4(%edi) 81 | movl 16(%ebp), %esi; movl %esi, -8(%edi) 82 | movl 12(%ebp), %esi; movl %esi, -12(%edi) 83 | movl 8(%ebp), %esi; movl %esi, -16(%edi) 84 | movl 4(%ebp), %esi; movl %esi, -20(%edi) 85 | movl 0(%ebp), %esi; movl %esi, -24(%edi) 86 | 87 | leal -24(%edi), %esp 88 | 89 | popl %esi 90 | popl %edi 91 | popl %ebp 92 | iret 93 | 94 | #define NOERR push $0 95 | #define ERR 96 | #define IRQ_DEF(id, dpl, err) \ 97 | .globl __am_irq##id; __am_irq##id: cli; err; push $id; jmp trap; 98 | IRQS(IRQ_DEF) 99 | .globl __am_irqall; __am_irqall: cli; push $0; push $-1; jmp trap; 100 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/trap64.S: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | .globl __am_kcontext_start 4 | __am_kcontext_start: 5 | // rdi = arg, rsi = entry 6 | pushq $__am_panic_on_return 7 | jmpq *%rsi 8 | 9 | trap: 10 | cli 11 | subq $48, %rsp 12 | pushq %r15 13 | pushq %r14 14 | pushq %r13 15 | pushq %r12 16 | pushq %r11 17 | pushq %r10 18 | pushq %r9 19 | pushq %r8 20 | pushq %rdi 21 | pushq %rsi 22 | pushq %rbp 23 | pushq %rdx 24 | pushq %rcx 25 | pushq %rbx 26 | pushq %rax 27 | pushq $0 // cr3, saved in __am_irq_handle 28 | 29 | movq %rsp, %rdi 30 | call __am_irq_handle 31 | 32 | .globl __am_iret 33 | __am_iret: 34 | movq %rdi, %rsp 35 | movq 160(%rsp), %rax 36 | movw %ax, %ds 37 | movw %ax, %es 38 | addq $8, %rsp 39 | popq %rax 40 | popq %rbx 41 | popq %rcx 42 | popq %rdx 43 | popq %rbp 44 | popq %rsi 45 | popq %rdi 46 | popq %r8 47 | popq %r9 48 | popq %r10 49 | popq %r11 50 | popq %r12 51 | popq %r13 52 | popq %r14 53 | popq %r15 54 | iretq 55 | 56 | #define NOERR push $0 57 | #define ERR 58 | #define IRQ_DEF(id, dpl, err) \ 59 | .globl __am_irq##id; __am_irq##id: cli; err; push $id; jmp trap; 60 | IRQS(IRQ_DEF) 61 | .globl __am_irqall; __am_irqall: cli; push $0; push $-1; jmp trap; 62 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/x86-qemu.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PML4_ADDR 0x1000 4 | #define PDPT_ADDR 0x2000 5 | 6 | #define NR_SEG 6 // GDT size 7 | #define SEG_KCODE 1 // Kernel code 8 | #define SEG_KDATA 2 // Kernel data/stack 9 | #define SEG_UCODE 3 // User code 10 | #define SEG_UDATA 4 // User data/stack 11 | #define SEG_TSS 5 // Global unique task state segement 12 | 13 | #define NR_IRQ 256 // IDT size 14 | 15 | #ifndef __ASSEMBLER__ 16 | 17 | #include 18 | #include 19 | 20 | struct kernel_stack { 21 | uint8_t stack[8192]; 22 | }; 23 | 24 | static inline void *stack_top(struct kernel_stack *stk) { 25 | return stk->stack + sizeof(stk->stack); 26 | } 27 | 28 | struct mmu_config { 29 | int ptlevels, pgsize; 30 | struct ptinfo { 31 | const char *name; 32 | uintptr_t mask; 33 | int shift, bits; 34 | } pgtables[]; 35 | }; 36 | 37 | struct vm_area { 38 | Area area; 39 | int kernel; 40 | }; 41 | 42 | void __am_iret(Context *ctx); 43 | 44 | struct cpu_local { 45 | AddrSpace *uvm; 46 | #if __x86_64__ 47 | SegDesc gdt[NR_SEG + 1]; 48 | TSS64 tss; 49 | #else 50 | SegDesc gdt[NR_SEG]; 51 | TSS32 tss; 52 | #endif 53 | struct kernel_stack stack; 54 | }; 55 | 56 | #if __x86_64__ 57 | struct trap_frame { 58 | Context saved_context; 59 | uint64_t irq, errcode; 60 | uint64_t rip, cs, rflags, rsp, ss; 61 | }; 62 | #else 63 | struct trap_frame { 64 | Context saved_context; 65 | uint32_t irq, errcode; 66 | uint32_t eip, cs, eflags, esp, ss; 67 | }; 68 | #endif 69 | 70 | extern volatile uint32_t *__am_lapic; 71 | extern int __am_ncpu; 72 | extern struct cpu_local __am_cpuinfo[MAX_CPU]; 73 | 74 | #define CPU (&__am_cpuinfo[cpu_current()]) 75 | 76 | #define bug_on(cond) \ 77 | do { \ 78 | if (cond) panic("internal error (likely a bug in AM)"); \ 79 | } while (0) 80 | 81 | #define bug() bug_on(1) 82 | 83 | // apic utils 84 | void __am_lapic_eoi(); 85 | void __am_ioapic_init(); 86 | void __am_lapic_bootap(uint32_t cpu, void *address); 87 | void __am_ioapic_enable(int irq, int cpu); 88 | 89 | // x86-specific operations 90 | void __am_bootcpu_init(); 91 | void __am_percpu_init(); 92 | Area __am_heap_init(); 93 | void __am_lapic_init(); 94 | void __am_othercpu_entry(); 95 | void __am_percpu_initirq(); 96 | void __am_percpu_initgdt(); 97 | void __am_percpu_initlapic(); 98 | void __am_stop_the_world(); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /abstract-machine/klib/Makefile: -------------------------------------------------------------------------------- 1 | NAME = klib 2 | SRCS = $(shell find src/ -name "*.c") 3 | include $(AM_HOME)/Makefile 4 | -------------------------------------------------------------------------------- /abstract-machine/klib/include/klib-macros.h: -------------------------------------------------------------------------------- 1 | #ifndef KLIB_MACROS_H__ 2 | #define KLIB_MACROS_H__ 3 | 4 | #define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1)) 5 | #define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz) - 1)) 6 | #define LENGTH(arr) (sizeof(arr) / sizeof((arr)[0])) 7 | #define RANGE(st, ed) (Area) { .start = (void *)(st), .end = (void *)(ed) } 8 | #define IN_RANGE(ptr, area) ((area).start <= (ptr) && (ptr) < (area).end) 9 | 10 | #define STRINGIFY(s) #s 11 | #define TOSTRING(s) STRINGIFY(s) 12 | #define _CONCAT(x, y) x ## y 13 | #define CONCAT(x, y) _CONCAT(x, y) 14 | 15 | #define putstr(s) \ 16 | ({ for (const char *p = s; *p; p++) putch(*p); }) 17 | 18 | #define io_read(reg) \ 19 | ({ reg##_T __io_param; \ 20 | ioe_read(reg, &__io_param); \ 21 | __io_param; }) 22 | 23 | #define io_write(reg, ...) \ 24 | ({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \ 25 | ioe_write(reg, &__io_param); }) 26 | 27 | #define static_assert(const_cond) \ 28 | static char CONCAT(_static_assert_, __LINE__) [(const_cond) ? 1 : -1] __attribute__((unused)) 29 | 30 | #define panic_on(cond, s) \ 31 | ({ if (cond) { \ 32 | putstr("AM Panic: "); putstr(s); \ 33 | putstr(" @ " __FILE__ ":" TOSTRING(__LINE__) " \n"); \ 34 | halt(1); \ 35 | } }) 36 | 37 | #define panic(s) panic_on(1, s) 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /abstract-machine/klib/include/klib.h: -------------------------------------------------------------------------------- 1 | #ifndef KLIB_H__ 2 | #define KLIB_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | //#define __NATIVE_USE_KLIB__ 13 | 14 | // string.h 15 | void *memset (void *s, int c, size_t n); 16 | void *memcpy (void *dst, const void *src, size_t n); 17 | void *memmove (void *dst, const void *src, size_t n); 18 | int memcmp (const void *s1, const void *s2, size_t n); 19 | size_t strlen (const char *s); 20 | char *strcat (char *dst, const char *src); 21 | char *strcpy (char *dst, const char *src); 22 | char *strncpy (char *dst, const char *src, size_t n); 23 | int strcmp (const char *s1, const char *s2); 24 | int strncmp (const char *s1, const char *s2, size_t n); 25 | 26 | // stdlib.h 27 | void srand (unsigned int seed); 28 | int rand (void); 29 | void *malloc (size_t size); 30 | void free (void *ptr); 31 | int abs (int x); 32 | int atoi (const char *nptr); 33 | 34 | // stdio.h 35 | int printf (const char *format, ...); 36 | int sprintf (char *str, const char *format, ...); 37 | int snprintf (char *str, size_t size, const char *format, ...); 38 | int vsprintf (char *str, const char *format, va_list ap); 39 | int vsnprintf (char *str, size_t size, const char *format, va_list ap); 40 | 41 | // assert.h 42 | #ifdef NDEBUG 43 | #define assert(ignore) ((void)0) 44 | #else 45 | #define assert(cond) \ 46 | do { \ 47 | if (!(cond)) { \ 48 | printf("Assertion fail at %s:%d\n", __FILE__, __LINE__); \ 49 | halt(1); \ 50 | } \ 51 | } while (0) 52 | #endif 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/cpp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef __ISA_NATIVE__ 5 | 6 | void __dso_handle() { 7 | } 8 | 9 | void __cxa_guard_acquire() { 10 | } 11 | 12 | void __cxa_guard_release() { 13 | } 14 | 15 | void __cxa_atexit() { 16 | assert(0); 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) 7 | 8 | int printf(const char *fmt, ...) { 9 | panic("Not implemented"); 10 | } 11 | 12 | int vsprintf(char *out, const char *fmt, va_list ap) { 13 | panic("Not implemented"); 14 | } 15 | 16 | int sprintf(char *out, const char *fmt, ...) { 17 | panic("Not implemented"); 18 | } 19 | 20 | int snprintf(char *out, size_t n, const char *fmt, ...) { 21 | panic("Not implemented"); 22 | } 23 | 24 | int vsnprintf(char *out, size_t n, const char *fmt, va_list ap) { 25 | panic("Not implemented"); 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/stdlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) 6 | static unsigned long int next = 1; 7 | 8 | int rand(void) { 9 | // RAND_MAX assumed to be 32767 10 | next = next * 1103515245 + 12345; 11 | return (unsigned int)(next/65536) % 32768; 12 | } 13 | 14 | void srand(unsigned int seed) { 15 | next = seed; 16 | } 17 | 18 | int abs(int x) { 19 | return (x < 0 ? -x : x); 20 | } 21 | 22 | int atoi(const char* nptr) { 23 | int x = 0; 24 | while (*nptr == ' ') { nptr ++; } 25 | while (*nptr >= '0' && *nptr <= '9') { 26 | x = x * 10 + *nptr - '0'; 27 | nptr ++; 28 | } 29 | return x; 30 | } 31 | 32 | void *malloc(size_t size) { 33 | // On native, malloc() will be called during initializaion of C runtime. 34 | // Therefore do not call panic() here, else it will yield a dead recursion: 35 | // panic() -> putchar() -> (glibc) -> malloc() -> panic() 36 | #if !(defined(__ISA_NATIVE__) && defined(__NATIVE_USE_KLIB__)) 37 | panic("Not implemented"); 38 | #endif 39 | return NULL; 40 | } 41 | 42 | void free(void *ptr) { 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) 6 | 7 | size_t strlen(const char *s) { 8 | panic("Not implemented"); 9 | } 10 | 11 | char *strcpy(char *dst, const char *src) { 12 | panic("Not implemented"); 13 | } 14 | 15 | char *strncpy(char *dst, const char *src, size_t n) { 16 | panic("Not implemented"); 17 | } 18 | 19 | char *strcat(char *dst, const char *src) { 20 | panic("Not implemented"); 21 | } 22 | 23 | int strcmp(const char *s1, const char *s2) { 24 | panic("Not implemented"); 25 | } 26 | 27 | int strncmp(const char *s1, const char *s2, size_t n) { 28 | panic("Not implemented"); 29 | } 30 | 31 | void *memset(void *s, int c, size_t n) { 32 | panic("Not implemented"); 33 | } 34 | 35 | void *memmove(void *dst, const void *src, size_t n) { 36 | panic("Not implemented"); 37 | } 38 | 39 | void *memcpy(void *out, const void *in, size_t n) { 40 | panic("Not implemented"); 41 | } 42 | 43 | int memcmp(const void *s1, const void *s2, size_t n) { 44 | panic("Not implemented"); 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /abstract-machine/scripts/isa/mips32.mk: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE := mips-linux-gnu- 2 | COMMON_FLAGS := -march=mips32 -fno-pic -fno-delayed-branch -mno-abicalls -mno-check-zero-division -EL 3 | CFLAGS += $(COMMON_FLAGS) -static -mno-llsc -mno-imadd -mno-mad 4 | ASFLAGS += $(COMMON_FLAGS) -O0 5 | LDFLAGS += -EL 6 | -------------------------------------------------------------------------------- /abstract-machine/scripts/isa/riscv32.mk: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE := riscv64-linux-gnu- 2 | COMMON_FLAGS := -fno-pic -march=rv32g -mabi=ilp32 3 | CFLAGS += $(COMMON_FLAGS) -static 4 | ASFLAGS += $(COMMON_FLAGS) -O0 5 | LDFLAGS += -melf32lriscv 6 | -------------------------------------------------------------------------------- /abstract-machine/scripts/isa/riscv64.mk: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE := riscv64-linux-gnu- 2 | COMMON_FLAGS := -fno-pic -march=rv64g -mcmodel=medany -mstrict-align 3 | CFLAGS += $(COMMON_FLAGS) -static 4 | ASFLAGS += $(COMMON_FLAGS) -O0 5 | LDFLAGS += -melf64lriscv 6 | -------------------------------------------------------------------------------- /abstract-machine/scripts/isa/x86.mk: -------------------------------------------------------------------------------- 1 | export CROSS_COMPILE := x86_64-linux-gnu- 2 | CFLAGS += -m32 -fno-pic -fno-omit-frame-pointer -march=i386 3 | CFLAGS += -fcf-protection=none # remove endbr32 in Ubuntu 20.04 with a CPU newer than Comet Lake 4 | ASFLAGS += -m32 -fno-pic 5 | LDFLAGS += -melf_i386 6 | -------------------------------------------------------------------------------- /abstract-machine/scripts/isa/x86_64.mk: -------------------------------------------------------------------------------- 1 | export CROSS_COMPILE := x86_64-linux-gnu- 2 | CFLAGS += -m64 -fPIC -mno-sse 3 | ASFLAGS += -m64 -fPIC 4 | LDFLAGS += -melf_x86_64 5 | -------------------------------------------------------------------------------- /abstract-machine/scripts/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | PHDRS { text PT_LOAD; data PT_LOAD; } 3 | 4 | SECTIONS { 5 | /* _pmem_start and _entry_offset are defined in LDFLAGS */ 6 | . = _pmem_start + _entry_offset; 7 | .text : { 8 | *(entry) 9 | *(.text*) 10 | } : text 11 | etext = .; 12 | _etext = .; 13 | .rodata : { 14 | *(.rodata*) 15 | } 16 | .data : { 17 | *(.data) 18 | } : data 19 | edata = .; 20 | _data = .; 21 | .bss : { 22 | _bss_start = .; 23 | *(.bss*) 24 | *(.sbss*) 25 | *(.scommon) 26 | } 27 | _stack_top = ALIGN(0x1000); 28 | . = _stack_top + 0x8000; 29 | _stack_pointer = .; 30 | end = .; 31 | _end = .; 32 | _heap_start = ALIGN(0x1000); 33 | } 34 | -------------------------------------------------------------------------------- /abstract-machine/scripts/mips32-nemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/mips32.mk 2 | include $(AM_HOME)/scripts/platform/nemu.mk 3 | CFLAGS += -DISA_H=\"mips/mips32.h\" 4 | 5 | AM_SRCS += mips/nemu/start.S \ 6 | mips/nemu/cte.c \ 7 | mips/nemu/trap.S \ 8 | mips/nemu/vme.c 9 | -------------------------------------------------------------------------------- /abstract-machine/scripts/native.mk: -------------------------------------------------------------------------------- 1 | AM_SRCS := native/trm.c \ 2 | native/ioe.c \ 3 | native/cte.c \ 4 | native/trap.S \ 5 | native/vme.c \ 6 | native/mpe.c \ 7 | native/platform.c \ 8 | native/ioe/input.c \ 9 | native/ioe/timer.c \ 10 | native/ioe/gpu.c \ 11 | native/ioe/audio.c \ 12 | native/ioe/disk.c \ 13 | 14 | CFLAGS += -fpie 15 | ASFLAGS += -fpie -pie 16 | 17 | image: 18 | @echo + LD "->" $(IMAGE_REL) 19 | @g++ -pie -o $(IMAGE) -Wl,--whole-archive $(LINKAGE) -Wl,-no-whole-archive -Wl,-z -Wl,noexecstack -lSDL2 -ldl 20 | 21 | run: image 22 | $(IMAGE) 23 | 24 | gdb: image 25 | gdb -ex "handle SIGUSR1 SIGUSR2 SIGSEGV noprint nostop" $(IMAGE) 26 | -------------------------------------------------------------------------------- /abstract-machine/scripts/platform/nemu.mk: -------------------------------------------------------------------------------- 1 | AM_SRCS := platform/nemu/trm.c \ 2 | platform/nemu/ioe/ioe.c \ 3 | platform/nemu/ioe/timer.c \ 4 | platform/nemu/ioe/input.c \ 5 | platform/nemu/ioe/gpu.c \ 6 | platform/nemu/ioe/audio.c \ 7 | platform/nemu/ioe/disk.c \ 8 | platform/nemu/mpe.c 9 | 10 | CFLAGS += -fdata-sections -ffunction-sections 11 | LDFLAGS += -T $(AM_HOME)/scripts/linker.ld \ 12 | --defsym=_pmem_start=0x80000000 --defsym=_entry_offset=0x0 13 | LDFLAGS += --gc-sections -e _start 14 | NEMUFLAGS += -l $(shell dirname $(IMAGE).elf)/nemu-log.txt 15 | 16 | CFLAGS += -DMAINARGS=\"$(mainargs)\" 17 | CFLAGS += -I$(AM_HOME)/am/src/platform/nemu/include 18 | .PHONY: $(AM_HOME)/am/src/platform/nemu/trm.c 19 | 20 | image: $(IMAGE).elf 21 | @$(OBJDUMP) -d $(IMAGE).elf > $(IMAGE).txt 22 | @echo + OBJCOPY "->" $(IMAGE_REL).bin 23 | @$(OBJCOPY) -S --set-section-flags .bss=alloc,contents -O binary $(IMAGE).elf $(IMAGE).bin 24 | 25 | run: image 26 | $(MAKE) -C $(NEMU_HOME) ISA=$(ISA) run ARGS="$(NEMUFLAGS)" IMG=$(IMAGE).bin 27 | 28 | gdb: image 29 | $(MAKE) -C $(NEMU_HOME) ISA=$(ISA) gdb ARGS="$(NEMUFLAGS)" IMG=$(IMAGE).bin 30 | -------------------------------------------------------------------------------- /abstract-machine/scripts/platform/qemu.mk: -------------------------------------------------------------------------------- 1 | .PHONY: build-arg 2 | 3 | LDFLAGS += -N -Ttext-segment=0x00100000 4 | QEMU_FLAGS += -serial mon:stdio \ 5 | -machine accel=tcg \ 6 | -smp "$(smp)" \ 7 | -drive format=raw,file=$(IMAGE) 8 | 9 | build-arg: image 10 | @( echo -n $(mainargs); ) | dd if=/dev/stdin of=$(IMAGE) bs=512 count=2 seek=1 conv=notrunc status=none 11 | 12 | BOOT_HOME := $(AM_HOME)/am/src/x86/qemu/boot 13 | 14 | image: $(IMAGE).elf 15 | @$(MAKE) -s -C $(BOOT_HOME) 16 | @echo + CREATE "->" $(IMAGE_REL) 17 | @( cat $(BOOT_HOME)/bootblock.o; head -c 1024 /dev/zero; cat $(IMAGE).elf ) > $(IMAGE) 18 | -------------------------------------------------------------------------------- /abstract-machine/scripts/riscv32-nemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/riscv32.mk 2 | include $(AM_HOME)/scripts/platform/nemu.mk 3 | CFLAGS += -DISA_H=\"riscv/riscv.h\" 4 | 5 | AM_SRCS += riscv/nemu/start.S \ 6 | riscv/nemu/cte.c \ 7 | riscv/nemu/trap.S \ 8 | riscv/nemu/vme.c 9 | -------------------------------------------------------------------------------- /abstract-machine/scripts/riscv64-nemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/riscv64.mk 2 | include $(AM_HOME)/scripts/platform/nemu.mk 3 | CFLAGS += -DISA_H=\"riscv/riscv.h\" 4 | 5 | AM_SRCS += riscv/nemu/start.S \ 6 | riscv/nemu/cte.c \ 7 | riscv/nemu/trap.S \ 8 | riscv/nemu/vme.c 9 | -------------------------------------------------------------------------------- /abstract-machine/scripts/riscv64-npc.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/riscv64.mk 2 | 3 | AM_SRCS := riscv/npc/start.S \ 4 | riscv/npc/trm.c \ 5 | riscv/npc/ioe.c \ 6 | riscv/npc/timer.c \ 7 | riscv/npc/input.c \ 8 | riscv/npc/cte.c \ 9 | riscv/npc/trap.S \ 10 | platform/dummy/vme.c \ 11 | platform/dummy/mpe.c 12 | 13 | CFLAGS += -fdata-sections -ffunction-sections 14 | LDFLAGS += -T $(AM_HOME)/scripts/linker.ld --defsym=_pmem_start=0x80000000 --defsym=_entry_offset=0x0 15 | LDFLAGS += --gc-sections -e _start 16 | CFLAGS += -DMAINARGS=\"$(mainargs)\" 17 | .PHONY: $(AM_HOME)/am/src/riscv/npc/trm.c 18 | 19 | image: $(IMAGE).elf 20 | @$(OBJDUMP) -d $(IMAGE).elf > $(IMAGE).txt 21 | @echo + OBJCOPY "->" $(IMAGE_REL).bin 22 | @$(OBJCOPY) -S --set-section-flags .bss=alloc,contents -O binary $(IMAGE).elf $(IMAGE).bin 23 | -------------------------------------------------------------------------------- /abstract-machine/scripts/spike.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/riscv64.mk 2 | 3 | AM_SRCS := riscv/spike/trm.c \ 4 | riscv/spike/ioe.c \ 5 | riscv/spike/timer.c \ 6 | riscv/spike/start.S \ 7 | riscv/spike/htif.S \ 8 | platform/dummy/cte.c \ 9 | platform/dummy/vme.c \ 10 | platform/dummy/mpe.c \ 11 | 12 | CFLAGS += -fdata-sections -ffunction-sections 13 | LDFLAGS += -T $(AM_HOME)/am/src/riscv/spike/linker.ld 14 | LDFLAGS += --gc-sections -e _start 15 | 16 | CFLAGS += -DMAINARGS=\"$(mainargs)\" 17 | .PHONY: $(AM_HOME)/am/src/riscv/spike/trm.c 18 | 19 | image: $(IMAGE).elf 20 | -------------------------------------------------------------------------------- /abstract-machine/scripts/x86-nemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/x86.mk 2 | include $(AM_HOME)/scripts/platform/nemu.mk 3 | CFLAGS += -mstringop-strategy=loop -DISA_H=\"x86/x86.h\" 4 | # overwrite _pmem_start and _entry_offset defined in nemu.mk 5 | LDFLAGS += --defsym=_pmem_start=0x0 --defsym=_entry_offset=0x100000 6 | 7 | AM_SRCS += x86/nemu/start.S \ 8 | x86/nemu/cte.c \ 9 | x86/nemu/trap.S \ 10 | x86/nemu/vme.c 11 | -------------------------------------------------------------------------------- /abstract-machine/scripts/x86-qemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/x86.mk 2 | include $(AM_HOME)/scripts/platform/qemu.mk 3 | 4 | AM_SRCS := x86/qemu/start32.S \ 5 | x86/qemu/trap32.S \ 6 | x86/qemu/trm.c \ 7 | x86/qemu/cte.c \ 8 | x86/qemu/ioe.c \ 9 | x86/qemu/vme.c \ 10 | x86/qemu/mpe.c 11 | 12 | run: build-arg 13 | @qemu-system-i386 $(QEMU_FLAGS) 14 | -------------------------------------------------------------------------------- /abstract-machine/scripts/x86_64-qemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/x86_64.mk 2 | include $(AM_HOME)/scripts/platform/qemu.mk 3 | 4 | AM_SRCS := x86/qemu/start64.S \ 5 | x86/qemu/trap64.S \ 6 | x86/qemu/trm.c \ 7 | x86/qemu/cte.c \ 8 | x86/qemu/ioe.c \ 9 | x86/qemu/vme.c \ 10 | x86/qemu/mpe.c 11 | 12 | run: build-arg 13 | @qemu-system-x86_64 $(QEMU_FLAGS) 14 | -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # usage: addenv env_name path 4 | function addenv() { 5 | sed -i -e "/^export $1=.*/d" ~/.bashrc 6 | echo "export $1=`readlink -e $2`" >> ~/.bashrc 7 | echo "By default this script will add environment variables into ~/.bashrc." 8 | echo "After that, please run 'source ~/.bashrc' to let these variables take effect." 9 | echo "If you use shell other than bash, please add these environment variables manually." 10 | } 11 | 12 | # usage: init repo branch directory trace [env] 13 | # trace = true|false 14 | function init() { 15 | if [ -d $3 ]; then 16 | echo "$3 is already initialized, skipping..." 17 | return 18 | fi 19 | 20 | while [ ! -d $3 ]; do 21 | git clone -b $2 git@github.com:$1.git $3 22 | done 23 | log="$1 `cd $3 && git log --oneline --no-abbrev-commit -n1`"$'\n' 24 | 25 | if [ $4 == "true" ] ; then 26 | rm -rf $3/.git 27 | git add -A $3 28 | git commit -am "$1 $2 initialized"$'\n\n'"$log" 29 | else 30 | sed -i -e "/^\/$3/d" .gitignore 31 | echo "/$3" >> .gitignore 32 | git add -A .gitignore 33 | git commit --no-verify --allow-empty -am "$1 $2 initialized without tracing"$'\n\n'"$log" 34 | fi 35 | 36 | if [ $5 ] ; then 37 | addenv $5 $3 38 | fi 39 | } 40 | 41 | case $1 in 42 | nemu) 43 | init NJU-ProjectN/nemu ics2022 nemu true NEMU_HOME 44 | ;; 45 | abstract-machine) 46 | init NJU-ProjectN/abstract-machine ics2022 abstract-machine true AM_HOME 47 | init NJU-ProjectN/fceux-am ics2021 fceux-am false 48 | ;; 49 | am-kernels) 50 | init NJU-ProjectN/am-kernels ics2021 am-kernels false 51 | ;; 52 | nanos-lite) 53 | init NJU-ProjectN/nanos-lite ics2021 nanos-lite true 54 | ;; 55 | navy-apps) 56 | init NJU-ProjectN/navy-apps ics2021 navy-apps true NAVY_HOME 57 | ;; 58 | *) 59 | echo "Invalid input..." 60 | exit 61 | ;; 62 | esac 63 | -------------------------------------------------------------------------------- /nemu/.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | * 3 | !*/ 4 | !Makefile 5 | !*.mk 6 | !*.[cSh] 7 | !*.cc 8 | !.gitignore 9 | !README.md 10 | !Kconfig 11 | include/config 12 | include/generated 13 | -------------------------------------------------------------------------------- /nemu/Makefile: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | # Sanity check 17 | ifeq ($(wildcard $(NEMU_HOME)/src/nemu-main.c),) 18 | $(error NEMU_HOME=$(NEMU_HOME) is not a NEMU repo) 19 | endif 20 | 21 | # Include variables and rules generated by menuconfig 22 | -include $(NEMU_HOME)/include/config/auto.conf 23 | -include $(NEMU_HOME)/include/config/auto.conf.cmd 24 | 25 | remove_quote = $(patsubst "%",%,$(1)) 26 | 27 | # Extract variabls from menuconfig 28 | GUEST_ISA ?= $(call remove_quote,$(CONFIG_ISA)) 29 | ENGINE ?= $(call remove_quote,$(CONFIG_ENGINE)) 30 | NAME = $(GUEST_ISA)-nemu-$(ENGINE) 31 | 32 | # Include all filelist.mk to merge file lists 33 | FILELIST_MK = $(shell find ./src -name "filelist.mk") 34 | include $(FILELIST_MK) 35 | 36 | # Filter out directories and files in blacklist to obtain the final set of source files 37 | DIRS-BLACKLIST-y += $(DIRS-BLACKLIST) 38 | SRCS-BLACKLIST-y += $(SRCS-BLACKLIST) $(shell find $(DIRS-BLACKLIST-y) -name "*.c") 39 | SRCS-y += $(shell find $(DIRS-y) -name "*.c") 40 | SRCS = $(filter-out $(SRCS-BLACKLIST-y),$(SRCS-y)) 41 | 42 | # Extract compiler and options from menuconfig 43 | CC = $(call remove_quote,$(CONFIG_CC)) 44 | CFLAGS_BUILD += $(call remove_quote,$(CONFIG_CC_OPT)) 45 | CFLAGS_BUILD += $(if $(CONFIG_CC_LTO),-flto,) 46 | CFLAGS_BUILD += $(if $(CONFIG_CC_DEBUG),-Og -ggdb3,) 47 | CFLAGS_BUILD += $(if $(CONFIG_CC_ASAN),-fsanitize=address,) 48 | CFLAGS_TRACE += -DITRACE_COND=$(if $(CONFIG_ITRACE_COND),$(call remove_quote,$(CONFIG_ITRACE_COND)),true) 49 | CFLAGS += $(CFLAGS_BUILD) $(CFLAGS_TRACE) -D__GUEST_ISA__=$(GUEST_ISA) 50 | LDFLAGS += $(CFLAGS_BUILD) 51 | 52 | # Include rules for menuconfig 53 | include $(NEMU_HOME)/scripts/config.mk 54 | 55 | ifdef CONFIG_TARGET_AM 56 | include $(AM_HOME)/Makefile 57 | LINKAGE += $(ARCHIVES) 58 | else 59 | # Include rules to build NEMU 60 | include $(NEMU_HOME)/scripts/native.mk 61 | endif 62 | -------------------------------------------------------------------------------- /nemu/README.md: -------------------------------------------------------------------------------- 1 | # NEMU 2 | 3 | NEMU(NJU Emulator) is a simple but complete full-system emulator designed for teaching purpose. 4 | Currently it supports x86, mips32, riscv32 and riscv64. 5 | To build programs run above NEMU, refer to the [AM project](https://github.com/NJU-ProjectN/abstract-machine). 6 | 7 | The main features of NEMU include 8 | * a small monitor with a simple debugger 9 | * single step 10 | * register/memory examination 11 | * expression evaluation without the support of symbols 12 | * watch point 13 | * differential testing with reference design (e.g. QEMU) 14 | * snapshot 15 | * CPU core with support of most common used instructions 16 | * x86 17 | * real mode is not supported 18 | * x87 floating point instructions are not supported 19 | * mips32 20 | * CP1 floating point instructions are not supported 21 | * riscv32 22 | * only RV32IM 23 | * riscv64 24 | * only RV64IM 25 | * memory 26 | * paging 27 | * TLB is optional (but necessary for mips32) 28 | * protection is not supported 29 | * interrupt and exception 30 | * protection is not supported 31 | * 5 devices 32 | * serial, timer, keyboard, VGA, audio 33 | * most of them are simplified and unprogrammable 34 | * 2 types of I/O 35 | * port-mapped I/O and memory-mapped I/O 36 | -------------------------------------------------------------------------------- /nemu/configs/.gitignore: -------------------------------------------------------------------------------- 1 | !*_defconfig 2 | -------------------------------------------------------------------------------- /nemu/configs/riscv32-am_defconfig: -------------------------------------------------------------------------------- 1 | CONFIG_TARGET_AM=y 2 | CONFIG_MSIZE=0x2000000 3 | CONFIG_DEVICE=y 4 | -------------------------------------------------------------------------------- /nemu/configs/riscv64-am_defconfig: -------------------------------------------------------------------------------- 1 | CONFIG_ISA_riscv64=y 2 | CONFIG_TARGET_AM=y 3 | CONFIG_MSIZE=0x2000000 4 | CONFIG_DEVICE=y 5 | -------------------------------------------------------------------------------- /nemu/include/common.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __COMMON_H__ 17 | #define __COMMON_H__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #ifdef CONFIG_TARGET_AM 28 | #include 29 | #else 30 | #include 31 | #include 32 | #endif 33 | 34 | #if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul 35 | #define PMEM64 1 36 | #endif 37 | 38 | typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t; 39 | typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t; 40 | #define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016"PRIx64, "0x%08"PRIx32) 41 | 42 | typedef word_t vaddr_t; 43 | typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t; 44 | #define FMT_PADDR MUXDEF(PMEM64, "0x%016"PRIx64, "0x%08"PRIx32) 45 | typedef uint16_t ioaddr_t; 46 | 47 | #include 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /nemu/include/cpu/cpu.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __CPU_CPU_H__ 17 | #define __CPU_CPU_H__ 18 | 19 | #include 20 | 21 | void cpu_exec(uint64_t n); 22 | 23 | void set_nemu_state(int state, vaddr_t pc, int halt_ret); 24 | void invalid_inst(vaddr_t thispc); 25 | 26 | #define NEMUTRAP(thispc, code) set_nemu_state(NEMU_END, thispc, code) 27 | #define INV(thispc) invalid_inst(thispc) 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /nemu/include/cpu/difftest.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __CPU_DIFFTEST_H__ 17 | #define __CPU_DIFFTEST_H__ 18 | 19 | #include 20 | #include 21 | 22 | #ifdef CONFIG_DIFFTEST 23 | void difftest_skip_ref(); 24 | void difftest_skip_dut(int nr_ref, int nr_dut); 25 | void difftest_set_patch(void (*fn)(void *arg), void *arg); 26 | void difftest_step(vaddr_t pc, vaddr_t npc); 27 | void difftest_detach(); 28 | void difftest_attach(); 29 | #else 30 | static inline void difftest_skip_ref() {} 31 | static inline void difftest_skip_dut(int nr_ref, int nr_dut) {} 32 | static inline void difftest_set_patch(void (*fn)(void *arg), void *arg) {} 33 | static inline void difftest_step(vaddr_t pc, vaddr_t npc) {} 34 | static inline void difftest_detach() {} 35 | static inline void difftest_attach() {} 36 | #endif 37 | 38 | extern void (*ref_difftest_memcpy)(paddr_t addr, void *buf, size_t n, bool direction); 39 | extern void (*ref_difftest_regcpy)(void *dut, bool direction); 40 | extern void (*ref_difftest_exec)(uint64_t n); 41 | extern void (*ref_difftest_raise_intr)(uint64_t NO); 42 | 43 | static inline bool difftest_check_reg(const char *name, vaddr_t pc, word_t ref, word_t dut) { 44 | if (ref != dut) { 45 | Log("%s is different after executing instruction at pc = " FMT_WORD 46 | ", right = " FMT_WORD ", wrong = " FMT_WORD ", diff = " FMT_WORD, 47 | name, pc, ref, dut, ref ^ dut); 48 | return false; 49 | } 50 | return true; 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /nemu/include/cpu/ifetch.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __CPU_IFETCH_H__ 17 | 18 | #include 19 | 20 | static inline uint32_t inst_fetch(vaddr_t *pc, int len) { 21 | uint32_t inst = vaddr_ifetch(*pc, len); 22 | (*pc) += len; 23 | return inst; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /nemu/include/debug.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __DEBUG_H__ 17 | #define __DEBUG_H__ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define Log(format, ...) \ 24 | _Log(ANSI_FMT("[%s:%d %s] " format, ANSI_FG_BLUE) "\n", \ 25 | __FILE__, __LINE__, __func__, ## __VA_ARGS__) 26 | 27 | #define Assert(cond, format, ...) \ 28 | do { \ 29 | if (!(cond)) { \ 30 | MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \ 31 | (fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \ 32 | IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \ 33 | extern void assert_fail_msg(); \ 34 | assert_fail_msg(); \ 35 | assert(cond); \ 36 | } \ 37 | } while (0) 38 | 39 | #define panic(format, ...) Assert(0, format, ## __VA_ARGS__) 40 | 41 | #define TODO() panic("please implement me") 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /nemu/include/device/alarm.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __DEVICE_ALARM_H__ 17 | #define __DEVICE_ALARM_H__ 18 | 19 | #define TIMER_HZ 60 20 | 21 | typedef void (*alarm_handler_t) (); 22 | void add_alarm_handle(alarm_handler_t h); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /nemu/include/device/map.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __DEVICE_MAP_H__ 17 | #define __DEVICE_MAP_H__ 18 | 19 | #include 20 | 21 | typedef void(*io_callback_t)(uint32_t, int, bool); 22 | uint8_t* new_space(int size); 23 | 24 | typedef struct { 25 | const char *name; 26 | // we treat ioaddr_t as paddr_t here 27 | paddr_t low; 28 | paddr_t high; 29 | void *space; 30 | io_callback_t callback; 31 | } IOMap; 32 | 33 | static inline bool map_inside(IOMap *map, paddr_t addr) { 34 | return (addr >= map->low && addr <= map->high); 35 | } 36 | 37 | static inline int find_mapid_by_addr(IOMap *maps, int size, paddr_t addr) { 38 | int i; 39 | for (i = 0; i < size; i ++) { 40 | if (map_inside(maps + i, addr)) { 41 | difftest_skip_ref(); 42 | return i; 43 | } 44 | } 45 | return -1; 46 | } 47 | 48 | void add_pio_map(const char *name, ioaddr_t addr, 49 | void *space, uint32_t len, io_callback_t callback); 50 | void add_mmio_map(const char *name, paddr_t addr, 51 | void *space, uint32_t len, io_callback_t callback); 52 | 53 | word_t map_read(paddr_t addr, int len, IOMap *map); 54 | void map_write(paddr_t addr, int len, word_t data, IOMap *map); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /nemu/include/device/mmio.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __DEVICE_MMIO_H__ 17 | #define __DEVICE_MMIO_H__ 18 | 19 | #include 20 | 21 | word_t mmio_read(paddr_t addr, int len); 22 | void mmio_write(paddr_t addr, int len, word_t data); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /nemu/include/difftest-def.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __DIFFTEST_DEF_H__ 17 | #define __DIFFTEST_DEF_H__ 18 | 19 | #include 20 | #include 21 | 22 | enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF }; 23 | 24 | #if defined(CONFIG_ISA_x86) 25 | # define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 9) // GPRs + pc 26 | #elif defined(CONFIG_ISA_mips32) 27 | # define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 38) // GRPs + status + lo + hi + badvaddr + cause + pc 28 | #elif defined(CONFIG_ISA_riscv32) 29 | # define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 33) // GRPs + pc 30 | #elif defined(CONFIG_ISA_riscv64) 31 | # define DIFFTEST_REG_SIZE (sizeof(uint64_t) * 33) // GRPs + pc 32 | #else 33 | # error Unsupport ISA 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /nemu/include/isa.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __ISA_H__ 17 | #define __ISA_H__ 18 | 19 | // Located at src/isa/$(GUEST_ISA)/include/isa-def.h 20 | #include 21 | 22 | // The macro `__GUEST_ISA__` is defined in $(CFLAGS). 23 | // It will be expanded as "x86" or "mips32" ... 24 | typedef concat(__GUEST_ISA__, _CPU_state) CPU_state; 25 | typedef concat(__GUEST_ISA__, _ISADecodeInfo) ISADecodeInfo; 26 | 27 | // monitor 28 | extern char isa_logo[]; 29 | void init_isa(); 30 | 31 | // reg 32 | extern CPU_state cpu; 33 | void isa_reg_display(); 34 | word_t isa_reg_str2val(const char *name, bool *success); 35 | 36 | // exec 37 | struct Decode; 38 | int isa_exec_once(struct Decode *s); 39 | 40 | // memory 41 | enum { MMU_DIRECT, MMU_TRANSLATE, MMU_FAIL }; 42 | enum { MEM_TYPE_IFETCH, MEM_TYPE_READ, MEM_TYPE_WRITE }; 43 | enum { MEM_RET_OK, MEM_RET_FAIL, MEM_RET_CROSS_PAGE }; 44 | #ifndef isa_mmu_check 45 | int isa_mmu_check(vaddr_t vaddr, int len, int type); 46 | #endif 47 | paddr_t isa_mmu_translate(vaddr_t vaddr, int len, int type); 48 | 49 | // interrupt/exception 50 | vaddr_t isa_raise_intr(word_t NO, vaddr_t epc); 51 | #define INTR_EMPTY ((word_t)-1) 52 | word_t isa_query_intr(); 53 | 54 | // difftest 55 | bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc); 56 | void isa_difftest_attach(); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /nemu/include/memory/host.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __MEMORY_HOST_H__ 17 | #define __MEMORY_HOST_H__ 18 | 19 | #include 20 | 21 | static inline word_t host_read(void *addr, int len) { 22 | switch (len) { 23 | case 1: return *(uint8_t *)addr; 24 | case 2: return *(uint16_t *)addr; 25 | case 4: return *(uint32_t *)addr; 26 | IFDEF(CONFIG_ISA64, case 8: return *(uint64_t *)addr); 27 | default: MUXDEF(CONFIG_RT_CHECK, assert(0), return 0); 28 | } 29 | } 30 | 31 | static inline void host_write(void *addr, int len, word_t data) { 32 | switch (len) { 33 | case 1: *(uint8_t *)addr = data; return; 34 | case 2: *(uint16_t *)addr = data; return; 35 | case 4: *(uint32_t *)addr = data; return; 36 | IFDEF(CONFIG_ISA64, case 8: *(uint64_t *)addr = data; return); 37 | IFDEF(CONFIG_RT_CHECK, default: assert(0)); 38 | } 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /nemu/include/memory/paddr.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __MEMORY_PADDR_H__ 17 | #define __MEMORY_PADDR_H__ 18 | 19 | #include 20 | 21 | #define PMEM_LEFT ((paddr_t)CONFIG_MBASE) 22 | #define PMEM_RIGHT ((paddr_t)CONFIG_MBASE + CONFIG_MSIZE - 1) 23 | #define RESET_VECTOR (PMEM_LEFT + CONFIG_PC_RESET_OFFSET) 24 | 25 | /* convert the guest physical address in the guest program to host virtual address in NEMU */ 26 | uint8_t* guest_to_host(paddr_t paddr); 27 | /* convert the host virtual address in NEMU to guest physical address in the guest program */ 28 | paddr_t host_to_guest(uint8_t *haddr); 29 | 30 | static inline bool in_pmem(paddr_t addr) { 31 | return addr - CONFIG_MBASE < CONFIG_MSIZE; 32 | } 33 | 34 | word_t paddr_read(paddr_t addr, int len); 35 | void paddr_write(paddr_t addr, int len, word_t data); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /nemu/include/memory/vaddr.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __MEMORY_VADDR_H__ 17 | #define __MEMORY_VADDR_H__ 18 | 19 | #include 20 | 21 | word_t vaddr_ifetch(vaddr_t addr, int len); 22 | word_t vaddr_read(vaddr_t addr, int len); 23 | void vaddr_write(vaddr_t addr, int len, word_t data); 24 | 25 | #define PAGE_SHIFT 12 26 | #define PAGE_SIZE (1ul << PAGE_SHIFT) 27 | #define PAGE_MASK (PAGE_SIZE - 1) 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /nemu/include/utils.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __UTILS_H__ 17 | #define __UTILS_H__ 18 | 19 | #include 20 | 21 | // ----------- state ----------- 22 | 23 | enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT }; 24 | 25 | typedef struct { 26 | int state; 27 | vaddr_t halt_pc; 28 | uint32_t halt_ret; 29 | } NEMUState; 30 | 31 | extern NEMUState nemu_state; 32 | 33 | // ----------- timer ----------- 34 | 35 | uint64_t get_time(); 36 | 37 | // ----------- log ----------- 38 | 39 | #define ANSI_FG_BLACK "\33[1;30m" 40 | #define ANSI_FG_RED "\33[1;31m" 41 | #define ANSI_FG_GREEN "\33[1;32m" 42 | #define ANSI_FG_YELLOW "\33[1;33m" 43 | #define ANSI_FG_BLUE "\33[1;34m" 44 | #define ANSI_FG_MAGENTA "\33[1;35m" 45 | #define ANSI_FG_CYAN "\33[1;36m" 46 | #define ANSI_FG_WHITE "\33[1;37m" 47 | #define ANSI_BG_BLACK "\33[1;40m" 48 | #define ANSI_BG_RED "\33[1;41m" 49 | #define ANSI_BG_GREEN "\33[1;42m" 50 | #define ANSI_BG_YELLOW "\33[1;43m" 51 | #define ANSI_BG_BLUE "\33[1;44m" 52 | #define ANSI_BG_MAGENTA "\33[1;35m" 53 | #define ANSI_BG_CYAN "\33[1;46m" 54 | #define ANSI_BG_WHITE "\33[1;47m" 55 | #define ANSI_NONE "\33[0m" 56 | 57 | #define ANSI_FMT(str, fmt) fmt str ANSI_NONE 58 | 59 | #define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \ 60 | do { \ 61 | extern FILE* log_fp; \ 62 | extern bool log_enable(); \ 63 | if (log_enable()) { \ 64 | fprintf(log_fp, __VA_ARGS__); \ 65 | fflush(log_fp); \ 66 | } \ 67 | } while (0) \ 68 | ) 69 | 70 | #define _Log(...) \ 71 | do { \ 72 | printf(__VA_ARGS__); \ 73 | log_write(__VA_ARGS__); \ 74 | } while (0) 75 | 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /nemu/resource/mips-elf/README.md: -------------------------------------------------------------------------------- 1 | This is a dummy ELF file used by qemu-system-mips32 to start. 2 | -------------------------------------------------------------------------------- /nemu/resource/sdcard/README.md: -------------------------------------------------------------------------------- 1 | 2 | # NEMU sdhost驱动 3 | 4 | 本驱动裁剪自`linux/drivers/mmc/host/bcm2835.c`, 去除了DMA和中断, 改成直接轮询, 处理器无需支持DMA和中断即可运行. 5 | 6 | ## 使用方法 7 | 8 | * 将本目录下的`nemu.c`复制到`linux/drivers/mmc/host/`目录下 9 | * 在`linux/drivers/mmc/host/Makefile`中添加一行`obj-y += nemu.o` 10 | * 在menuconfig中取消`General setup -> Initial RAM filesystem and RAM disk (initramfs/initrd) support` 11 | * 在menuconfig中选中`Device Drivers -> MMC/SD/SDIO card support` 12 | * 在dts中加入以下节点 13 | ``` 14 | / { 15 | soc { 16 | sdhci: mmc { 17 | compatible = "nemu-sdhost"; 18 | reg = <0x0 0xa3000000 0x0 0x1000>; 19 | }; 20 | }; 21 | 22 | chosen { 23 | bootargs = "root=/dev/mmcblk0p1 rootfstype=ext4 ro rootwait earlycon"; 24 | }; 25 | }; 26 | ``` 27 | 28 | ## 在没有中断的处理器上访问SD卡 29 | 30 | 访问真实的SD卡需要等待一定的延迟, 这需要处理器的中断机制对内核支持计时的功能. 31 | 在没有中断机制的处理器上, 我们可以修改内核的部分代码, 使得无需等待这些延迟, 32 | 来达到确定性可重复的仿真效果. 33 | 34 | 具体只需修改以下文件: 35 | ```diff 36 | --- linux/drivers/mmc/core/block.c 37 | +++ linux/drivers/mmc/core/block.c 38 | @@ -983,6 +983,7 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, 39 | int err = 0; 40 | u32 status; 41 | 42 | + return err; 43 | do { 44 | bool done = time_after(jiffies, timeout); 45 | 46 | --- linux/drivers/mmc/core/core.h 47 | +++ linux/drivers/mmc/core/core.h 48 | @@ -64,6 +64,7 @@ void mmc_set_initial_state(struct mmc_host *host); 49 | 50 | static inline void mmc_delay(unsigned int ms) 51 | { 52 | + return; 53 | if (ms <= 20) 54 | usleep_range(ms * 1000, ms * 1250); 55 | else 56 | ``` 57 | 58 | 注意: 上述修改仅能用于模拟和仿真, 修改后将不能在真实的SD卡上运行!!! 59 | -------------------------------------------------------------------------------- /nemu/scripts/build.mk: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL = app 2 | 3 | # Add necessary options if the target is a shared library 4 | ifeq ($(SHARE),1) 5 | SO = -so 6 | CFLAGS += -fPIC 7 | LDFLAGS += -rdynamic -shared -fPIC 8 | endif 9 | 10 | WORK_DIR = $(shell pwd) 11 | BUILD_DIR = $(WORK_DIR)/build 12 | 13 | INC_PATH := $(WORK_DIR)/include $(INC_PATH) 14 | OBJ_DIR = $(BUILD_DIR)/obj-$(NAME)$(SO) 15 | BINARY = $(BUILD_DIR)/$(NAME)$(SO) 16 | 17 | # Compilation flags 18 | ifeq ($(CC),clang) 19 | CXX := clang++ 20 | else 21 | CXX := g++ 22 | endif 23 | LD := $(CXX) 24 | INCLUDES = $(addprefix -I, $(INC_PATH)) 25 | CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS) 26 | LDFLAGS := -O2 $(LDFLAGS) 27 | 28 | OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o) 29 | 30 | # Compilation patterns 31 | $(OBJ_DIR)/%.o: %.c 32 | @echo + CC $< 33 | @mkdir -p $(dir $@) 34 | @$(CC) $(CFLAGS) -c -o $@ $< 35 | $(call call_fixdep, $(@:.o=.d), $@) 36 | 37 | $(OBJ_DIR)/%.o: %.cc 38 | @echo + CXX $< 39 | @mkdir -p $(dir $@) 40 | @$(CXX) $(CFLAGS) $(CXXFLAGS) -c -o $@ $< 41 | $(call call_fixdep, $(@:.o=.d), $@) 42 | 43 | # Depencies 44 | -include $(OBJS:.o=.d) 45 | 46 | # Some convenient rules 47 | 48 | .PHONY: app clean 49 | 50 | app: $(BINARY) 51 | 52 | $(BINARY): $(OBJS) $(ARCHIVES) 53 | @echo + LD $@ 54 | @$(LD) -o $@ $(OBJS) $(LDFLAGS) $(ARCHIVES) $(LIBS) 55 | 56 | clean: 57 | -rm -rf $(BUILD_DIR) 58 | -------------------------------------------------------------------------------- /nemu/scripts/config.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | COLOR_RED := $(shell echo "\033[1;31m") 17 | COLOR_END := $(shell echo "\033[0m") 18 | 19 | ifeq ($(wildcard .config),) 20 | $(warning $(COLOR_RED)Warning: .config does not exists!$(COLOR_END)) 21 | $(warning $(COLOR_RED)To build the project, first run 'make menuconfig'.$(COLOR_END)) 22 | endif 23 | 24 | Q := @ 25 | KCONFIG_PATH := $(NEMU_HOME)/tools/kconfig 26 | FIXDEP_PATH := $(NEMU_HOME)/tools/fixdep 27 | Kconfig := $(NEMU_HOME)/Kconfig 28 | rm-distclean += include/generated include/config .config .config.old 29 | silent := -s 30 | 31 | CONF := $(KCONFIG_PATH)/build/conf 32 | MCONF := $(KCONFIG_PATH)/build/mconf 33 | FIXDEP := $(FIXDEP_PATH)/build/fixdep 34 | 35 | $(CONF): 36 | $(Q)$(MAKE) $(silent) -C $(KCONFIG_PATH) NAME=conf 37 | 38 | $(MCONF): 39 | $(Q)$(MAKE) $(silent) -C $(KCONFIG_PATH) NAME=mconf 40 | 41 | $(FIXDEP): 42 | $(Q)$(MAKE) $(silent) -C $(FIXDEP_PATH) 43 | 44 | menuconfig: $(MCONF) $(CONF) $(FIXDEP) 45 | $(Q)$(MCONF) $(Kconfig) 46 | $(Q)$(CONF) $(silent) --syncconfig $(Kconfig) 47 | 48 | savedefconfig: $(CONF) 49 | $(Q)$< $(silent) --$@=configs/defconfig $(Kconfig) 50 | 51 | %defconfig: $(CONF) $(FIXDEP) 52 | $(Q)$< $(silent) --defconfig=configs/$@ $(Kconfig) 53 | $(Q)$< $(silent) --syncconfig $(Kconfig) 54 | 55 | .PHONY: menuconfig savedefconfig defconfig 56 | 57 | # Help text used by make help 58 | help: 59 | @echo ' menuconfig - Update current config utilising a menu based program' 60 | @echo ' savedefconfig - Save current config as configs/defconfig (minimal config)' 61 | 62 | distclean: clean 63 | -@rm -rf $(rm-distclean) 64 | 65 | .PHONY: help distclean 66 | 67 | define call_fixdep 68 | @$(FIXDEP) $(1) $(2) unused > $(1).tmp 69 | @mv $(1).tmp $(1) 70 | endef 71 | -------------------------------------------------------------------------------- /nemu/scripts/native.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | -include $(NEMU_HOME)/../Makefile 17 | include $(NEMU_HOME)/scripts/build.mk 18 | 19 | include $(NEMU_HOME)/tools/difftest.mk 20 | 21 | compile_git: 22 | $(call git_commit, "compile NEMU") 23 | $(BINARY): compile_git 24 | 25 | # Some convenient rules 26 | 27 | override ARGS ?= --log=$(BUILD_DIR)/nemu-log.txt 28 | override ARGS += $(ARGS_DIFF) 29 | 30 | # Command to execute NEMU 31 | IMG ?= 32 | NEMU_EXEC := $(BINARY) $(ARGS) $(IMG) 33 | 34 | run-env: $(BINARY) $(DIFF_REF_SO) 35 | 36 | run: run-env 37 | $(call git_commit, "run NEMU") 38 | $(NEMU_EXEC) 39 | 40 | gdb: run-env 41 | $(call git_commit, "gdb NEMU") 42 | gdb -s $(BINARY) --args $(NEMU_EXEC) 43 | 44 | clean-tools = $(dir $(shell find ./tools -maxdepth 2 -mindepth 2 -name "Makefile")) 45 | $(clean-tools): 46 | -@$(MAKE) -s -C $@ clean 47 | clean-tools: $(clean-tools) 48 | clean-all: clean distclean clean-tools 49 | 50 | .PHONY: run gdb run-env clean-tools clean-all $(clean-tools) 51 | -------------------------------------------------------------------------------- /nemu/src/am-bin.S: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | .section .rodata 17 | .globl bin_start, bin_end 18 | bin_start: 19 | #ifdef BIN_PATH 20 | .incbin BIN_PATH 21 | #endif 22 | bin_end: 23 | -------------------------------------------------------------------------------- /nemu/src/cpu/difftest/ref.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void difftest_memcpy(paddr_t addr, void *buf, size_t n, bool direction) { 22 | assert(0); 23 | } 24 | 25 | void difftest_regcpy(void *dut, bool direction) { 26 | assert(0); 27 | } 28 | 29 | void difftest_exec(uint64_t n) { 30 | assert(0); 31 | } 32 | 33 | void difftest_raise_intr(word_t NO) { 34 | assert(0); 35 | } 36 | 37 | void difftest_init(int port) { 38 | /* Perform ISA dependent initialization. */ 39 | init_isa(); 40 | } 41 | -------------------------------------------------------------------------------- /nemu/src/device/alarm.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define MAX_HANDLER 8 22 | 23 | static alarm_handler_t handler[MAX_HANDLER] = {}; 24 | static int idx = 0; 25 | 26 | void add_alarm_handle(alarm_handler_t h) { 27 | assert(idx < MAX_HANDLER); 28 | handler[idx ++] = h; 29 | } 30 | 31 | static void alarm_sig_handler(int signum) { 32 | int i; 33 | for (i = 0; i < idx; i ++) { 34 | handler[i](); 35 | } 36 | } 37 | 38 | void init_alarm() { 39 | struct sigaction s; 40 | memset(&s, 0, sizeof(s)); 41 | s.sa_handler = alarm_sig_handler; 42 | int ret = sigaction(SIGVTALRM, &s, NULL); 43 | Assert(ret == 0, "Can not set signal handler"); 44 | 45 | struct itimerval it = {}; 46 | it.it_value.tv_sec = 0; 47 | it.it_value.tv_usec = 1000000 / TIMER_HZ; 48 | it.it_interval = it.it_value; 49 | ret = setitimer(ITIMER_VIRTUAL, &it, NULL); 50 | Assert(ret == 0, "Can not set timer"); 51 | } 52 | -------------------------------------------------------------------------------- /nemu/src/device/audio.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | enum { 21 | reg_freq, 22 | reg_channels, 23 | reg_samples, 24 | reg_sbuf_size, 25 | reg_init, 26 | reg_count, 27 | nr_reg 28 | }; 29 | 30 | static uint8_t *sbuf = NULL; 31 | static uint32_t *audio_base = NULL; 32 | 33 | static void audio_io_handler(uint32_t offset, int len, bool is_write) { 34 | } 35 | 36 | void init_audio() { 37 | uint32_t space_size = sizeof(uint32_t) * nr_reg; 38 | audio_base = (uint32_t *)new_space(space_size); 39 | #ifdef CONFIG_HAS_PORT_IO 40 | add_pio_map ("audio", CONFIG_AUDIO_CTL_PORT, audio_base, space_size, audio_io_handler); 41 | #else 42 | add_mmio_map("audio", CONFIG_AUDIO_CTL_MMIO, audio_base, space_size, audio_io_handler); 43 | #endif 44 | 45 | sbuf = (uint8_t *)new_space(CONFIG_SB_SIZE); 46 | add_mmio_map("audio-sbuf", CONFIG_SB_ADDR, sbuf, CONFIG_SB_SIZE, NULL); 47 | } 48 | -------------------------------------------------------------------------------- /nemu/src/device/device.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | #ifndef CONFIG_TARGET_AM 20 | #include 21 | #endif 22 | 23 | void init_map(); 24 | void init_serial(); 25 | void init_timer(); 26 | void init_vga(); 27 | void init_i8042(); 28 | void init_audio(); 29 | void init_disk(); 30 | void init_sdcard(); 31 | void init_alarm(); 32 | 33 | void send_key(uint8_t, bool); 34 | void vga_update_screen(); 35 | 36 | void device_update() { 37 | static uint64_t last = 0; 38 | uint64_t now = get_time(); 39 | if (now - last < 1000000 / TIMER_HZ) { 40 | return; 41 | } 42 | last = now; 43 | 44 | IFDEF(CONFIG_HAS_VGA, vga_update_screen()); 45 | 46 | #ifndef CONFIG_TARGET_AM 47 | SDL_Event event; 48 | while (SDL_PollEvent(&event)) { 49 | switch (event.type) { 50 | case SDL_QUIT: 51 | nemu_state.state = NEMU_QUIT; 52 | break; 53 | #ifdef CONFIG_HAS_KEYBOARD 54 | // If a key was pressed 55 | case SDL_KEYDOWN: 56 | case SDL_KEYUP: { 57 | uint8_t k = event.key.keysym.scancode; 58 | bool is_keydown = (event.key.type == SDL_KEYDOWN); 59 | send_key(k, is_keydown); 60 | break; 61 | } 62 | #endif 63 | default: break; 64 | } 65 | } 66 | #endif 67 | } 68 | 69 | void sdl_clear_event_queue() { 70 | #ifndef CONFIG_TARGET_AM 71 | SDL_Event event; 72 | while (SDL_PollEvent(&event)); 73 | #endif 74 | } 75 | 76 | void init_device() { 77 | IFDEF(CONFIG_TARGET_AM, ioe_init()); 78 | init_map(); 79 | 80 | IFDEF(CONFIG_HAS_SERIAL, init_serial()); 81 | IFDEF(CONFIG_HAS_TIMER, init_timer()); 82 | IFDEF(CONFIG_HAS_VGA, init_vga()); 83 | IFDEF(CONFIG_HAS_KEYBOARD, init_i8042()); 84 | IFDEF(CONFIG_HAS_AUDIO, init_audio()); 85 | IFDEF(CONFIG_HAS_DISK, init_disk()); 86 | IFDEF(CONFIG_HAS_SDCARD, init_sdcard()); 87 | 88 | IFNDEF(CONFIG_TARGET_AM, init_alarm()); 89 | } 90 | -------------------------------------------------------------------------------- /nemu/src/device/disk.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | void init_disk() { 19 | } 20 | -------------------------------------------------------------------------------- /nemu/src/device/filelist.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | DIRS-y += src/device/io 17 | SRCS-$(CONFIG_DEVICE) += src/device/device.c src/device/alarm.c src/device/intr.c 18 | SRCS-$(CONFIG_HAS_SERIAL) += src/device/serial.c 19 | SRCS-$(CONFIG_HAS_TIMER) += src/device/timer.c 20 | SRCS-$(CONFIG_HAS_KEYBOARD) += src/device/keyboard.c 21 | SRCS-$(CONFIG_HAS_VGA) += src/device/vga.c 22 | SRCS-$(CONFIG_HAS_AUDIO) += src/device/audio.c 23 | SRCS-$(CONFIG_HAS_DISK) += src/device/disk.c 24 | SRCS-$(CONFIG_HAS_SDCARD) += src/device/sdcard.c 25 | 26 | SRCS-BLACKLIST-$(CONFIG_TARGET_AM) += src/device/alarm.c 27 | 28 | ifdef CONFIG_DEVICE 29 | ifndef CONFIG_TARGET_AM 30 | LIBS += -lSDL2 31 | endif 32 | endif 33 | -------------------------------------------------------------------------------- /nemu/src/device/intr.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | void dev_raise_intr() { 19 | } 20 | -------------------------------------------------------------------------------- /nemu/src/device/io/map.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define IO_SPACE_MAX (2 * 1024 * 1024) 22 | 23 | static uint8_t *io_space = NULL; 24 | static uint8_t *p_space = NULL; 25 | 26 | uint8_t* new_space(int size) { 27 | uint8_t *p = p_space; 28 | // page aligned; 29 | size = (size + (PAGE_SIZE - 1)) & ~PAGE_MASK; 30 | p_space += size; 31 | assert(p_space - io_space < IO_SPACE_MAX); 32 | return p; 33 | } 34 | 35 | static void check_bound(IOMap *map, paddr_t addr) { 36 | if (map == NULL) { 37 | Assert(map != NULL, "address (" FMT_PADDR ") is out of bound at pc = " FMT_WORD, addr, cpu.pc); 38 | } else { 39 | Assert(addr <= map->high && addr >= map->low, 40 | "address (" FMT_PADDR ") is out of bound {%s} [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD, 41 | addr, map->name, map->low, map->high, cpu.pc); 42 | } 43 | } 44 | 45 | static void invoke_callback(io_callback_t c, paddr_t offset, int len, bool is_write) { 46 | if (c != NULL) { c(offset, len, is_write); } 47 | } 48 | 49 | void init_map() { 50 | io_space = malloc(IO_SPACE_MAX); 51 | assert(io_space); 52 | p_space = io_space; 53 | } 54 | 55 | word_t map_read(paddr_t addr, int len, IOMap *map) { 56 | assert(len >= 1 && len <= 8); 57 | check_bound(map, addr); 58 | paddr_t offset = addr - map->low; 59 | invoke_callback(map->callback, offset, len, false); // prepare data to read 60 | word_t ret = host_read(map->space + offset, len); 61 | return ret; 62 | } 63 | 64 | void map_write(paddr_t addr, int len, word_t data, IOMap *map) { 65 | assert(len >= 1 && len <= 8); 66 | check_bound(map, addr); 67 | paddr_t offset = addr - map->low; 68 | host_write(map->space + offset, len, data); 69 | invoke_callback(map->callback, offset, len, true); 70 | } 71 | -------------------------------------------------------------------------------- /nemu/src/device/io/mmio.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | 19 | #define NR_MAP 16 20 | 21 | static IOMap maps[NR_MAP] = {}; 22 | static int nr_map = 0; 23 | 24 | static IOMap* fetch_mmio_map(paddr_t addr) { 25 | int mapid = find_mapid_by_addr(maps, nr_map, addr); 26 | return (mapid == -1 ? NULL : &maps[mapid]); 27 | } 28 | 29 | static void report_mmio_overlap(const char *name1, paddr_t l1, paddr_t r1, 30 | const char *name2, paddr_t l2, paddr_t r2) { 31 | panic("MMIO region %s@[" FMT_PADDR ", " FMT_PADDR "] is overlapped " 32 | "with %s@[" FMT_PADDR ", " FMT_PADDR "]", name1, l1, r1, name2, l2, r2); 33 | } 34 | 35 | /* device interface */ 36 | void add_mmio_map(const char *name, paddr_t addr, void *space, uint32_t len, io_callback_t callback) { 37 | assert(nr_map < NR_MAP); 38 | paddr_t left = addr, right = addr + len - 1; 39 | if (in_pmem(left) || in_pmem(right)) { 40 | report_mmio_overlap(name, left, right, "pmem", PMEM_LEFT, PMEM_RIGHT); 41 | } 42 | for (int i = 0; i < nr_map; i++) { 43 | if (left <= maps[i].high && right >= maps[i].low) { 44 | report_mmio_overlap(name, left, right, maps[i].name, maps[i].low, maps[i].high); 45 | } 46 | } 47 | 48 | maps[nr_map] = (IOMap){ .name = name, .low = addr, .high = addr + len - 1, 49 | .space = space, .callback = callback }; 50 | Log("Add mmio map '%s' at [" FMT_PADDR ", " FMT_PADDR "]", 51 | maps[nr_map].name, maps[nr_map].low, maps[nr_map].high); 52 | 53 | nr_map ++; 54 | } 55 | 56 | /* bus interface */ 57 | word_t mmio_read(paddr_t addr, int len) { 58 | return map_read(addr, len, fetch_mmio_map(addr)); 59 | } 60 | 61 | void mmio_write(paddr_t addr, int len, word_t data) { 62 | map_write(addr, len, data, fetch_mmio_map(addr)); 63 | } 64 | -------------------------------------------------------------------------------- /nemu/src/device/io/port-io.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | #define PORT_IO_SPACE_MAX 65535 19 | 20 | #define NR_MAP 16 21 | static IOMap maps[NR_MAP] = {}; 22 | static int nr_map = 0; 23 | 24 | /* device interface */ 25 | void add_pio_map(const char *name, ioaddr_t addr, void *space, uint32_t len, io_callback_t callback) { 26 | assert(nr_map < NR_MAP); 27 | assert(addr + len <= PORT_IO_SPACE_MAX); 28 | maps[nr_map] = (IOMap){ .name = name, .low = addr, .high = addr + len - 1, 29 | .space = space, .callback = callback }; 30 | Log("Add port-io map '%s' at [" FMT_PADDR ", " FMT_PADDR "]", 31 | maps[nr_map].name, maps[nr_map].low, maps[nr_map].high); 32 | 33 | nr_map ++; 34 | } 35 | 36 | /* CPU interface */ 37 | uint32_t pio_read(ioaddr_t addr, int len) { 38 | assert(addr + len - 1 < PORT_IO_SPACE_MAX); 39 | int mapid = find_mapid_by_addr(maps, nr_map, addr); 40 | assert(mapid != -1); 41 | return map_read(addr, len, &maps[mapid]); 42 | } 43 | 44 | void pio_write(ioaddr_t addr, int len, uint32_t data) { 45 | assert(addr + len - 1 < PORT_IO_SPACE_MAX); 46 | int mapid = find_mapid_by_addr(maps, nr_map, addr); 47 | assert(mapid != -1); 48 | map_write(addr, len, data, &maps[mapid]); 49 | } 50 | -------------------------------------------------------------------------------- /nemu/src/device/serial.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | 19 | /* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */ 20 | // NOTE: this is compatible to 16550 21 | 22 | #define CH_OFFSET 0 23 | 24 | static uint8_t *serial_base = NULL; 25 | 26 | 27 | static void serial_putc(char ch) { 28 | MUXDEF(CONFIG_TARGET_AM, putch(ch), putc(ch, stderr)); 29 | } 30 | 31 | static void serial_io_handler(uint32_t offset, int len, bool is_write) { 32 | assert(len == 1); 33 | switch (offset) { 34 | /* We bind the serial port with the host stderr in NEMU. */ 35 | case CH_OFFSET: 36 | if (is_write) serial_putc(serial_base[0]); 37 | else panic("do not support read"); 38 | break; 39 | default: panic("do not support offset = %d", offset); 40 | } 41 | } 42 | 43 | void init_serial() { 44 | serial_base = new_space(8); 45 | #ifdef CONFIG_HAS_PORT_IO 46 | add_pio_map ("serial", CONFIG_SERIAL_PORT, serial_base, 8, serial_io_handler); 47 | #else 48 | add_mmio_map("serial", CONFIG_SERIAL_MMIO, serial_base, 8, serial_io_handler); 49 | #endif 50 | 51 | } 52 | -------------------------------------------------------------------------------- /nemu/src/device/timer.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | static uint32_t *rtc_port_base = NULL; 21 | 22 | static void rtc_io_handler(uint32_t offset, int len, bool is_write) { 23 | assert(offset == 0 || offset == 4); 24 | if (!is_write && offset == 4) { 25 | uint64_t us = get_time(); 26 | rtc_port_base[0] = (uint32_t)us; 27 | rtc_port_base[1] = us >> 32; 28 | } 29 | } 30 | 31 | #ifndef CONFIG_TARGET_AM 32 | static void timer_intr() { 33 | if (nemu_state.state == NEMU_RUNNING) { 34 | extern void dev_raise_intr(); 35 | dev_raise_intr(); 36 | } 37 | } 38 | #endif 39 | 40 | void init_timer() { 41 | rtc_port_base = (uint32_t *)new_space(8); 42 | #ifdef CONFIG_HAS_PORT_IO 43 | add_pio_map ("rtc", CONFIG_RTC_PORT, rtc_port_base, 8, rtc_io_handler); 44 | #else 45 | add_mmio_map("rtc", CONFIG_RTC_MMIO, rtc_port_base, 8, rtc_io_handler); 46 | #endif 47 | IFNDEF(CONFIG_TARGET_AM, add_alarm_handle(timer_intr)); 48 | } 49 | -------------------------------------------------------------------------------- /nemu/src/engine/filelist.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | INC_PATH += $(NEMU_HOME)/src/engine/$(ENGINE) 17 | DIRS-y += src/engine/$(ENGINE) 18 | -------------------------------------------------------------------------------- /nemu/src/engine/interpreter/hostcall.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | void set_nemu_state(int state, vaddr_t pc, int halt_ret) { 22 | difftest_skip_ref(); 23 | nemu_state.state = state; 24 | nemu_state.halt_pc = pc; 25 | nemu_state.halt_ret = halt_ret; 26 | } 27 | 28 | __attribute__((noinline)) 29 | void invalid_inst(vaddr_t thispc) { 30 | uint32_t temp[2]; 31 | vaddr_t pc = thispc; 32 | temp[0] = inst_fetch(&pc, 4); 33 | temp[1] = inst_fetch(&pc, 4); 34 | 35 | uint8_t *p = (uint8_t *)temp; 36 | printf("invalid opcode(PC = " FMT_WORD "):\n" 37 | "\t%02x %02x %02x %02x %02x %02x %02x %02x ...\n" 38 | "\t%08x %08x...\n", 39 | thispc, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], temp[0], temp[1]); 40 | 41 | printf("There are two cases which will trigger this unexpected exception:\n" 42 | "1. The instruction at PC = " FMT_WORD " is not implemented.\n" 43 | "2. Something is implemented incorrectly.\n", thispc); 44 | printf("Find this PC(" FMT_WORD ") in the disassembling result to distinguish which case it is.\n\n", thispc); 45 | printf(ANSI_FMT("If it is the first case, see\n%s\nfor more details.\n\n" 46 | "If it is the second case, remember:\n" 47 | "* The machine is always right!\n" 48 | "* Every line of untested code is always wrong!\n\n", ANSI_FG_RED), isa_logo); 49 | 50 | set_nemu_state(NEMU_ABORT, thispc, -1); 51 | } 52 | -------------------------------------------------------------------------------- /nemu/src/engine/interpreter/init.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | void sdb_mainloop(); 19 | 20 | void engine_start() { 21 | #ifdef CONFIG_TARGET_AM 22 | cpu_exec(-1); 23 | #else 24 | /* Receive commands from user. */ 25 | sdb_mainloop(); 26 | #endif 27 | } 28 | -------------------------------------------------------------------------------- /nemu/src/filelist.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | SRCS-y += src/nemu-main.c 17 | DIRS-y += src/cpu src/monitor src/utils 18 | DIRS-$(CONFIG_MODE_SYSTEM) += src/memory 19 | DIRS-BLACKLIST-$(CONFIG_TARGET_AM) += src/monitor/sdb 20 | 21 | SHARE = $(if $(CONFIG_TARGET_SHARE),1,0) 22 | LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lreadline -ldl -pie,) 23 | 24 | ifdef mainargs 25 | ASFLAGS += -DBIN_PATH=\"$(mainargs)\" 26 | endif 27 | SRCS-$(CONFIG_TARGET_AM) += src/am-bin.S 28 | .PHONY: src/am-bin.S 29 | -------------------------------------------------------------------------------- /nemu/src/isa/filelist.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | INC_PATH += $(NEMU_HOME)/src/isa/$(GUEST_ISA)/include 17 | DIRS-y += src/isa/$(GUEST_ISA) 18 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv32/difftest/dut.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include "../local-include/reg.h" 19 | 20 | bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) { 21 | return false; 22 | } 23 | 24 | void isa_difftest_attach() { 25 | } 26 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv32/include/isa-def.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __ISA_RISCV32_H__ 17 | #define __ISA_RISCV32_H__ 18 | 19 | #include 20 | 21 | typedef struct { 22 | word_t gpr[32]; 23 | vaddr_t pc; 24 | } riscv32_CPU_state; 25 | 26 | // decode 27 | typedef struct { 28 | union { 29 | uint32_t val; 30 | } inst; 31 | } riscv32_ISADecodeInfo; 32 | 33 | #define isa_mmu_check(vaddr, len, type) (MMU_DIRECT) 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv32/init.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | 19 | // this is not consistent with uint8_t 20 | // but it is ok since we do not access the array directly 21 | static const uint32_t img [] = { 22 | 0x800002b7, // lui t0,0x80000 23 | 0x0002a023, // sw zero,0(t0) 24 | 0x0002a503, // lw a0,0(t0) 25 | 0x00100073, // ebreak (used as nemu_trap) 26 | }; 27 | 28 | static void restart() { 29 | /* Set the initial program counter. */ 30 | cpu.pc = RESET_VECTOR; 31 | 32 | /* The zero register is always 0. */ 33 | cpu.gpr[0] = 0; 34 | } 35 | 36 | void init_isa() { 37 | /* Load built-in image. */ 38 | memcpy(guest_to_host(RESET_VECTOR), img, sizeof(img)); 39 | 40 | /* Initialize this virtual computer system. */ 41 | restart(); 42 | } 43 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv32/local-include/reg.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __RISCV32_REG_H__ 17 | #define __RISCV32_REG_H__ 18 | 19 | #include 20 | 21 | static inline int check_reg_idx(int idx) { 22 | IFDEF(CONFIG_RT_CHECK, assert(idx >= 0 && idx < 32)); 23 | return idx; 24 | } 25 | 26 | #define gpr(idx) cpu.gpr[check_reg_idx(idx)] 27 | 28 | static inline const char* reg_name(int idx, int width) { 29 | extern const char* regs[]; 30 | return regs[check_reg_idx(idx)]; 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv32/reg.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include "local-include/reg.h" 18 | 19 | #define NR_REGS ARRLEN(regs) //sizeof(regs)/sizeof(regs[0]) 20 | 21 | 22 | const char *regs[] = { 23 | "$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 24 | "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 25 | "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 26 | "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" 27 | }; 28 | 29 | 30 | void isa_reg_display() { 31 | printf("%-15s%-17s%-15s\n", "Registers", "Hexadecimal", "Decimal"); 32 | for(int i = 0; i < NR_REGS; ++i){ 33 | printf("%-15s0x%-15x%-15d\n",regs[i], cpu.gpr[i], cpu.gpr[i]); 34 | } 35 | printf("%-15s0x%-15x%-15d\n","pc", cpu.pc, cpu.pc); 36 | } 37 | 38 | word_t isa_reg_str2val(const char *s, bool *success) { 39 | *success = false; 40 | for(int i = 0; i < NR_REGS; ++i ){ 41 | if(strcmp(regs[i], s+1) == 0){ 42 | *success = true; 43 | return cpu.gpr[i]; 44 | } 45 | } 46 | if(strcmp("pc", s+1) == 0){ 47 | *success = true; 48 | return cpu.pc; 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv32/system/intr.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | word_t isa_raise_intr(word_t NO, vaddr_t epc) { 19 | /* TODO: Trigger an interrupt/exception with ``NO''. 20 | * Then return the address of the interrupt/exception vector. 21 | */ 22 | 23 | return 0; 24 | } 25 | 26 | word_t isa_query_intr() { 27 | return INTR_EMPTY; 28 | } 29 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv32/system/mmu.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | paddr_t isa_mmu_translate(vaddr_t vaddr, int len, int type) { 21 | return MEM_RET_FAIL; 22 | } 23 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/difftest/dut.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include "../local-include/reg.h" 19 | 20 | bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) { 21 | return false; 22 | } 23 | 24 | void isa_difftest_attach() { 25 | } 26 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/include/isa-def.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __ISA_RISCV64_H__ 17 | #define __ISA_RISCV64_H__ 18 | 19 | #include 20 | 21 | typedef struct { 22 | word_t gpr[32]; 23 | vaddr_t pc; 24 | } riscv64_CPU_state; 25 | 26 | // decode 27 | typedef struct { 28 | union { 29 | uint32_t val; 30 | } inst; 31 | } riscv64_ISADecodeInfo; 32 | 33 | #define isa_mmu_check(vaddr, len, type) (MMU_DIRECT) 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/init.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | 19 | // this is not consistent with uint8_t 20 | // but it is ok since we do not access the array directly 21 | static const uint32_t img [] = { 22 | 0x00000297, // auipc t0,0 23 | 0x0002b823, // sd zero,16(t0) 24 | 0x0102b503, // ld a0,16(t0) 25 | 0x00100073, // ebreak (used as nemu_trap) 26 | 0xdeadbeef, // some data 27 | }; 28 | 29 | static void restart() { 30 | /* Set the initial program counter. */ 31 | cpu.pc = RESET_VECTOR; 32 | 33 | /* The zero register is always 0. */ 34 | cpu.gpr[0] = 0; 35 | } 36 | 37 | void init_isa() { 38 | /* Load built-in image. */ 39 | memcpy(guest_to_host(RESET_VECTOR), img, sizeof(img)); 40 | 41 | /* Initialize this virtual computer system. */ 42 | restart(); 43 | } 44 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/local-include/reg.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __RISCV64_REG_H__ 17 | #define __RISCV64_REG_H__ 18 | 19 | #include 20 | 21 | static inline int check_reg_idx(int idx) { 22 | IFDEF(CONFIG_RT_CHECK, assert(idx >= 0 && idx < 32)); 23 | return idx; 24 | } 25 | 26 | #define gpr(idx) (cpu.gpr[check_reg_idx(idx)]) 27 | 28 | static inline const char* reg_name(int idx, int width) { 29 | extern const char* regs[]; 30 | return regs[check_reg_idx(idx)]; 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/reg.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include "local-include/reg.h" 18 | 19 | const char *regs[] = { 20 | "$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 21 | "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 22 | "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 23 | "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" 24 | }; 25 | 26 | void isa_reg_display() { 27 | } 28 | 29 | word_t isa_reg_str2val(const char *s, bool *success) { 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/system/intr.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | word_t isa_raise_intr(word_t NO, vaddr_t epc) { 19 | /* TODO: Trigger an interrupt/exception with ``NO''. 20 | * Then return the address of the interrupt/exception vector. 21 | */ 22 | 23 | return 0; 24 | } 25 | 26 | word_t isa_query_intr() { 27 | return INTR_EMPTY; 28 | } 29 | -------------------------------------------------------------------------------- /nemu/src/isa/riscv64/system/mmu.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | paddr_t isa_mmu_translate(vaddr_t vaddr, int len, int type) { 21 | return MEM_RET_FAIL; 22 | } 23 | -------------------------------------------------------------------------------- /nemu/src/memory/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Memory Configuration" 2 | 3 | config MBASE 4 | hex "Memory base address" 5 | default 0x0 if ISA_x86 6 | default 0x80000000 7 | 8 | config MSIZE 9 | hex "Memory size" 10 | default 0x8000000 11 | 12 | config PC_RESET_OFFSET 13 | hex "Offset of reset vector from the base of memory" 14 | default 0x100000 if ISA_x86 15 | default 0 16 | 17 | choice 18 | prompt "Physical memory definition" 19 | default PMEM_GARRAY 20 | config PMEM_MALLOC 21 | bool "Using malloc()" 22 | config PMEM_GARRAY 23 | depends on !TARGET_AM 24 | bool "Using global array" 25 | endchoice 26 | 27 | config MEM_RANDOM 28 | depends on MODE_SYSTEM && !DIFFTEST && !TARGET_AM 29 | bool "Initialize the memory with random values" 30 | default y 31 | help 32 | This may help to find undefined behaviors. 33 | 34 | endmenu #MEMORY 35 | -------------------------------------------------------------------------------- /nemu/src/memory/paddr.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #if defined(CONFIG_PMEM_MALLOC) 22 | static uint8_t *pmem = NULL; 23 | #else // CONFIG_PMEM_GARRAY 24 | static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {}; 25 | #endif 26 | 27 | uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; } 28 | paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; } 29 | 30 | static word_t pmem_read(paddr_t addr, int len) { 31 | word_t ret = host_read(guest_to_host(addr), len); 32 | return ret; 33 | } 34 | 35 | static void pmem_write(paddr_t addr, int len, word_t data) { 36 | host_write(guest_to_host(addr), len, data); 37 | } 38 | 39 | static void out_of_bound(paddr_t addr) { 40 | panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD, 41 | addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc); 42 | } 43 | 44 | void init_mem() { 45 | #if defined(CONFIG_PMEM_MALLOC) 46 | pmem = malloc(CONFIG_MSIZE); 47 | assert(pmem); 48 | #endif 49 | #ifdef CONFIG_MEM_RANDOM 50 | uint32_t *p = (uint32_t *)pmem; 51 | int i; 52 | for (i = 0; i < (int) (CONFIG_MSIZE / sizeof(p[0])); i ++) { 53 | p[i] = rand(); 54 | } 55 | #endif 56 | Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT); 57 | } 58 | 59 | word_t paddr_read(paddr_t addr, int len) { 60 | if (likely(in_pmem(addr))) return pmem_read(addr, len); 61 | IFDEF(CONFIG_DEVICE, return mmio_read(addr, len)); 62 | out_of_bound(addr); 63 | return 0; 64 | } 65 | 66 | void paddr_write(paddr_t addr, int len, word_t data) { 67 | if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; } 68 | IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return); 69 | out_of_bound(addr); 70 | } 71 | -------------------------------------------------------------------------------- /nemu/src/memory/vaddr.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include 18 | 19 | word_t vaddr_ifetch(vaddr_t addr, int len) { 20 | return paddr_read(addr, len); 21 | } 22 | 23 | word_t vaddr_read(vaddr_t addr, int len) { 24 | return paddr_read(addr, len); 25 | } 26 | 27 | void vaddr_write(vaddr_t addr, int len, word_t data) { 28 | paddr_write(addr, len, data); 29 | } 30 | -------------------------------------------------------------------------------- /nemu/src/monitor/sdb/watchpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef __WATCHPOINT_H__ 2 | #define __WATCHPOINT_H__ 3 | 4 | #include 5 | 6 | typedef struct watchpoint {} WP; 7 | 8 | #endif -------------------------------------------------------------------------------- /nemu/src/nemu-main.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" 20 | 21 | word_t expr(char *e, bool *success); 22 | void init_monitor(int, char *[]); 23 | void am_init_monitor(); 24 | void engine_start(); 25 | int is_exit_status_bad(); 26 | 27 | //#define CALCULATION_TEST 28 | 29 | int main(int argc, char *argv[]) { 30 | /* Initialize the monitor. */ 31 | #ifdef CONFIG_TARGET_AM 32 | am_init_monitor(); 33 | #else 34 | init_monitor(argc, argv); 35 | #ifdef CALCULATION_TEST 36 | /************************************************************************************ 37 | * preserved to test if calculator works 38 | *************************************************************************************/ 39 | FILE * fp=fopen("tools/gen-expr/input","r"); 40 | char expression[70000]; 41 | char *str; 42 | char *unused; 43 | unsigned answer=0; 44 | unsigned ans; 45 | for(int i = 0;i < 100;i++){ 46 | bool flag=true; 47 | expression[0]='\0'; 48 | unused=fgets(expression,70000,fp); 49 | 50 | str = strtok(expression," "); 51 | sscanf(expression,"%u",&answer); 52 | str=expression+strlen(expression)+1; 53 | ans=expr(str,&flag); 54 | if(answer!=ans) 55 | printf("[%d] is wrong\n",i); 56 | else 57 | printf("[%d] is correct\n",i); 58 | } 59 | #endif 60 | #endif 61 | 62 | /* Start engine. */ 63 | engine_start(); 64 | 65 | return is_exit_status_bad(); 66 | } 67 | -------------------------------------------------------------------------------- /nemu/src/utils/filelist.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | ifdef CONFIG_ITRACE 17 | CXXSRC = src/utils/disasm.cc 18 | CXXFLAGS += $(shell llvm-config --cxxflags) -fPIE 19 | LIBS += $(shell llvm-config --libs) 20 | endif 21 | -------------------------------------------------------------------------------- /nemu/src/utils/log.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | extern uint64_t g_nr_guest_inst; 19 | FILE *log_fp = NULL; 20 | 21 | void init_log(const char *log_file) { 22 | log_fp = stdout; 23 | if (log_file != NULL) { 24 | FILE *fp = fopen(log_file, "w"); 25 | Assert(fp, "Can not open '%s'", log_file); 26 | log_fp = fp; 27 | } 28 | Log("Log is written to %s", log_file ? log_file : "stdout"); 29 | } 30 | 31 | bool log_enable() { 32 | return MUXDEF(CONFIG_TRACE, (g_nr_guest_inst >= CONFIG_TRACE_START) && 33 | (g_nr_guest_inst <= CONFIG_TRACE_END), false); 34 | } 35 | -------------------------------------------------------------------------------- /nemu/src/utils/rand.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #ifndef CONFIG_TARGET_AM 18 | #include 19 | #endif 20 | 21 | void init_rand() { 22 | srand(MUXDEF(CONFIG_TARGET_AM, 0, time(0))); 23 | } 24 | -------------------------------------------------------------------------------- /nemu/src/utils/state.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | 18 | NEMUState nemu_state = { .state = NEMU_STOP }; 19 | 20 | int is_exit_status_bad() { 21 | int good = (nemu_state.state == NEMU_END && nemu_state.halt_ret == 0) || 22 | (nemu_state.state == NEMU_QUIT); 23 | return !good; 24 | } 25 | -------------------------------------------------------------------------------- /nemu/src/utils/timer.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include 17 | #include MUXDEF(CONFIG_TIMER_GETTIMEOFDAY, , ) 18 | 19 | IFDEF(CONFIG_TIMER_CLOCK_GETTIME, 20 | static_assert(CLOCKS_PER_SEC == 1000000, "CLOCKS_PER_SEC != 1000000")); 21 | IFDEF(CONFIG_TIMER_CLOCK_GETTIME, 22 | static_assert(sizeof(clock_t) == 8, "sizeof(clock_t) != 8")); 23 | 24 | static uint64_t boot_time = 0; 25 | 26 | static uint64_t get_time_internal() { 27 | #if defined(CONFIG_TARGET_AM) 28 | uint64_t us = io_read(AM_TIMER_UPTIME).us; 29 | #elif defined(CONFIG_TIMER_GETTIMEOFDAY) 30 | struct timeval now; 31 | gettimeofday(&now, NULL); 32 | uint64_t us = now.tv_sec * 1000000 + now.tv_usec; 33 | #else 34 | struct timespec now; 35 | clock_gettime(CLOCK_MONOTONIC_COARSE, &now); 36 | uint64_t us = now.tv_sec * 1000000 + now.tv_nsec / 1000; 37 | #endif 38 | return us; 39 | } 40 | 41 | uint64_t get_time() { 42 | if (boot_time == 0) boot_time = get_time_internal(); 43 | uint64_t now = get_time_internal(); 44 | return now - boot_time; 45 | } 46 | -------------------------------------------------------------------------------- /nemu/tools/difftest.mk: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | ifdef CONFIG_DIFFTEST 17 | DIFF_REF_PATH = $(NEMU_HOME)/$(call remove_quote,$(CONFIG_DIFFTEST_REF_PATH)) 18 | DIFF_REF_SO = $(DIFF_REF_PATH)/build/$(GUEST_ISA)-$(call remove_quote,$(CONFIG_DIFFTEST_REF_NAME))-so 19 | MKFLAGS = GUEST_ISA=$(GUEST_ISA) SHARE=1 ENGINE=interpreter 20 | ARGS_DIFF = --diff=$(DIFF_REF_SO) 21 | 22 | ifndef CONFIG_DIFFTEST_REF_NEMU 23 | $(DIFF_REF_SO): 24 | $(MAKE) -s -C $(DIFF_REF_PATH) $(MKFLAGS) 25 | endif 26 | 27 | .PHONY: $(DIFF_REF_SO) 28 | endif 29 | -------------------------------------------------------------------------------- /nemu/tools/fixdep/Makefile: -------------------------------------------------------------------------------- 1 | NAME = fixdep 2 | SRCS = fixdep.c 3 | include $(NEMU_HOME)/scripts/build.mk 4 | -------------------------------------------------------------------------------- /nemu/tools/gen-expr/.gitignore: -------------------------------------------------------------------------------- 1 | .code.c 2 | -------------------------------------------------------------------------------- /nemu/tools/gen-expr/Makefile: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | NAME = gen-expr 17 | SRCS = gen-expr.c 18 | include $(NEMU_HOME)/scripts/build.mk 19 | -------------------------------------------------------------------------------- /nemu/tools/kconfig/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | !lexer.l 3 | !parser.y 4 | -------------------------------------------------------------------------------- /nemu/tools/kconfig/Makefile: -------------------------------------------------------------------------------- 1 | NAME = conf 2 | obj := build 3 | SRCS += confdata.c expr.c preprocess.c symbol.c util.c 4 | SRCS += $(obj)/lexer.lex.c $(obj)/parser.tab.c 5 | CC = gcc 6 | CFLAGS += -DYYDEBUG 7 | INC_PATH += . 8 | 9 | ifeq ($(NAME),conf) 10 | SRCS += conf.c 11 | else ifeq ($(NAME),mconf) 12 | SRCS += mconf.c $(shell find lxdialog/ -name "*.c") 13 | LIBS += -lncurses 14 | else 15 | $(error bad target=$(NAME)) 16 | endif 17 | 18 | include $(NEMU_HOME)/scripts/build.mk 19 | 20 | $(obj)/lexer.lex.o: $(obj)/parser.tab.h 21 | $(obj)/lexer.lex.c: lexer.l $(obj)/parser.tab.h 22 | @echo + LEX $@ 23 | @flex -o $@ $< 24 | 25 | $(obj)/parser.tab.c $(obj)/parser.tab.h: parser.y 26 | @echo + YACC $@ 27 | @bison -v $< --defines=$(obj)/parser.tab.h -o $(obj)/parser.tab.c 28 | 29 | conf: 30 | @$(MAKE) -s 31 | 32 | mconf: 33 | @$(MAKE) -s NAME=mconf 34 | 35 | .PHONY: conf mconf 36 | -------------------------------------------------------------------------------- /nemu/tools/kconfig/lkc_proto.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #include 3 | 4 | /* confdata.c */ 5 | void conf_parse(const char *name); 6 | int conf_read(const char *name); 7 | int conf_read_simple(const char *name, int); 8 | int conf_write_defconfig(const char *name); 9 | int conf_write(const char *name); 10 | int conf_write_autoconf(int overwrite); 11 | bool conf_get_changed(void); 12 | void conf_set_changed_callback(void (*fn)(void)); 13 | void conf_set_message_callback(void (*fn)(const char *s)); 14 | 15 | /* symbol.c */ 16 | extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; 17 | 18 | struct symbol * sym_lookup(const char *name, int flags); 19 | struct symbol * sym_find(const char *name); 20 | const char * sym_escape_string_value(const char *in); 21 | struct symbol ** sym_re_search(const char *pattern); 22 | const char * sym_type_name(enum symbol_type type); 23 | void sym_calc_value(struct symbol *sym); 24 | enum symbol_type sym_get_type(struct symbol *sym); 25 | bool sym_tristate_within_range(struct symbol *sym,tristate tri); 26 | bool sym_set_tristate_value(struct symbol *sym,tristate tri); 27 | tristate sym_toggle_tristate_value(struct symbol *sym); 28 | bool sym_string_valid(struct symbol *sym, const char *newval); 29 | bool sym_string_within_range(struct symbol *sym, const char *str); 30 | bool sym_set_string_value(struct symbol *sym, const char *newval); 31 | bool sym_is_changeable(struct symbol *sym); 32 | struct property * sym_get_choice_prop(struct symbol *sym); 33 | const char * sym_get_string_value(struct symbol *sym); 34 | 35 | const char * prop_get_type_name(enum prop_type type); 36 | 37 | /* preprocess.c */ 38 | enum variable_flavor { 39 | VAR_SIMPLE, 40 | VAR_RECURSIVE, 41 | VAR_APPEND, 42 | }; 43 | void env_write_dep(FILE *f, const char *auto_conf_name); 44 | void variable_add(const char *name, const char *value, 45 | enum variable_flavor flavor); 46 | void variable_all_del(void); 47 | char *expand_dollar(const char **str); 48 | char *expand_one_token(const char **str); 49 | 50 | /* expr.c */ 51 | void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); 52 | -------------------------------------------------------------------------------- /nemu/tools/kconfig/lxdialog/yesno.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0+ 2 | /* 3 | * yesno.c -- implements the yes/no box 4 | * 5 | * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 6 | * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) 7 | */ 8 | 9 | #include "dialog.h" 10 | 11 | /* 12 | * Display termination buttons 13 | */ 14 | static void print_buttons(WINDOW * dialog, int height, int width, int selected) 15 | { 16 | int x = width / 2 - 10; 17 | int y = height - 2; 18 | 19 | print_button(dialog, " Yes ", y, x, selected == 0); 20 | print_button(dialog, " No ", y, x + 13, selected == 1); 21 | 22 | wmove(dialog, y, x + 1 + 13 * selected); 23 | wrefresh(dialog); 24 | } 25 | 26 | /* 27 | * Display a dialog box with two buttons - Yes and No 28 | */ 29 | int dialog_yesno(const char *title, const char *prompt, int height, int width) 30 | { 31 | int i, x, y, key = 0, button = 0; 32 | WINDOW *dialog; 33 | 34 | do_resize: 35 | if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN)) 36 | return -ERRDISPLAYTOOSMALL; 37 | if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) 38 | return -ERRDISPLAYTOOSMALL; 39 | 40 | /* center dialog box on screen */ 41 | x = (getmaxx(stdscr) - width) / 2; 42 | y = (getmaxy(stdscr) - height) / 2; 43 | 44 | draw_shadow(stdscr, y, x, height, width); 45 | 46 | dialog = newwin(height, width, y, x); 47 | keypad(dialog, TRUE); 48 | 49 | draw_box(dialog, 0, 0, height, width, 50 | dlg.dialog.atr, dlg.border.atr); 51 | wattrset(dialog, dlg.border.atr); 52 | mvwaddch(dialog, height - 3, 0, ACS_LTEE); 53 | for (i = 0; i < width - 2; i++) 54 | waddch(dialog, ACS_HLINE); 55 | wattrset(dialog, dlg.dialog.atr); 56 | waddch(dialog, ACS_RTEE); 57 | 58 | print_title(dialog, title, width); 59 | 60 | wattrset(dialog, dlg.dialog.atr); 61 | print_autowrap(dialog, prompt, width - 2, 1, 3); 62 | 63 | print_buttons(dialog, height, width, 0); 64 | 65 | while (key != KEY_ESC) { 66 | key = wgetch(dialog); 67 | switch (key) { 68 | case 'Y': 69 | case 'y': 70 | delwin(dialog); 71 | return 0; 72 | case 'N': 73 | case 'n': 74 | delwin(dialog); 75 | return 1; 76 | 77 | case TAB: 78 | case KEY_LEFT: 79 | case KEY_RIGHT: 80 | button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); 81 | 82 | print_buttons(dialog, height, width, button); 83 | wrefresh(dialog); 84 | break; 85 | case ' ': 86 | case '\n': 87 | delwin(dialog); 88 | return button; 89 | case KEY_ESC: 90 | key = on_key_esc(dialog); 91 | break; 92 | case KEY_RESIZE: 93 | delwin(dialog); 94 | on_key_resize(); 95 | goto do_resize; 96 | } 97 | } 98 | 99 | delwin(dialog); 100 | return key; /* ESC pressed */ 101 | } 102 | -------------------------------------------------------------------------------- /nemu/tools/kconfig/util.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (C) 2002-2005 Roman Zippel 4 | * Copyright (C) 2002-2005 Sam Ravnborg 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "lkc.h" 11 | 12 | /* file already present in list? If not add it */ 13 | struct file *file_lookup(const char *name) 14 | { 15 | struct file *file; 16 | 17 | for (file = file_list; file; file = file->next) { 18 | if (!strcmp(name, file->name)) { 19 | return file; 20 | } 21 | } 22 | 23 | file = xmalloc(sizeof(*file)); 24 | memset(file, 0, sizeof(*file)); 25 | file->name = xstrdup(name); 26 | file->next = file_list; 27 | file_list = file; 28 | return file; 29 | } 30 | 31 | /* Allocate initial growable string */ 32 | struct gstr str_new(void) 33 | { 34 | struct gstr gs; 35 | gs.s = xmalloc(sizeof(char) * 64); 36 | gs.len = 64; 37 | gs.max_width = 0; 38 | strcpy(gs.s, "\0"); 39 | return gs; 40 | } 41 | 42 | /* Free storage for growable string */ 43 | void str_free(struct gstr *gs) 44 | { 45 | if (gs->s) 46 | free(gs->s); 47 | gs->s = NULL; 48 | gs->len = 0; 49 | } 50 | 51 | /* Append to growable string */ 52 | void str_append(struct gstr *gs, const char *s) 53 | { 54 | size_t l; 55 | if (s) { 56 | l = strlen(gs->s) + strlen(s) + 1; 57 | if (l > gs->len) { 58 | gs->s = xrealloc(gs->s, l); 59 | gs->len = l; 60 | } 61 | strcat(gs->s, s); 62 | } 63 | } 64 | 65 | /* Append printf formatted string to growable string */ 66 | void str_printf(struct gstr *gs, const char *fmt, ...) 67 | { 68 | va_list ap; 69 | char s[10000]; /* big enough... */ 70 | va_start(ap, fmt); 71 | vsnprintf(s, sizeof(s), fmt, ap); 72 | str_append(gs, s); 73 | va_end(ap); 74 | } 75 | 76 | /* Retrieve value of growable string */ 77 | const char *str_get(struct gstr *gs) 78 | { 79 | return gs->s; 80 | } 81 | 82 | void *xmalloc(size_t size) 83 | { 84 | void *p = malloc(size); 85 | if (p) 86 | return p; 87 | fprintf(stderr, "Out of memory.\n"); 88 | exit(1); 89 | } 90 | 91 | void *xcalloc(size_t nmemb, size_t size) 92 | { 93 | void *p = calloc(nmemb, size); 94 | if (p) 95 | return p; 96 | fprintf(stderr, "Out of memory.\n"); 97 | exit(1); 98 | } 99 | 100 | void *xrealloc(void *p, size_t size) 101 | { 102 | p = realloc(p, size); 103 | if (p) 104 | return p; 105 | fprintf(stderr, "Out of memory.\n"); 106 | exit(1); 107 | } 108 | 109 | char *xstrdup(const char *s) 110 | { 111 | char *p; 112 | 113 | p = strdup(s); 114 | if (p) 115 | return p; 116 | fprintf(stderr, "Out of memory.\n"); 117 | exit(1); 118 | } 119 | 120 | char *xstrndup(const char *s, size_t n) 121 | { 122 | char *p; 123 | 124 | p = strndup(s, n); 125 | if (p) 126 | return p; 127 | fprintf(stderr, "Out of memory.\n"); 128 | exit(1); 129 | } 130 | -------------------------------------------------------------------------------- /nemu/tools/kvm-diff/Makefile: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | NAME = x86-kvm 17 | SRCS = $(shell find src/ -name "*.c") 18 | 19 | SHARE = 1 20 | INC_PATH += $(NEMU_HOME)/include $(NEMU_HOME)/src/isa/x86/include 21 | GUEST_ISA = x86 22 | 23 | include $(NEMU_HOME)/scripts/build.mk 24 | -------------------------------------------------------------------------------- /nemu/tools/kvm-diff/include/paddr.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | // this is an empty file to avoid compile error 17 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/Makefile: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | NAME = $(GUEST_ISA)-qemu 17 | SRCS = $(shell find src/ -name "*.c") 18 | 19 | SHARE = 1 20 | CFLAGS += -DNEMU_HOME=\"$(NEMU_HOME)\" -DCONFIG_ISA_$(GUEST_ISA) 21 | INC_PATH += $(NEMU_HOME)/include 22 | 23 | include $(NEMU_HOME)/scripts/build.mk 24 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/include/common.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __COMMON_H__ 17 | #define __COMMON_H__ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef uint32_t paddr_t; 28 | 29 | #include "isa.h" 30 | #include "protocol.h" 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/include/isa.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #ifndef __ISA_H__ 17 | #define __ISA_H__ 18 | 19 | #if defined(CONFIG_ISA_mips32) 20 | #define ISA_QEMU_BIN "qemu-system-mipsel" 21 | #define ISA_QEMU_ARGS "-machine", "mipssim",\ 22 | "-kernel", NEMU_HOME "/resource/mips-elf/mips.dummy", 23 | #elif defined(CONFIG_ISA_riscv32) 24 | #define ISA_QEMU_BIN "qemu-system-riscv32" 25 | #define ISA_QEMU_ARGS "-bios", "none", 26 | #elif defined(CONFIG_ISA_riscv64) 27 | #define ISA_QEMU_BIN "qemu-system-riscv64" 28 | #define ISA_QEMU_ARGS 29 | #elif defined(CONFIG_ISA_x86) 30 | #define ISA_QEMU_BIN "qemu-system-i386" 31 | #define ISA_QEMU_ARGS 32 | #else 33 | #error Unsupport ISA 34 | #endif 35 | 36 | union isa_gdb_regs { 37 | struct { 38 | #if defined(CONFIG_ISA_mips32) 39 | uint32_t gpr[32]; 40 | uint32_t status, lo, hi, badvaddr, cause, pc; 41 | #elif defined(CONFIG_ISA_riscv32) 42 | uint32_t gpr[32]; 43 | uint32_t pc; 44 | #elif defined(CONFIG_ISA_riscv64) 45 | uint64_t gpr[32]; 46 | uint64_t fpr[32]; 47 | uint64_t pc; 48 | #elif defined(CONFIG_ISA_x86) 49 | uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi; 50 | uint32_t eip, eflags; 51 | uint32_t cs, ss, ds, es, fs, gs; 52 | #endif 53 | }; 54 | struct { 55 | uint32_t array[77]; 56 | }; 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/include/protocol.h: -------------------------------------------------------------------------------- 1 | /* Simple interface of a GDB remote protocol client. 2 | * Copyright (C) 2015 Red Hat Inc. 3 | * 4 | * This file is part of gdb-toys. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License as published by the Free 8 | * Software Foundation; either version 3 of the License, or (at your option) 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 | * more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | struct gdb_conn; 23 | 24 | uint16_t gdb_decode_hex(uint8_t msb, uint8_t lsb); 25 | uint64_t gdb_decode_hex_str(uint8_t *bytes); 26 | 27 | uint8_t hex_encode(uint8_t digit); 28 | 29 | struct gdb_conn *gdb_begin_inet(const char *addr, uint16_t port); 30 | 31 | void gdb_end(struct gdb_conn *conn); 32 | 33 | void gdb_send(struct gdb_conn *conn, const uint8_t *command, size_t size); 34 | 35 | uint8_t *gdb_recv(struct gdb_conn *conn, size_t *size); 36 | 37 | const char * gdb_start_noack(struct gdb_conn *conn); 38 | -------------------------------------------------------------------------------- /nemu/tools/qemu-diff/src/isa.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************************** 2 | * Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | * 4 | * NEMU is licensed under Mulan PSL v2. 5 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | * You may obtain a copy of Mulan PSL v2 at: 7 | * http://license.coscl.org.cn/MulanPSL2 8 | * 9 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | * 13 | * See the Mulan PSL v2 for more details. 14 | ***************************************************************************************/ 15 | 16 | #include "common.h" 17 | 18 | #if defined(CONFIG_ISA_x86) 19 | 20 | bool gdb_memcpy_to_qemu(uint32_t, void *, int); 21 | bool gdb_getregs(union isa_gdb_regs *); 22 | bool gdb_setregs(union isa_gdb_regs *); 23 | void difftest_exec(uint64_t n); 24 | 25 | static uint8_t mbr[] = { 26 | // start16: 27 | 0xfa, // cli 28 | 0x31, 0xc0, // xorw %ax,%ax 29 | 0x8e, 0xd8, // movw %ax,%ds 30 | 0x8e, 0xc0, // movw %ax,%es 31 | 0x8e, 0xd0, // movw %ax,%ss 32 | 0x0f, 0x01, 0x16, 0x44, 0x7c, // lgdt gdtdesc 33 | 0x0f, 0x20, 0xc0, // movl %cr0,%eax 34 | 0x66, 0x83, 0xc8, 0x01, // orl $CR0_PE,%eax 35 | 0x0f, 0x22, 0xc0, // movl %eax,%cr0 36 | 0xea, 0x1d, 0x7c, 0x08, 0x00, // ljmp $GDT_ENTRY(1),$start32 37 | 38 | // start32: 39 | 0x66, 0xb8, 0x10, 0x00, // movw $0x10,%ax 40 | 0x8e, 0xd8, // movw %ax, %ds 41 | 0x8e, 0xc0, // movw %ax, %es 42 | 0x8e, 0xd0, // movw %ax, %ss 43 | 0xeb, 0xfe, // jmp 7c27 44 | 0x8d, 0x76, 0x00, // lea 0x0(%esi),%esi 45 | 46 | // GDT 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00, 49 | 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, 50 | 51 | // GDT descriptor 52 | 0x17, 0x00, 0x2c, 0x7c, 0x00, 0x00 53 | }; 54 | 55 | void init_isa() { 56 | // put the MBR code to QEMU to enable protected mode 57 | bool ok = gdb_memcpy_to_qemu(0x7c00, mbr, sizeof(mbr)); 58 | assert(ok == 1); 59 | 60 | union isa_gdb_regs r; 61 | gdb_getregs(&r); 62 | 63 | // set cs:eip to 0000:7c00 64 | r.eip = 0x7c00; 65 | r.cs = 0x0000; 66 | ok = gdb_setregs(&r); 67 | assert(ok == 1); 68 | 69 | // execute enough instructions to enter protected mode 70 | difftest_exec(20); 71 | } 72 | 73 | #else 74 | 75 | void init_isa() { 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /nemu/tools/spike-diff/.gitignore: -------------------------------------------------------------------------------- 1 | repo/ 2 | !difftest.cc 3 | -------------------------------------------------------------------------------- /nemu/tools/spike-diff/Makefile: -------------------------------------------------------------------------------- 1 | #*************************************************************************************** 2 | # Copyright (c) 2014-2022 Zihao Yu, Nanjing University 3 | # 4 | # NEMU is licensed under Mulan PSL v2. 5 | # You can use this software according to the terms and conditions of the Mulan PSL v2. 6 | # You may obtain a copy of Mulan PSL v2 at: 7 | # http://license.coscl.org.cn/MulanPSL2 8 | # 9 | # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 10 | # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 11 | # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 12 | # 13 | # See the Mulan PSL v2 for more details. 14 | #**************************************************************************************/ 15 | 16 | REPO_PATH = repo 17 | ifeq ($(wildcard repo/spike_main),) 18 | $(shell git clone --depth=1 git@github.com:NJU-ProjectN/riscv-isa-sim $(REPO_PATH)) 19 | endif 20 | 21 | REPO_BUILD_PATH = $(REPO_PATH)/build 22 | REPO_MAKEFILE = $(REPO_BUILD_PATH)/Makefile 23 | $(REPO_MAKEFILE): 24 | @mkdir -p $(@D) 25 | cd $(@D) && $(abspath $(REPO_PATH))/configure 26 | sed -i -e 's/-g -O2/-O2/' $@ 27 | 28 | SPIKE = $(REPO_BUILD_PATH)/spike 29 | $(SPIKE): $(REPO_MAKEFILE) 30 | $(MAKE) -C $(^D) 31 | 32 | BUILD_DIR = ./build 33 | $(shell mkdir -p $(BUILD_DIR)) 34 | 35 | inc_dependencies = fesvr riscv disasm customext fdt softfloat spike_main spike_dasm build 36 | INC_PATH = -I$(REPO_PATH) $(addprefix -I$(REPO_PATH)/, $(inc_dependencies)) 37 | INC_PATH += -I$(NEMU_HOME)/include 38 | lib_dependencies = libspike_main.a libriscv.a libdisasm.a libsoftfloat.a libfesvr.a libfdt.a 39 | INC_LIBS = $(addprefix $(REPO_PATH)/build/, $(lib_dependencies)) 40 | 41 | NAME = $(GUEST_ISA)-spike-so 42 | BINARY = $(BUILD_DIR)/$(NAME) 43 | SRCS = difftest.cc 44 | 45 | $(BINARY): $(SPIKE) $(SRCS) 46 | g++ -O2 -shared -fPIC $(INC_PATH) $(SRCS) $(INC_LIBS) -o $@ 47 | 48 | clean: 49 | rm -rf $(BUILD_DIR) 50 | 51 | all: $(BINARY) 52 | .DEFAULT_GOAL = all 53 | 54 | .PHONY: all clean $(SPIKE) 55 | --------------------------------------------------------------------------------