commit 80a2e72f5b5cd624675a0869774e5c2cff47a47c from: Benjamin Stürz date: Mon Apr 15 11:25:36 2024 UTC Actually rename to linurv commit - c791d5e82e697eff4e99ced039d29bd8d2029da3 commit + 80a2e72f5b5cd624675a0869774e5c2cff47a47c blob - f8ced90bcaa3a38a746c653e9d44a09d2fd308c4 blob + a0baec7dd2d222cb9851c15e968d68c23e0ddede --- .gitignore +++ .gitignore @@ -15,5 +15,5 @@ microcoreutils *.core *.pdf rootfs -rvemu +linurv config.mk.local blob - 1919ea85b5986250356e8214c1ad812230ceb1d6 blob + a53351c28db4a20b91144e436234f89f1169f586 --- Makefile +++ Makefile @@ -12,7 +12,7 @@ COPT = -g -O2 CFLAGS = ${CFLAGS_OS} ${COPT} -std=c2x LDFLAGS = ${LDFLAGS_OS} -lpthread -OBJ = src/rvemu.o src/ecall.o src/cpu.o src/exec.o +OBJ = src/linurv.o src/ecall.o src/cpu.o src/exec.o T = asm PROGS = examples/test.elf \ examples/echo.elf \ @@ -20,31 +20,31 @@ PROGS = examples/test.elf \ examples/hello.elf \ examples/asm.elf -all: rvemu ${PROGS} +all: linurv ${PROGS} od: examples/$T.elf ${CROSS}-objdump -d examples/$T.elf | less -run: rvemu ${PROGS} +run: linurv ${PROGS} mkdir -p rootfs/bin - cp -f rvemu rootfs/bin + cp -f linurv rootfs/bin cp -f ${PROGS} rootfs/bin cp -f test.txt rootfs/ - ${CHROOT} rootfs /bin/rvemu /bin/$T.elf + ${CHROOT} rootfs /bin/linurv /bin/$T.elf distclean: clean (cd tools; ${MAKE} distclean) clean: - rm -f rvemu src/*.o examples/*.elf *.core src/syscalls.h + rm -f linurv src/*.o examples/*.elf *.core src/syscalls.h rm -rf rootfs -install: rvemu +install: linurv mkdir -p ${DESTDIR}${PREFIX}/bin - cp -f rvemu ${DESTDIR}${PREFIX}/bin/ + cp -f linurv ${DESTDIR}${PREFIX}/bin/ -rvemu: ${OBJ} +linurv: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} src/ecall.o: src/syscalls.h blob - 075f9f812a8cba378fee259e930a8050d929f4c7 blob + 6aab3a3a59ada2565b3f6779c303333bfcb266b6 --- src/cpu.c +++ src/cpu.c @@ -1,5 +1,5 @@ #include -#include "rvemu.h" +#include "linurv.h" static u64 regs[31]; u64 pc; blob - 5c4a53f2813521dd056d4782dafd04e7c74dcae6 blob + 24edc75616e9d0e8c904863d33c37c7de7d42af7 --- src/ecall.c +++ src/ecall.c @@ -17,7 +17,7 @@ #include #include #include "syscalls.h" -#include "rvemu.h" +#include "linurv.h" struct linux_stat64 { u64 dev; blob - 156608f9903fa2c229f72dc09bf641c0865a2f3a blob + 45391396df92dfe98e982e147b7c07508a1ccd41 --- src/exec.c +++ src/exec.c @@ -4,7 +4,7 @@ #include #include #include -#include "rvemu.h" +#include "linurv.h" int is_executable (const Elf64_Ehdr *ehdr) @@ -65,11 +65,11 @@ int my_execve (const char *path, char **argv, char **e old_env = environ; environ = envp; - st = execvp ("rvemu", argv); + st = execvp ("linurv", argv); environ = old_env; return st; #else - return execvpe ("rvemu", argv, envp); + return execvpe ("linurv", argv, envp); #endif } blob - b2820cb92338ed9fca5224d5a138323dc27d6cf7 (mode 644) blob + /dev/null --- src/rvemu.c +++ /dev/null @@ -1,192 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rvemu.h" - -u64 brkval = 0; - -static void load_segment (int fd, Elf64_Phdr phdr) -{ - size_t end, len, ps; - int prot = 0; - void *addr, *ptr; - - - if (phdr.p_filesz > phdr.p_memsz) - errx (1, "invalid program header: p_filesz > p_memsz"); - - ps = getpagesize (); - addr = (void *)(phdr.p_vaddr & ~(ps - 1)); - len = phdr.p_memsz + phdr.p_vaddr - (size_t)addr; - - ptr = mmap ( - addr, - len, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, - -1, - 0 - ); - eprintf ("mmap (%p, %#zx) = %p;\n", addr, len, ptr); - - if (ptr == NULL) - err (1, "mmap()"); - - if (phdr.p_filesz > 0) { - lseek (fd, phdr.p_offset, SEEK_SET); - read (fd, (void *)phdr.p_vaddr, phdr.p_filesz); - } - - if (phdr.p_flags & (PF_R | PF_X)) - prot |= PROT_READ; - if (phdr.p_flags & PF_W) - prot |= PROT_WRITE; - if (mprotect (addr, len, prot) != 0) - err (1, "mprotect()"); - - end = (phdr.p_vaddr + phdr.p_memsz + ps - 1) & ~(ps - 1); - if (end > brkval) - brkval = end; -} - -static void load_image (const char *filename) -{ - Elf64_Ehdr ehdr; - int fd; - - fd = open (filename, O_RDONLY); - if (fd < 0) - err (1, "open('%s')", filename); - - if (read (fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) - err (1, "read('%s')", filename); - - if (!is_executable (&ehdr)) - errx (1, "Invalid argument"); - - pc = ehdr.e_entry; - - for (unsigned i = 0; i < ehdr.e_phnum; ++i) { - Elf64_Phdr phdr; - - lseek (fd, ehdr.e_phoff + i * ehdr.e_phentsize, SEEK_SET); - if (read (fd, &phdr, ehdr.e_phentsize) != ehdr.e_phentsize) - err (1, "failed to read program header %u", i); - - switch (phdr.p_type) { - case PT_NULL: - break; - case PT_LOAD: - load_segment (fd, phdr); - break; - case PT_INTERP: - case PT_DYNAMIC: - errx (1, "shared objects not supported"); - default: - //warnx ("%u: ignoring program header: %x", - // i, (unsigned)phdr.p_type); - break; - } - } - close (fd); -} - -static void cpu_push (u64 val) -{ - cpu_set (REG_sp, cpu_get (REG_sp) - 8); - write_u64 (cpu_get (REG_sp), val); -} - -static void setup_stack ( - u64 stack_size, - int argc, - char **argv, - int envc, - char **envp -) { - void *ptr; - void *stack_bottom; - - // set stack pointer - cpu_set (REG_sp, 0x80000000); - - stack_bottom = (void *)(u64)(0x80000000 - stack_size); - ptr = mmap ( - stack_bottom, - stack_size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, - -1, - 0 - ); - - if (ptr != stack_bottom) - err (1, "failed to map stack"); - - // auxv - cpu_push (0); - cpu_push (0); - cpu_push (getegid ()); - cpu_push (14); - cpu_push (getgid ()); - cpu_push (13); - cpu_push (geteuid ()); - cpu_push (12); - cpu_push (getuid ()); - cpu_push (11); - cpu_push (getpagesize ()); - cpu_push (6); - - cpu_push (0); - for (int i = envc - 1; i >= 0; --i) - cpu_push ((u64)envp[i]); - cpu_push (0); - for (int i = argc - 1; i >= 0; --i) - cpu_push ((u64)argv[i]); - cpu_push (argc); -} - -int main (int argc, char *argv[], char *envp[]) -{ - const char *filename; - struct rlimit rl; - size_t stack_size; - int fd, envc; - char *base; - void *ptr; - - base = basename (argv[0]); - - if (strcmp (base, "rvemu") == 0) { - if (argc < 2) - errx (1, "usage: rvemu file"); - ++argv; - --argc; - } - - filename = argv[0]; - load_image (filename); - - if (getrlimit (RLIMIT_STACK, &rl) == 0) { - stack_size = rl.rlim_cur; - } else { - stack_size = 1 << 20; - } - - for (envc = 0; envp[envc] != NULL; ++envc); - - setup_stack (stack_size, argc, argv, envc, envp); - - while (1) { - const u32 instr = cpu_fetch (); - cpu_exec (instr); - } - - return 0; -} blob - /dev/null blob + 8528c3aaf97812d6a936b0ea33e916ab0ce836df (mode 644) --- /dev/null +++ src/linurv.c @@ -0,0 +1,192 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linurv.h" + +u64 brkval = 0; + +static void load_segment (int fd, Elf64_Phdr phdr) +{ + size_t end, len, ps; + int prot = 0; + void *addr, *ptr; + + + if (phdr.p_filesz > phdr.p_memsz) + errx (1, "invalid program header: p_filesz > p_memsz"); + + ps = getpagesize (); + addr = (void *)(phdr.p_vaddr & ~(ps - 1)); + len = phdr.p_memsz + phdr.p_vaddr - (size_t)addr; + + ptr = mmap ( + addr, + len, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, + -1, + 0 + ); + eprintf ("mmap (%p, %#zx) = %p;\n", addr, len, ptr); + + if (ptr == NULL) + err (1, "mmap()"); + + if (phdr.p_filesz > 0) { + lseek (fd, phdr.p_offset, SEEK_SET); + read (fd, (void *)phdr.p_vaddr, phdr.p_filesz); + } + + if (phdr.p_flags & (PF_R | PF_X)) + prot |= PROT_READ; + if (phdr.p_flags & PF_W) + prot |= PROT_WRITE; + if (mprotect (addr, len, prot) != 0) + err (1, "mprotect()"); + + end = (phdr.p_vaddr + phdr.p_memsz + ps - 1) & ~(ps - 1); + if (end > brkval) + brkval = end; +} + +static void load_image (const char *filename) +{ + Elf64_Ehdr ehdr; + int fd; + + fd = open (filename, O_RDONLY); + if (fd < 0) + err (1, "open('%s')", filename); + + if (read (fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) + err (1, "read('%s')", filename); + + if (!is_executable (&ehdr)) + errx (1, "Invalid argument"); + + pc = ehdr.e_entry; + + for (unsigned i = 0; i < ehdr.e_phnum; ++i) { + Elf64_Phdr phdr; + + lseek (fd, ehdr.e_phoff + i * ehdr.e_phentsize, SEEK_SET); + if (read (fd, &phdr, ehdr.e_phentsize) != ehdr.e_phentsize) + err (1, "failed to read program header %u", i); + + switch (phdr.p_type) { + case PT_NULL: + break; + case PT_LOAD: + load_segment (fd, phdr); + break; + case PT_INTERP: + case PT_DYNAMIC: + errx (1, "shared objects not supported"); + default: + //warnx ("%u: ignoring program header: %x", + // i, (unsigned)phdr.p_type); + break; + } + } + close (fd); +} + +static void cpu_push (u64 val) +{ + cpu_set (REG_sp, cpu_get (REG_sp) - 8); + write_u64 (cpu_get (REG_sp), val); +} + +static void setup_stack ( + u64 stack_size, + int argc, + char **argv, + int envc, + char **envp +) { + void *ptr; + void *stack_bottom; + + // set stack pointer + cpu_set (REG_sp, 0x80000000); + + stack_bottom = (void *)(u64)(0x80000000 - stack_size); + ptr = mmap ( + stack_bottom, + stack_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, + -1, + 0 + ); + + if (ptr != stack_bottom) + err (1, "failed to map stack"); + + // auxv + cpu_push (0); + cpu_push (0); + cpu_push (getegid ()); + cpu_push (14); + cpu_push (getgid ()); + cpu_push (13); + cpu_push (geteuid ()); + cpu_push (12); + cpu_push (getuid ()); + cpu_push (11); + cpu_push (getpagesize ()); + cpu_push (6); + + cpu_push (0); + for (int i = envc - 1; i >= 0; --i) + cpu_push ((u64)envp[i]); + cpu_push (0); + for (int i = argc - 1; i >= 0; --i) + cpu_push ((u64)argv[i]); + cpu_push (argc); +} + +int main (int argc, char *argv[], char *envp[]) +{ + const char *filename; + struct rlimit rl; + size_t stack_size; + int fd, envc; + char *base; + void *ptr; + + base = basename (argv[0]); + + if (strcmp (base, "linurv") == 0) { + if (argc < 2) + errx (1, "usage: linurv file"); + ++argv; + --argc; + } + + filename = argv[0]; + load_image (filename); + + if (getrlimit (RLIMIT_STACK, &rl) == 0) { + stack_size = rl.rlim_cur; + } else { + stack_size = 1 << 20; + } + + for (envc = 0; envp[envc] != NULL; ++envc); + + setup_stack (stack_size, argc, argv, envc, envp); + + while (1) { + const u32 instr = cpu_fetch (); + cpu_exec (instr); + } + + return 0; +} blob - f1fa870f78600a53528abcc226d280124e392286 (mode 644) blob + /dev/null --- src/rvemu.h +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include -#include -#include - -#define DEBUG 0 - -#if DEBUG -# define eprintf(...) fprintf (stderr, __VA_ARGS__) -#else -# define eprintf(...) -#endif - -enum { - REG_zero, - REG_ra, - REG_sp, - REG_gp, - REG_tp, - REG_t0, - REG_t1, - REG_t2, - REG_s0, - REG_s1, - REG_a0, - REG_a1, - REG_a2, - REG_a3, - REG_a4, - REG_a5, - REG_a6, - REG_a7, - REG_s2, - REG_s3, - REG_s4, - REG_s5, - REG_s6, - REG_s7, - REG_s8, - REG_s9, - REG_s10, - REG_s11, - REG_t3, - REG_t4, - REG_t5, - REG_t6, -}; - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef int8_t i8; -typedef int16_t i16; -typedef int32_t i32; -typedef int64_t i64; - -typedef unsigned int uint; - -extern u64 pc; -extern u64 brkval; -extern const char *interpreter; - -u32 cpu_fetch (void); -u64 cpu_get (size_t reg); -void cpu_set (size_t reg, u64 val); -void cpu_exec (u32 instr); -void ecall (void); -int my_execve (const char *path, char **argv, char **envp); -int is_executable (const Elf64_Ehdr *); - -#define read_u8(ptr) (*(const u8 *)(size_t)(ptr)) -#define read_u16(ptr) (*(const u16 *)(size_t)(ptr)) -#define read_u32(ptr) (*(const u32 *)(size_t)(ptr)) -#define read_u64(ptr) (*(const u64 *)(size_t)(ptr)) -#define read_i8(ptr) (*(const i8 *)(size_t)(ptr)) -#define read_i16(ptr) (*(const i16 *)(size_t)(ptr)) -#define read_i32(ptr) (*(const i32 *)(size_t)(ptr)) -#define read_i64(ptr) (*(const i64 *)(size_t)(ptr)) -#define write_u8(ptr, val) (*(u8 *)(size_t)(ptr) = (val)) -#define write_u16(ptr, val) (*(u16 *)(size_t)(ptr) = (val)) -#define write_u32(ptr, val) (*(u32 *)(size_t)(ptr) = (val)) -#define write_u64(ptr, val) (*(u64 *)(size_t)(ptr) = (val)) blob - /dev/null blob + f1fa870f78600a53528abcc226d280124e392286 (mode 644) --- /dev/null +++ src/linurv.h @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +#define DEBUG 0 + +#if DEBUG +# define eprintf(...) fprintf (stderr, __VA_ARGS__) +#else +# define eprintf(...) +#endif + +enum { + REG_zero, + REG_ra, + REG_sp, + REG_gp, + REG_tp, + REG_t0, + REG_t1, + REG_t2, + REG_s0, + REG_s1, + REG_a0, + REG_a1, + REG_a2, + REG_a3, + REG_a4, + REG_a5, + REG_a6, + REG_a7, + REG_s2, + REG_s3, + REG_s4, + REG_s5, + REG_s6, + REG_s7, + REG_s8, + REG_s9, + REG_s10, + REG_s11, + REG_t3, + REG_t4, + REG_t5, + REG_t6, +}; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; + +typedef unsigned int uint; + +extern u64 pc; +extern u64 brkval; +extern const char *interpreter; + +u32 cpu_fetch (void); +u64 cpu_get (size_t reg); +void cpu_set (size_t reg, u64 val); +void cpu_exec (u32 instr); +void ecall (void); +int my_execve (const char *path, char **argv, char **envp); +int is_executable (const Elf64_Ehdr *); + +#define read_u8(ptr) (*(const u8 *)(size_t)(ptr)) +#define read_u16(ptr) (*(const u16 *)(size_t)(ptr)) +#define read_u32(ptr) (*(const u32 *)(size_t)(ptr)) +#define read_u64(ptr) (*(const u64 *)(size_t)(ptr)) +#define read_i8(ptr) (*(const i8 *)(size_t)(ptr)) +#define read_i16(ptr) (*(const i16 *)(size_t)(ptr)) +#define read_i32(ptr) (*(const i32 *)(size_t)(ptr)) +#define read_i64(ptr) (*(const i64 *)(size_t)(ptr)) +#define write_u8(ptr, val) (*(u8 *)(size_t)(ptr) = (val)) +#define write_u16(ptr, val) (*(u16 *)(size_t)(ptr) = (val)) +#define write_u32(ptr, val) (*(u32 *)(size_t)(ptr) = (val)) +#define write_u64(ptr, val) (*(u64 *)(size_t)(ptr) = (val))