diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..880ac59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index 77f5900..8609f68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,7 @@ cmake_minimum_required(VERSION 3.0) project(ucore_user) - -enable_language(C ASM) +enable_language(ASM) # Path if (${ARCH} STREQUAL riscv32 OR ${ARCH} STREQUAL riscv64) @@ -36,6 +35,8 @@ elseif (${ARCH} STREQUAL riscv64) set(CMAKE_C_FLAGS "-march=rv64imac -mabi=lp64 -mcmodel=medany") elseif (${ARCH} STREQUAL aarch64) set(PREFIX aarch64-none-elf-) + set(CMAKE_C_FLAGS "-mgeneral-regs-only") + set(CMAKE_C_LINK_FLAGS "-Ttext 0xffff000000000000") else() message("Unsupported arch: ${ARCH}") endif () @@ -44,8 +45,8 @@ set(CMAKE_C_COMPILER ${PREFIX}gcc) set(CMAKE_RANLIB ${PREFIX}ranlib) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-builtin -nostdinc -fno-stack-protector -ggdb -Wall") set(CMAKE_ASM_FLAGS ${CMAKE_C_FLAGS}) -set(CMAKE_C_LINK_FLAGS "-nostdlib") # get rid of '-Wl,-search_paths_first -Wl,-headerpad_max_install_names' -set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) # get rid of '-rdynamic' on Linux +set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -nostdlib") # get rid of '-Wl,-search_paths_first -Wl,-headerpad_max_install_names' +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) # get rid of '-rdynamic' on Linux # Library add_library(ulib ${LIBS}) diff --git a/src/arch/aarch64/arch.h b/src/arch/aarch64/arch.h new file mode 100644 index 0000000..4fdfb90 --- /dev/null +++ b/src/arch/aarch64/arch.h @@ -0,0 +1,14 @@ +// See LICENSE for license details. + +#ifndef __LIBS_AARCH64_H__ +#define __LIBS_AARCH64_H__ + +#define do_div(n, base) \ + ({ \ + int __res; \ + __res = ((unsigned long)n) % (unsigned)base; \ + n = ((unsigned long)n) / (unsigned)base; \ + __res; \ + }) + +#endif diff --git a/src/arch/aarch64/atomic.h b/src/arch/aarch64/atomic.h new file mode 100644 index 0000000..bbbb8da --- /dev/null +++ b/src/arch/aarch64/atomic.h @@ -0,0 +1,75 @@ +#ifndef __LIBS_ATOMIC_H__ +#define __LIBS_ATOMIC_H__ + +// TODO: implement atomic operations for aarch64 + +/* Atomic operations that C can't guarantee us. Useful for resource counting etc.. */ + +static inline void set_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline void clear_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline void change_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline bool test_and_set_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline bool test_and_clear_bit(int nr, volatile void *addr) __attribute__((always_inline)); +static inline bool test_bit(int nr, volatile void *addr) __attribute__((always_inline)); + +/* * + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + * */ +static inline void set_bit(int nr, volatile void *addr) { + /* unimplemented */ +} + +/* * + * clear_bit - Atomically clears a bit in memory + * @nr: the bit to clear + * @addr: the address to start counting from + * */ +static inline void clear_bit(int nr, volatile void *addr) { + /* unimplemented */ +} + +/* * + * change_bit - Atomically toggle a bit in memory + * @nr: the bit to change + * @addr: the address to start counting from + * */ +static inline void change_bit(int nr, volatile void *addr) { + /* unimplemented */ +} + +/* * + * test_bit - Determine whether a bit is set + * @nr: the bit to test + * @addr: the address to count from + * */ +static inline bool test_bit(int nr, volatile void *addr) { + /* unimplemented */ + return 0; +} + +/* * + * test_and_set_bit - Atomically set a bit and return its old value + * @nr: the bit to set + * @addr: the address to count from + * */ +static inline bool test_and_set_bit(int nr, volatile void *addr) { + /* unimplemented */ + return 0; +} + +/* * + * test_and_clear_bit - Atomically clear a bit and return its old value + * @nr: the bit to clear + * @addr: the address to count from + * */ +static inline bool test_and_clear_bit(int nr, volatile void *addr) { + /* unimplemented */ + return 0; +} + +#endif /* !__LIBS_ATOMIC_H__ */ diff --git a/src/arch/aarch64/defs.h b/src/arch/aarch64/defs.h new file mode 100644 index 0000000..1e1def7 --- /dev/null +++ b/src/arch/aarch64/defs.h @@ -0,0 +1,79 @@ +#ifndef __LIBS_DEFS_H__ +#define __LIBS_DEFS_H__ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define __always_inline inline __attribute__((always_inline)) +#define __noinline __attribute__((noinline)) +#define __noreturn __attribute__((noreturn)) + +#define CHAR_BIT 8 + +/* Represents true-or-false values */ +typedef long long bool; + +/* Explicitly-sized versions of integer types */ +typedef char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +/* * + * Pointers and addresses are 32 bits long. + * We use pointer types to represent addresses, + * uintptr_t to represent the numerical values of addresses. + * */ +typedef int64_t intptr_t; +typedef uint64_t uintptr_t; + +/* size_t is used for memory object sizes */ +typedef uintptr_t size_t; + +/* off_t is used for file offsets and lengths */ +typedef intptr_t off_t; + +/* used for page numbers */ +typedef size_t ppn_t; + +/* * + * Rounding operations (efficient when n is a power of 2) + * Round down to the nearest multiple of n + * */ +#define ROUNDDOWN(a, n) ({ \ + size_t __a = (size_t)(a); \ + (typeof(a))(__a - __a % (n)); \ + }) + +/* Round up to the nearest multiple of n */ +#define ROUNDUP(a, n) ({ \ + size_t __n = (size_t)(n); \ + (typeof(a))(ROUNDDOWN((size_t)(a) + __n - 1, __n)); \ + }) + +/* Round up the result of dividing of n */ +#define ROUNDUP_DIV(a, n) ({ \ +uint64_t __n = (uint64_t)(n); \ +(typeof(a))(((a) + __n - 1) / __n); \ +}) + +/* Return the offset of 'member' relative to the beginning of a struct type */ +#define offsetof(type, member) \ + ((size_t)(&((type *)0)->member)) + +/* * + * to_struct - get the struct from a ptr + * @ptr: a struct pointer of member + * @type: the type of the struct this is embedded in + * @member: the name of the member within the struct + * */ +#define to_struct(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) + +#endif /* !__LIBS_DEFS_H__ */ + diff --git a/src/arch/aarch64/elf.h b/src/arch/aarch64/elf.h new file mode 100644 index 0000000..867066f --- /dev/null +++ b/src/arch/aarch64/elf.h @@ -0,0 +1,48 @@ +#ifndef __LIBS_ELF_H__ +#define __LIBS_ELF_H__ + +#include + +#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian + +/* file header */ +struct elfhdr { + uint32_t e_magic; // must equal ELF_MAGIC + uint8_t e_elf[12]; + uint16_t e_type; // 1=relocatable, 2=executable, 3=shared object, 4=core image + uint16_t e_machine; // 3=x86, 4=68K, etc. + uint32_t e_version; // file version, always 1 + uint64_t e_entry; // entry point if executable + uint64_t e_phoff; // file position of program header or 0 + uint64_t e_shoff; // file position of section header or 0 + uint32_t e_flags; // architecture-specific flags, usually 0 + uint16_t e_ehsize; // size of this elf header + uint16_t e_phentsize; // size of an entry in program header + uint16_t e_phnum; // number of entries in program header or 0 + uint16_t e_shentsize; // size of an entry in section header + uint16_t e_shnum; // number of entries in section header or 0 + uint16_t e_shstrndx; // section number that contains section name strings +}; + +/* program section header */ +struct proghdr { + uint32_t p_type; // loadable code or data, dynamic linking info,etc. + uint32_t p_flags; // read/write/execute bits + uint64_t p_offset; // file offset of segment + uint64_t p_va; // virtual address to map segment + uint64_t p_pa; // physical address, not used + uint64_t p_filesz; // size of segment in file + uint64_t p_memsz; // size of segment in memory (bigger if contains bss) + uint64_t p_align; // required alignment, invariably hardware page size +}; + +/* values for Proghdr::p_type */ +#define ELF_PT_LOAD 1 + +/* flag bits for Proghdr::p_flags */ +#define ELF_PF_X 1 +#define ELF_PF_W 2 +#define ELF_PF_R 4 + +#endif /* !__LIBS_ELF_H__ */ + diff --git a/src/arch/aarch64/initcode.S b/src/arch/aarch64/initcode.S new file mode 100644 index 0000000..91fa2eb --- /dev/null +++ b/src/arch/aarch64/initcode.S @@ -0,0 +1,8 @@ +.text +.globl _start +_start: + # call user-program function + ldr x0, [sp] + add x1, sp, #8 + bl umain +1: b 1b diff --git a/src/libs/dirent.h b/src/libs/dirent.h index 429e4fe..d56c96a 100755 --- a/src/libs/dirent.h +++ b/src/libs/dirent.h @@ -5,7 +5,7 @@ #include struct dirent { - off_t offset; + int32_t offset; char name[FS_MAX_FNAME_LEN + 1]; }; diff --git a/src/libs/stat.h b/src/libs/stat.h index 41a392d..f17d0d3 100644 --- a/src/libs/stat.h +++ b/src/libs/stat.h @@ -5,9 +5,9 @@ struct stat { uint32_t st_mode; // protection mode and file type - size_t st_nlinks; // number of hard links - size_t st_blocks; // number of blocks file is using - size_t st_size; // file size (bytes) + uint32_t st_nlinks; // number of hard links + uint32_t st_blocks; // number of blocks file is using + uint32_t st_size; // file size (bytes) }; #define S_IFMT 070000 // mask for type of file diff --git a/src/sh.c b/src/sh.c index 9a652f1..60bf86c 100755 --- a/src/sh.c +++ b/src/sh.c @@ -78,7 +78,7 @@ readline(const char *prompt) { i --; } else if (c == '\n' || c == '\r') { - putc(c); + putc('\n'); buffer[i] = '\0'; break; } diff --git a/src/ulibs/syscall.c b/src/ulibs/syscall.c index 3e4758f..b121008 100644 --- a/src/ulibs/syscall.c +++ b/src/ulibs/syscall.c @@ -12,10 +12,10 @@ static inline int syscall(int num, ...) { va_list ap; va_start(ap, num); - uint32_t a[MAX_ARGS]; + size_t a[MAX_ARGS]; int i, ret; for (i = 0; i < MAX_ARGS; i ++) { - a[i] = va_arg(ap, uint32_t); + a[i] = va_arg(ap, size_t); } va_end(ap); @@ -50,6 +50,25 @@ syscall(int num, ...) { "m" (a[4]) : "memory" ); +#elif defined(__aarch64__) + asm volatile ( + "ldr w8, %1\n" + "ldr x0, %2\n" + "ldr x1, %3\n" + "ldr x2, %4\n" + "ldr x3, %5\n" + "ldr x4, %6\n" + "svc 0\n" + "str w0, %0" + : "=m" (ret) + : "m" (num), + "m" (a[0]), + "m" (a[1]), + "m" (a[2]), + "m" (a[3]), + "m" (a[4]) + : "cc", "memory" + ); #endif return ret; } diff --git a/src/ulibs/umain.c b/src/ulibs/umain.c index 9bee9ab..8c45ea3 100644 --- a/src/ulibs/umain.c +++ b/src/ulibs/umain.c @@ -7,10 +7,11 @@ int main(int argc, char *argv[]); static int initfd(int fd2, const char *path, uint32_t open_flags) { - int fd1, ret; + int fd1; if ((fd1 = open(path, open_flags)) < 0) { return fd1; } + int ret = fd1; if (fd1 != fd2) { close(fd2); ret = dup2(fd1, fd2);