parent
ef23c9e884
commit
86e1e41645
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
|||||||
#include <riscv.h>
|
|
||||||
|
|
||||||
.text
|
|
||||||
.globl _start
|
|
||||||
_start:
|
|
||||||
# call user-program function
|
|
||||||
LOAD a0, 0(sp)
|
|
||||||
addi a1, sp, 4
|
|
||||||
call umain
|
|
||||||
1: j 1b
|
|
@ -1,109 +0,0 @@
|
|||||||
#ifndef __LIBS_ATOMIC_H__
|
|
||||||
#define __LIBS_ATOMIC_H__
|
|
||||||
|
|
||||||
/* 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_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));
|
|
||||||
|
|
||||||
#define BITS_PER_LONG __riscv_xlen
|
|
||||||
|
|
||||||
#if (BITS_PER_LONG == 64)
|
|
||||||
#define __AMO(op) "amo" #op ".d"
|
|
||||||
#elif (BITS_PER_LONG == 32)
|
|
||||||
#define __AMO(op) "amo" #op ".w"
|
|
||||||
#else
|
|
||||||
#error "Unexpected BITS_PER_LONG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
|
||||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
|
||||||
|
|
||||||
#define __test_and_op_bit(op, mod, nr, addr) \
|
|
||||||
({ \
|
|
||||||
unsigned long __res, __mask; \
|
|
||||||
__mask = BIT_MASK(nr); \
|
|
||||||
__asm__ __volatile__(__AMO(op) " %0, %2, %1" \
|
|
||||||
: "=r"(__res), "+A"(addr[BIT_WORD(nr)]) \
|
|
||||||
: "r"(mod(__mask))); \
|
|
||||||
((__res & __mask) != 0); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define __op_bit(op, mod, nr, addr) \
|
|
||||||
__asm__ __volatile__(__AMO(op) " zero, %1, %0" \
|
|
||||||
: "+A"(addr[BIT_WORD(nr)]) \
|
|
||||||
: "r"(mod(BIT_MASK(nr))))
|
|
||||||
|
|
||||||
/* Bitmask modifiers */
|
|
||||||
#define __NOP(x) (x)
|
|
||||||
#define __NOT(x) (~(x))
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* 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) {
|
|
||||||
__op_bit(or, __NOP, nr, ((volatile unsigned long *)addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* 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) {
|
|
||||||
__op_bit(and, __NOT, nr, ((volatile unsigned long *)addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* 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) {
|
|
||||||
__op_bit (xor, __NOP, nr, ((volatile unsigned long *)addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* 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) {
|
|
||||||
return (((*(volatile unsigned long *)addr) >> nr) & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* 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) {
|
|
||||||
return __test_and_op_bit(or, __NOP, nr, ((volatile unsigned long *)addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* 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) {
|
|
||||||
return __test_and_op_bit(and, __NOT, nr, ((volatile unsigned long *)addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !__LIBS_ATOMIC_H__ */
|
|
@ -1,79 +0,0 @@
|
|||||||
#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__ */
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
#ifndef __LIBS_DIRENT_H__
|
|
||||||
#define __LIBS_DIRENT_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
struct dirent {
|
|
||||||
off_t offset;
|
|
||||||
char name[FS_MAX_FNAME_LEN + 1];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* !__LIBS_DIRENT_H__ */
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef __LIBS_ERROR_H__
|
|
||||||
#define __LIBS_ERROR_H__
|
|
||||||
|
|
||||||
/* kernel error codes -- keep in sync with list in lib/printfmt.c */
|
|
||||||
#define E_UNSPECIFIED 1 // Unspecified or unknown problem
|
|
||||||
#define E_BAD_PROC 2 // Process doesn't exist or otherwise
|
|
||||||
#define E_INVAL 3 // Invalid parameter
|
|
||||||
#define E_NO_MEM 4 // Request failed due to memory shortage
|
|
||||||
#define E_NO_FREE_PROC 5 // Attempt to create a new process beyond
|
|
||||||
#define E_FAULT 6 // Memory fault
|
|
||||||
#define E_SWAP_FAULT 7 // SWAP READ/WRITE fault
|
|
||||||
#define E_INVAL_ELF 8 // Invalid elf file
|
|
||||||
#define E_KILLED 9 // Process is killed
|
|
||||||
#define E_PANIC 10 // Panic Failure
|
|
||||||
#define E_TIMEOUT 11 // Timeout
|
|
||||||
#define E_TOO_BIG 12 // Argument is Too Big
|
|
||||||
#define E_NO_DEV 13 // No such Device
|
|
||||||
#define E_NA_DEV 14 // Device Not Available
|
|
||||||
#define E_BUSY 15 // Device/File is Busy
|
|
||||||
#define E_NOENT 16 // No Such File or Directory
|
|
||||||
#define E_ISDIR 17 // Is a Directory
|
|
||||||
#define E_NOTDIR 18 // Not a Directory
|
|
||||||
#define E_XDEV 19 // Cross Device-Link
|
|
||||||
#define E_UNIMP 20 // Unimplemented Feature
|
|
||||||
#define E_SEEK 21 // Illegal Seek
|
|
||||||
#define E_MAX_OPEN 22 // Too Many Files are Open
|
|
||||||
#define E_EXISTS 23 // File/Directory Already Exists
|
|
||||||
#define E_NOTEMPTY 24 // Directory is Not Empty
|
|
||||||
/* the maximum allowed */
|
|
||||||
#define MAXERROR 24
|
|
||||||
|
|
||||||
#endif /* !__LIBS_ERROR_H__ */
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
|
|
||||||
#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* hash32 - generate a hash value in the range [0, 2^@bits - 1]
|
|
||||||
* @val: the input value
|
|
||||||
* @bits: the number of bits in a return value
|
|
||||||
*
|
|
||||||
* High bits are more random, so we use them.
|
|
||||||
* */
|
|
||||||
uint32_t
|
|
||||||
hash32(uint32_t val, unsigned int bits) {
|
|
||||||
uint32_t hash = val * GOLDEN_RATIO_PRIME_32;
|
|
||||||
return (hash >> (32 - bits));
|
|
||||||
}
|
|
||||||
|
|
@ -1,163 +0,0 @@
|
|||||||
#ifndef __LIBS_LIST_H__
|
|
||||||
#define __LIBS_LIST_H__
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* Simple doubly linked list implementation.
|
|
||||||
*
|
|
||||||
* Some of the internal functions ("__xxx") are useful when manipulating
|
|
||||||
* whole lists rather than single entries, as sometimes we already know
|
|
||||||
* the next/prev entries and we can generate better code by using them
|
|
||||||
* directly rather than using the generic single-entry routines.
|
|
||||||
* */
|
|
||||||
|
|
||||||
struct list_entry {
|
|
||||||
struct list_entry *prev, *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct list_entry list_entry_t;
|
|
||||||
|
|
||||||
static inline void list_init(list_entry_t *elm) __attribute__((always_inline));
|
|
||||||
static inline void list_add(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
|
|
||||||
static inline void list_add_before(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
|
|
||||||
static inline void list_add_after(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
|
|
||||||
static inline void list_del(list_entry_t *listelm) __attribute__((always_inline));
|
|
||||||
static inline void list_del_init(list_entry_t *listelm) __attribute__((always_inline));
|
|
||||||
static inline bool list_empty(list_entry_t *list) __attribute__((always_inline));
|
|
||||||
static inline list_entry_t *list_next(list_entry_t *listelm) __attribute__((always_inline));
|
|
||||||
static inline list_entry_t *list_prev(list_entry_t *listelm) __attribute__((always_inline));
|
|
||||||
|
|
||||||
static inline void __list_add(list_entry_t *elm, list_entry_t *prev, list_entry_t *next) __attribute__((always_inline));
|
|
||||||
static inline void __list_del(list_entry_t *prev, list_entry_t *next) __attribute__((always_inline));
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_init - initialize a new entry
|
|
||||||
* @elm: new entry to be initialized
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
list_init(list_entry_t *elm) {
|
|
||||||
elm->prev = elm->next = elm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_add - add a new entry
|
|
||||||
* @listelm: list head to add after
|
|
||||||
* @elm: new entry to be added
|
|
||||||
*
|
|
||||||
* Insert the new element @elm *after* the element @listelm which
|
|
||||||
* is already in the list.
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
list_add(list_entry_t *listelm, list_entry_t *elm) {
|
|
||||||
list_add_after(listelm, elm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_add_before - add a new entry
|
|
||||||
* @listelm: list head to add before
|
|
||||||
* @elm: new entry to be added
|
|
||||||
*
|
|
||||||
* Insert the new element @elm *before* the element @listelm which
|
|
||||||
* is already in the list.
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
list_add_before(list_entry_t *listelm, list_entry_t *elm) {
|
|
||||||
__list_add(elm, listelm->prev, listelm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_add_after - add a new entry
|
|
||||||
* @listelm: list head to add after
|
|
||||||
* @elm: new entry to be added
|
|
||||||
*
|
|
||||||
* Insert the new element @elm *after* the element @listelm which
|
|
||||||
* is already in the list.
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
list_add_after(list_entry_t *listelm, list_entry_t *elm) {
|
|
||||||
__list_add(elm, listelm, listelm->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_del - deletes entry from list
|
|
||||||
* @listelm: the element to delete from the list
|
|
||||||
*
|
|
||||||
* Note: list_empty() on @listelm does not return true after this, the entry is
|
|
||||||
* in an undefined state.
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
list_del(list_entry_t *listelm) {
|
|
||||||
__list_del(listelm->prev, listelm->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_del_init - deletes entry from list and reinitialize it.
|
|
||||||
* @listelm: the element to delete from the list.
|
|
||||||
*
|
|
||||||
* Note: list_empty() on @listelm returns true after this.
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
list_del_init(list_entry_t *listelm) {
|
|
||||||
list_del(listelm);
|
|
||||||
list_init(listelm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_empty - tests whether a list is empty
|
|
||||||
* @list: the list to test.
|
|
||||||
* */
|
|
||||||
static inline bool
|
|
||||||
list_empty(list_entry_t *list) {
|
|
||||||
return list->next == list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_next - get the next entry
|
|
||||||
* @listelm: the list head
|
|
||||||
**/
|
|
||||||
static inline list_entry_t *
|
|
||||||
list_next(list_entry_t *listelm) {
|
|
||||||
return listelm->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* list_prev - get the previous entry
|
|
||||||
* @listelm: the list head
|
|
||||||
**/
|
|
||||||
static inline list_entry_t *
|
|
||||||
list_prev(list_entry_t *listelm) {
|
|
||||||
return listelm->prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* Insert a new entry between two known consecutive entries.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
__list_add(list_entry_t *elm, list_entry_t *prev, list_entry_t *next) {
|
|
||||||
prev->next = next->prev = elm;
|
|
||||||
elm->next = next;
|
|
||||||
elm->prev = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* Delete a list entry by making the prev/next entries point to each other.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
* */
|
|
||||||
static inline void
|
|
||||||
__list_del(list_entry_t *prev, list_entry_t *next) {
|
|
||||||
prev->next = next;
|
|
||||||
next->prev = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !__ASSEMBLER__ */
|
|
||||||
|
|
||||||
#endif /* !__LIBS_LIST_H__ */
|
|
||||||
|
|
@ -1,359 +0,0 @@
|
|||||||
#include <defs.h>
|
|
||||||
#include <riscv.h>
|
|
||||||
#include <error.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* Space or zero padding and a field width are supported for the numeric
|
|
||||||
* formats only.
|
|
||||||
*
|
|
||||||
* The special format %e takes an integer error code
|
|
||||||
* and prints a string describing the error.
|
|
||||||
* The integer may be positive or negative,
|
|
||||||
* so that -E_NO_MEM and E_NO_MEM are equivalent.
|
|
||||||
* */
|
|
||||||
|
|
||||||
static const char * const error_string[MAXERROR + 1] = {
|
|
||||||
[0] NULL,
|
|
||||||
[E_UNSPECIFIED] "unspecified error",
|
|
||||||
[E_BAD_PROC] "bad process",
|
|
||||||
[E_INVAL] "invalid parameter",
|
|
||||||
[E_NO_MEM] "out of memory",
|
|
||||||
[E_NO_FREE_PROC] "out of processes",
|
|
||||||
[E_FAULT] "segmentation fault",
|
|
||||||
[E_INVAL_ELF] "invalid elf file",
|
|
||||||
[E_KILLED] "process is killed",
|
|
||||||
[E_PANIC] "panic failure",
|
|
||||||
[E_NO_DEV] "no such device",
|
|
||||||
[E_NA_DEV] "device not available",
|
|
||||||
[E_BUSY] "device/file is busy",
|
|
||||||
[E_NOENT] "no such file or directory",
|
|
||||||
[E_ISDIR] "is a directory",
|
|
||||||
[E_NOTDIR] "not a directory",
|
|
||||||
[E_XDEV] "cross device link",
|
|
||||||
[E_UNIMP] "unimplemented feature",
|
|
||||||
[E_SEEK] "illegal seek",
|
|
||||||
[E_MAX_OPEN] "too many files are open",
|
|
||||||
[E_EXISTS] "file or directory already exists",
|
|
||||||
[E_NOTEMPTY] "directory is not empty",
|
|
||||||
};
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* printnum - print a number (base <= 16) in reverse order
|
|
||||||
* @putch: specified putch function, print a single character
|
|
||||||
* @fd: file descriptor
|
|
||||||
* @putdat: used by @putch function
|
|
||||||
* @num: the number will be printed
|
|
||||||
* @base: base for print, must be in [1, 16]
|
|
||||||
* @width: maximum number of digits, if the actual width is less than @width, use @padc instead
|
|
||||||
* @padc: character that padded on the left if the actual width is less than @width
|
|
||||||
* */
|
|
||||||
static void
|
|
||||||
printnum(void (*putch)(int, void*, int), int fd, void *putdat,
|
|
||||||
unsigned long long num, unsigned base, int width, int padc) {
|
|
||||||
unsigned long long result = num;
|
|
||||||
unsigned mod = do_div(result, base);
|
|
||||||
|
|
||||||
// first recursively print all preceding (more significant) digits
|
|
||||||
if (num >= base) {
|
|
||||||
printnum(putch, fd, putdat, result, base, width - 1, padc);
|
|
||||||
} else {
|
|
||||||
// print any needed pad characters before first digit
|
|
||||||
while (-- width > 0)
|
|
||||||
putch(padc, putdat, fd);
|
|
||||||
}
|
|
||||||
// then print this (the least significant) digit
|
|
||||||
putch("0123456789abcdef"[mod], putdat, fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* getuint - get an unsigned int of various possible sizes from a varargs list
|
|
||||||
* @ap: a varargs list pointer
|
|
||||||
* @lflag: determines the size of the vararg that @ap points to
|
|
||||||
* */
|
|
||||||
static unsigned long long
|
|
||||||
getuint(va_list *ap, int lflag) {
|
|
||||||
if (lflag >= 2) {
|
|
||||||
return va_arg(*ap, unsigned long long);
|
|
||||||
}
|
|
||||||
else if (lflag) {
|
|
||||||
return va_arg(*ap, unsigned long);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return va_arg(*ap, unsigned int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* getint - same as getuint but signed, we can't use getuint because of sign extension
|
|
||||||
* @ap: a varargs list pointer
|
|
||||||
* @lflag: determines the size of the vararg that @ap points to
|
|
||||||
* */
|
|
||||||
static long long
|
|
||||||
getint(va_list *ap, int lflag) {
|
|
||||||
if (lflag >= 2) {
|
|
||||||
return va_arg(*ap, long long);
|
|
||||||
}
|
|
||||||
else if (lflag) {
|
|
||||||
return va_arg(*ap, long);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return va_arg(*ap, int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* printfmt - format a string and print it by using putch
|
|
||||||
* @putch: specified putch function, print a single character
|
|
||||||
* @fd: file descriptor
|
|
||||||
* @putdat: used by @putch function
|
|
||||||
* @fmt: the format string to use
|
|
||||||
* */
|
|
||||||
void
|
|
||||||
printfmt(void (*putch)(int, void*, int), int fd, void *putdat, const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vprintfmt(putch, fd, putdat, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* vprintfmt - format a string and print it by using putch, it's called with a va_list
|
|
||||||
* instead of a variable number of arguments
|
|
||||||
* @fd: file descriptor
|
|
||||||
* @putch: specified putch function, print a single character
|
|
||||||
* @putdat: used by @putch function
|
|
||||||
* @fmt: the format string to use
|
|
||||||
* @ap: arguments for the format string
|
|
||||||
*
|
|
||||||
* Call this function if you are already dealing with a va_list.
|
|
||||||
* Or you probably want printfmt() instead.
|
|
||||||
* */
|
|
||||||
void
|
|
||||||
vprintfmt(void (*putch)(int, void*, int), int fd, void *putdat, const char *fmt, va_list ap) {
|
|
||||||
register const char *p;
|
|
||||||
register int ch, err;
|
|
||||||
unsigned long long num;
|
|
||||||
int base, width, precision, lflag, altflag;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
while ((ch = *(unsigned char *)fmt ++) != '%') {
|
|
||||||
if (ch == '\0') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
putch(ch, putdat, fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process a %-escape sequence
|
|
||||||
char padc = ' ';
|
|
||||||
width = precision = -1;
|
|
||||||
lflag = altflag = 0;
|
|
||||||
|
|
||||||
reswitch:
|
|
||||||
switch (ch = *(unsigned char *)fmt ++) {
|
|
||||||
|
|
||||||
// flag to pad on the right
|
|
||||||
case '-':
|
|
||||||
padc = '-';
|
|
||||||
goto reswitch;
|
|
||||||
|
|
||||||
// flag to pad with 0's instead of spaces
|
|
||||||
case '0':
|
|
||||||
padc = '0';
|
|
||||||
goto reswitch;
|
|
||||||
|
|
||||||
// width field
|
|
||||||
case '1' ... '9':
|
|
||||||
for (precision = 0; ; ++ fmt) {
|
|
||||||
precision = precision * 10 + ch - '0';
|
|
||||||
ch = *fmt;
|
|
||||||
if (ch < '0' || ch > '9') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto process_precision;
|
|
||||||
|
|
||||||
case '*':
|
|
||||||
precision = va_arg(ap, int);
|
|
||||||
goto process_precision;
|
|
||||||
|
|
||||||
case '.':
|
|
||||||
if (width < 0)
|
|
||||||
width = 0;
|
|
||||||
goto reswitch;
|
|
||||||
|
|
||||||
case '#':
|
|
||||||
altflag = 1;
|
|
||||||
goto reswitch;
|
|
||||||
|
|
||||||
process_precision:
|
|
||||||
if (width < 0)
|
|
||||||
width = precision, precision = -1;
|
|
||||||
goto reswitch;
|
|
||||||
|
|
||||||
// long flag (doubled for long long)
|
|
||||||
case 'l':
|
|
||||||
lflag ++;
|
|
||||||
goto reswitch;
|
|
||||||
|
|
||||||
// character
|
|
||||||
case 'c':
|
|
||||||
putch(va_arg(ap, int), putdat, fd);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// error message
|
|
||||||
case 'e':
|
|
||||||
err = va_arg(ap, int);
|
|
||||||
if (err < 0) {
|
|
||||||
err = -err;
|
|
||||||
}
|
|
||||||
if (err > MAXERROR || (p = error_string[err]) == NULL) {
|
|
||||||
printfmt(putch, fd, putdat, "error %d", err);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printfmt(putch, fd, putdat, "%s", p);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// string
|
|
||||||
case 's':
|
|
||||||
if ((p = va_arg(ap, char *)) == NULL) {
|
|
||||||
p = "(null)";
|
|
||||||
}
|
|
||||||
if (width > 0 && padc != '-') {
|
|
||||||
for (width -= strnlen(p, precision); width > 0; width --) {
|
|
||||||
putch(padc, putdat, fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (; (ch = *p ++) != '\0' && (precision < 0 || -- precision >= 0); width --) {
|
|
||||||
if (altflag && (ch < ' ' || ch > '~')) {
|
|
||||||
putch('?', putdat, fd);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
putch(ch, putdat, fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (; width > 0; width --) {
|
|
||||||
putch(' ', putdat, fd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// (signed) decimal
|
|
||||||
case 'd':
|
|
||||||
num = getint(&ap, lflag);
|
|
||||||
if ((long long)num < 0) {
|
|
||||||
putch('-', putdat, fd);
|
|
||||||
num = -(long long)num;
|
|
||||||
}
|
|
||||||
base = 10;
|
|
||||||
goto number;
|
|
||||||
|
|
||||||
// unsigned decimal
|
|
||||||
case 'u':
|
|
||||||
num = getuint(&ap, lflag);
|
|
||||||
base = 10;
|
|
||||||
goto number;
|
|
||||||
|
|
||||||
// (unsigned) octal
|
|
||||||
case 'o':
|
|
||||||
num = getuint(&ap, lflag);
|
|
||||||
base = 8;
|
|
||||||
goto number;
|
|
||||||
|
|
||||||
// pointer
|
|
||||||
case 'p':
|
|
||||||
putch('0', putdat, fd);
|
|
||||||
putch('x', putdat, fd);
|
|
||||||
num = (unsigned long long)(uintptr_t)va_arg(ap, void *);
|
|
||||||
base = 16;
|
|
||||||
goto number;
|
|
||||||
|
|
||||||
// (unsigned) hexadecimal
|
|
||||||
case 'x':
|
|
||||||
num = getuint(&ap, lflag);
|
|
||||||
base = 16;
|
|
||||||
number:
|
|
||||||
printnum(putch, fd, putdat, num, base, width, padc);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// escaped '%' character
|
|
||||||
case '%':
|
|
||||||
putch(ch, putdat, fd);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// unrecognized escape sequence - just print it literally
|
|
||||||
default:
|
|
||||||
putch('%', putdat, fd);
|
|
||||||
for (fmt --; fmt[-1] != '%'; fmt --)
|
|
||||||
/* do nothing */;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sprintbuf is used to save enough information of a buffer */
|
|
||||||
struct sprintbuf {
|
|
||||||
char *buf; // address pointer points to the first unused memory
|
|
||||||
char *ebuf; // points the end of the buffer
|
|
||||||
int cnt; // the number of characters that have been placed in this buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* sprintputch - 'print' a single character in a buffer
|
|
||||||
* @ch: the character will be printed
|
|
||||||
* @b: the buffer to place the character @ch
|
|
||||||
* */
|
|
||||||
static void
|
|
||||||
sprintputch(int ch, struct sprintbuf *b) {
|
|
||||||
b->cnt ++;
|
|
||||||
if (b->buf < b->ebuf) {
|
|
||||||
*b->buf ++ = ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* snprintf - format a string and place it in a buffer
|
|
||||||
* @str: the buffer to place the result into
|
|
||||||
* @size: the size of buffer, including the trailing null space
|
|
||||||
* @fmt: the format string to use
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
snprintf(char *str, size_t size, const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
int cnt;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
cnt = vsnprintf(str, size, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* vsnprintf - format a string and place it in a buffer, it's called with a va_list
|
|
||||||
* instead of a variable number of arguments
|
|
||||||
* @str: the buffer to place the result into
|
|
||||||
* @size: the size of buffer, including the trailing null space
|
|
||||||
* @fmt: the format string to use
|
|
||||||
* @ap: arguments for the format string
|
|
||||||
*
|
|
||||||
* The return value is the number of characters which would be generated for the
|
|
||||||
* given input, excluding the trailing '\0'.
|
|
||||||
*
|
|
||||||
* Call this function if you are already dealing with a va_list.
|
|
||||||
* Or you probably want snprintf() instead.
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
|
|
||||||
struct sprintbuf b = {str, str + size - 1, 0};
|
|
||||||
if (str == NULL || b.buf > b.ebuf) {
|
|
||||||
return -E_INVAL;
|
|
||||||
}
|
|
||||||
// print the string to the buffer
|
|
||||||
vprintfmt((void*)sprintputch, NO_FD, &b, fmt, ap);
|
|
||||||
// null terminate the buffer
|
|
||||||
*b.buf = '\0';
|
|
||||||
return b.cnt;
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
#include <riscv.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static unsigned long long next = 1;
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* rand - returns a pseudo-random integer
|
|
||||||
*
|
|
||||||
* The rand() function return a value in the range [0, RAND_MAX].
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
rand(void) {
|
|
||||||
next = (next * 0x5DEECE66DLL + 0xBLL) & ((1LL << 48) - 1);
|
|
||||||
unsigned long long result = (next >> 12);
|
|
||||||
return (int)do_div(result, RAND_MAX + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* srand - seed the random number generator with the given number
|
|
||||||
* @seed: the required seed number
|
|
||||||
* */
|
|
||||||
void
|
|
||||||
srand(unsigned int seed) {
|
|
||||||
next = seed;
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Regents of the University of California
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation, version 2.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SBI_H__
|
|
||||||
#define __SBI_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
|
|
||||||
#define SBI_SET_TIMER 0
|
|
||||||
#define SBI_CONSOLE_PUTCHAR 1
|
|
||||||
#define SBI_CONSOLE_GETCHAR 2
|
|
||||||
#define SBI_CLEAR_IPI 3
|
|
||||||
#define SBI_SEND_IPI 4
|
|
||||||
#define SBI_REMOTE_FENCE_I 5
|
|
||||||
#define SBI_REMOTE_SFENCE_VMA 6
|
|
||||||
#define SBI_REMOTE_SFENCE_VMA_ASID 7
|
|
||||||
#define SBI_SHUTDOWN 8
|
|
||||||
|
|
||||||
#define SBI_CALL(which, arg0, arg1, arg2) ({ \
|
|
||||||
register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0); \
|
|
||||||
register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1); \
|
|
||||||
register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2); \
|
|
||||||
register uintptr_t a7 asm ("a7") = (uintptr_t)(which); \
|
|
||||||
asm volatile ("ecall" \
|
|
||||||
: "+r" (a0) \
|
|
||||||
: "r" (a1), "r" (a2), "r" (a7) \
|
|
||||||
: "memory"); \
|
|
||||||
a0; \
|
|
||||||
})
|
|
||||||
|
|
||||||
/* Lazy implementations until SBI is finalized */
|
|
||||||
#define SBI_CALL_0(which) SBI_CALL(which, 0, 0, 0)
|
|
||||||
#define SBI_CALL_1(which, arg0) SBI_CALL(which, arg0, 0, 0)
|
|
||||||
#define SBI_CALL_2(which, arg0, arg1) SBI_CALL(which, arg0, arg1, 0)
|
|
||||||
|
|
||||||
static inline void sbi_console_putchar(int ch)
|
|
||||||
{
|
|
||||||
SBI_CALL_1(SBI_CONSOLE_PUTCHAR, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int sbi_console_getchar(void)
|
|
||||||
{
|
|
||||||
return SBI_CALL_0(SBI_CONSOLE_GETCHAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sbi_set_timer(uint64_t stime_value)
|
|
||||||
{
|
|
||||||
#if __riscv_xlen == 32
|
|
||||||
SBI_CALL_2(SBI_SET_TIMER, stime_value, stime_value >> 32);
|
|
||||||
#else
|
|
||||||
SBI_CALL_1(SBI_SET_TIMER, stime_value);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sbi_shutdown(void)
|
|
||||||
{
|
|
||||||
SBI_CALL_0(SBI_SHUTDOWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sbi_clear_ipi(void)
|
|
||||||
{
|
|
||||||
SBI_CALL_0(SBI_CLEAR_IPI);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sbi_send_ipi(const unsigned long *hart_mask)
|
|
||||||
{
|
|
||||||
SBI_CALL_1(SBI_SEND_IPI, hart_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sbi_remote_fence_i(const unsigned long *hart_mask)
|
|
||||||
{
|
|
||||||
SBI_CALL_1(SBI_REMOTE_FENCE_I, hart_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sbi_remote_sfence_vma(const unsigned long *hart_mask,
|
|
||||||
unsigned long start,
|
|
||||||
unsigned long size)
|
|
||||||
{
|
|
||||||
SBI_CALL_1(SBI_REMOTE_SFENCE_VMA, hart_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
|
|
||||||
unsigned long start,
|
|
||||||
unsigned long size,
|
|
||||||
unsigned long asid)
|
|
||||||
{
|
|
||||||
SBI_CALL_1(SBI_REMOTE_SFENCE_VMA_ASID, hart_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !__SBI_H__ */
|
|
@ -1,87 +0,0 @@
|
|||||||
#ifndef __LIBS_SKEW_HEAP_H__
|
|
||||||
#define __LIBS_SKEW_HEAP_H__
|
|
||||||
|
|
||||||
struct skew_heap_entry {
|
|
||||||
struct skew_heap_entry *parent, *left, *right;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct skew_heap_entry skew_heap_entry_t;
|
|
||||||
|
|
||||||
typedef int(*compare_f)(void *a, void *b);
|
|
||||||
|
|
||||||
static inline void skew_heap_init(skew_heap_entry_t *a) __attribute__((always_inline));
|
|
||||||
static inline skew_heap_entry_t *skew_heap_merge(
|
|
||||||
skew_heap_entry_t *a, skew_heap_entry_t *b,
|
|
||||||
compare_f comp);
|
|
||||||
static inline skew_heap_entry_t *skew_heap_insert(
|
|
||||||
skew_heap_entry_t *a, skew_heap_entry_t *b,
|
|
||||||
compare_f comp) __attribute__((always_inline));
|
|
||||||
static inline skew_heap_entry_t *skew_heap_remove(
|
|
||||||
skew_heap_entry_t *a, skew_heap_entry_t *b,
|
|
||||||
compare_f comp) __attribute__((always_inline));
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
skew_heap_init(skew_heap_entry_t *a)
|
|
||||||
{
|
|
||||||
a->left = a->right = a->parent = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline skew_heap_entry_t *
|
|
||||||
skew_heap_merge(skew_heap_entry_t *a, skew_heap_entry_t *b,
|
|
||||||
compare_f comp)
|
|
||||||
{
|
|
||||||
if (a == NULL) return b;
|
|
||||||
else if (b == NULL) return a;
|
|
||||||
|
|
||||||
skew_heap_entry_t *l, *r;
|
|
||||||
if (comp(a, b) == -1)
|
|
||||||
{
|
|
||||||
r = a->left;
|
|
||||||
l = skew_heap_merge(a->right, b, comp);
|
|
||||||
|
|
||||||
a->left = l;
|
|
||||||
a->right = r;
|
|
||||||
if (l) l->parent = a;
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = b->left;
|
|
||||||
l = skew_heap_merge(a, b->right, comp);
|
|
||||||
|
|
||||||
b->left = l;
|
|
||||||
b->right = r;
|
|
||||||
if (l) l->parent = b;
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline skew_heap_entry_t *
|
|
||||||
skew_heap_insert(skew_heap_entry_t *a, skew_heap_entry_t *b,
|
|
||||||
compare_f comp)
|
|
||||||
{
|
|
||||||
skew_heap_init(b);
|
|
||||||
return skew_heap_merge(a, b, comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline skew_heap_entry_t *
|
|
||||||
skew_heap_remove(skew_heap_entry_t *a, skew_heap_entry_t *b,
|
|
||||||
compare_f comp)
|
|
||||||
{
|
|
||||||
skew_heap_entry_t *p = b->parent;
|
|
||||||
skew_heap_entry_t *rep = skew_heap_merge(b->left, b->right, comp);
|
|
||||||
if (rep) rep->parent = p;
|
|
||||||
|
|
||||||
if (p)
|
|
||||||
{
|
|
||||||
if (p->left == b)
|
|
||||||
p->left = rep;
|
|
||||||
else p->right = rep;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
else return rep;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !__LIBS_SKEW_HEAP_H__ */
|
|
@ -1,27 +0,0 @@
|
|||||||
#ifndef __LIBS_STAT_H__
|
|
||||||
#define __LIBS_STAT_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
#define S_IFMT 070000 // mask for type of file
|
|
||||||
#define S_IFREG 010000 // ordinary regular file
|
|
||||||
#define S_IFDIR 020000 // directory
|
|
||||||
#define S_IFLNK 030000 // symbolic link
|
|
||||||
#define S_IFCHR 040000 // character device
|
|
||||||
#define S_IFBLK 050000 // block device
|
|
||||||
|
|
||||||
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) // regular file
|
|
||||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) // directory
|
|
||||||
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) // symlink
|
|
||||||
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) // char device
|
|
||||||
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) // block device
|
|
||||||
|
|
||||||
#endif /* !__LIBS_STAT_H__ */
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
#ifndef __LIBS_STDARG_H__
|
|
||||||
#define __LIBS_STDARG_H__
|
|
||||||
|
|
||||||
/* compiler provides size of save area */
|
|
||||||
typedef __builtin_va_list va_list;
|
|
||||||
|
|
||||||
#define va_start(ap, last) (__builtin_va_start(ap, last))
|
|
||||||
#define va_arg(ap, type) (__builtin_va_arg(ap, type))
|
|
||||||
#define va_end(ap) /*nothing*/
|
|
||||||
|
|
||||||
#endif /* !__LIBS_STDARG_H__ */
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
#ifndef __LIBS_STDIO_H__
|
|
||||||
#define __LIBS_STDIO_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
/* kern/libs/stdio.c */
|
|
||||||
int cprintf(const char *fmt, ...);
|
|
||||||
int vcprintf(const char *fmt, va_list ap);
|
|
||||||
void cputchar(int c);
|
|
||||||
int cputs(const char *str);
|
|
||||||
int getchar(void);
|
|
||||||
|
|
||||||
/* kern/libs/readline.c */
|
|
||||||
char *readline(const char *prompt);
|
|
||||||
|
|
||||||
/* libs/printfmt.c */
|
|
||||||
void printfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, ...);
|
|
||||||
void vprintfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, va_list ap);
|
|
||||||
int snprintf(char *str, size_t size, const char *fmt, ...);
|
|
||||||
int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
|
|
||||||
|
|
||||||
#endif /* !__LIBS_STDIO_H__ */
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
|||||||
#ifndef __LIBS_STDLIB_H__
|
|
||||||
#define __LIBS_STDLIB_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
|
|
||||||
/* the largest number rand will return */
|
|
||||||
#define RAND_MAX 2147483647UL
|
|
||||||
|
|
||||||
/* libs/rand.c */
|
|
||||||
int rand(void);
|
|
||||||
void srand(unsigned int seed);
|
|
||||||
|
|
||||||
/* libs/hash.c */
|
|
||||||
uint32_t hash32(uint32_t val, unsigned int bits);
|
|
||||||
|
|
||||||
#endif /* !__LIBS_RAND_H__ */
|
|
||||||
|
|
@ -1,380 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include <riscv.h>
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strlen - calculate the length of the string @s, not including
|
|
||||||
* the terminating '\0' character.
|
|
||||||
* @s: the input string
|
|
||||||
*
|
|
||||||
* The strlen() function returns the length of string @s.
|
|
||||||
* */
|
|
||||||
size_t
|
|
||||||
strlen(const char *s) {
|
|
||||||
size_t cnt = 0;
|
|
||||||
while (*s ++ != '\0') {
|
|
||||||
cnt ++;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strnlen - calculate the length of the string @s, not including
|
|
||||||
* the terminating '\0' char acter, but at most @len.
|
|
||||||
* @s: the input string
|
|
||||||
* @len: the max-length that function will scan
|
|
||||||
*
|
|
||||||
* Note that, this function looks only at the first @len characters
|
|
||||||
* at @s, and never beyond @s + @len.
|
|
||||||
*
|
|
||||||
* The return value is strlen(s), if that is less than @len, or
|
|
||||||
* @len if there is no '\0' character among the first @len characters
|
|
||||||
* pointed by @s.
|
|
||||||
* */
|
|
||||||
size_t
|
|
||||||
strnlen(const char *s, size_t len) {
|
|
||||||
size_t cnt = 0;
|
|
||||||
while (cnt < len && *s ++ != '\0') {
|
|
||||||
cnt ++;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strcat - appends a copy of the @src string to the @dst string. The terminating null
|
|
||||||
* character in @dst is overwritten by the first character of @src, and a new null-character
|
|
||||||
* is appended at the end of the new string formed by the concatenation of both in @dst.
|
|
||||||
* @dst: pointer to the @dst array, which should be large enough to contain the concatenated
|
|
||||||
* resulting string.
|
|
||||||
* @src: string to be appended, this should not overlap @dst
|
|
||||||
* */
|
|
||||||
char *
|
|
||||||
strcat(char *dst, const char *src) {
|
|
||||||
return strcpy(dst + strlen(dst), src);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strcpy - copies the string pointed by @src into the array pointed by @dst,
|
|
||||||
* including the terminating null character.
|
|
||||||
* @dst: pointer to the destination array where the content is to be copied
|
|
||||||
* @src: string to be copied
|
|
||||||
*
|
|
||||||
* The return value is @dst.
|
|
||||||
*
|
|
||||||
* To avoid overflows, the size of array pointed by @dst should be long enough to
|
|
||||||
* contain the same string as @src (including the terminating null character), and
|
|
||||||
* should not overlap in memory with @src.
|
|
||||||
* */
|
|
||||||
char *
|
|
||||||
strcpy(char *dst, const char *src) {
|
|
||||||
#ifdef __HAVE_ARCH_STRCPY
|
|
||||||
return __strcpy(dst, src);
|
|
||||||
#else
|
|
||||||
char *p = dst;
|
|
||||||
while ((*p ++ = *src ++) != '\0')
|
|
||||||
/* nothing */;
|
|
||||||
return dst;
|
|
||||||
#endif /* __HAVE_ARCH_STRCPY */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strncpy - copies the first @len characters of @src to @dst. If the end of string @src
|
|
||||||
* if found before @len characters have been copied, @dst is padded with '\0' until a
|
|
||||||
* total of @len characters have been written to it.
|
|
||||||
* @dst: pointer to the destination array where the content is to be copied
|
|
||||||
* @src: string to be copied
|
|
||||||
* @len: maximum number of characters to be copied from @src
|
|
||||||
*
|
|
||||||
* The return value is @dst
|
|
||||||
* */
|
|
||||||
char *
|
|
||||||
strncpy(char *dst, const char *src, size_t len) {
|
|
||||||
char *p = dst;
|
|
||||||
while (len > 0) {
|
|
||||||
if ((*p = *src) != '\0') {
|
|
||||||
src ++;
|
|
||||||
}
|
|
||||||
p ++, len --;
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strcmp - compares the string @s1 and @s2
|
|
||||||
* @s1: string to be compared
|
|
||||||
* @s2: string to be compared
|
|
||||||
*
|
|
||||||
* This function starts comparing the first character of each string. If
|
|
||||||
* they are equal to each other, it continues with the following pairs until
|
|
||||||
* the characters differ or until a terminanting null-character is reached.
|
|
||||||
*
|
|
||||||
* Returns an integral value indicating the relationship between the strings:
|
|
||||||
* - A zero value indicates that both strings are equal;
|
|
||||||
* - A value greater than zero indicates that the first character that does
|
|
||||||
* not match has a greater value in @s1 than in @s2;
|
|
||||||
* - And a value less than zero indicates the opposite.
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
strcmp(const char *s1, const char *s2) {
|
|
||||||
#ifdef __HAVE_ARCH_STRCMP
|
|
||||||
return __strcmp(s1, s2);
|
|
||||||
#else
|
|
||||||
while (*s1 != '\0' && *s1 == *s2) {
|
|
||||||
s1 ++, s2 ++;
|
|
||||||
}
|
|
||||||
return (int)((unsigned char)*s1 - (unsigned char)*s2);
|
|
||||||
#endif /* __HAVE_ARCH_STRCMP */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strncmp - compares up to @n characters of the string @s1 to those of the string @s2
|
|
||||||
* @s1: string to be compared
|
|
||||||
* @s2: string to be compared
|
|
||||||
* @n: maximum number of characters to compare
|
|
||||||
*
|
|
||||||
* This function starts comparing the first character of each string. If
|
|
||||||
* they are equal to each other, it continues with the following pairs until
|
|
||||||
* the characters differ, until a terminating null-character is reached, or
|
|
||||||
* until @n characters match in both strings, whichever happens first.
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
strncmp(const char *s1, const char *s2, size_t n) {
|
|
||||||
while (n > 0 && *s1 != '\0' && *s1 == *s2) {
|
|
||||||
n --, s1 ++, s2 ++;
|
|
||||||
}
|
|
||||||
return (n == 0) ? 0 : (int)((unsigned char)*s1 - (unsigned char)*s2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strchr - locates first occurrence of character in string
|
|
||||||
* @s: the input string
|
|
||||||
* @c: character to be located
|
|
||||||
*
|
|
||||||
* The strchr() function returns a pointer to the first occurrence of
|
|
||||||
* character in @s. If the value is not found, the function returns 'NULL'.
|
|
||||||
* */
|
|
||||||
char *
|
|
||||||
strchr(const char *s, char c) {
|
|
||||||
while (*s != '\0') {
|
|
||||||
if (*s == c) {
|
|
||||||
return (char *)s;
|
|
||||||
}
|
|
||||||
s ++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strfind - locates first occurrence of character in string
|
|
||||||
* @s: the input string
|
|
||||||
* @c: character to be located
|
|
||||||
*
|
|
||||||
* The strfind() function is like strchr() except that if @c is
|
|
||||||
* not found in @s, then it returns a pointer to the null byte at the
|
|
||||||
* end of @s, rather than 'NULL'.
|
|
||||||
* */
|
|
||||||
char *
|
|
||||||
strfind(const char *s, char c) {
|
|
||||||
while (*s != '\0') {
|
|
||||||
if (*s == c) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s ++;
|
|
||||||
}
|
|
||||||
return (char *)s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* strtol - converts string to long integer
|
|
||||||
* @s: the input string that contains the representation of an integer number
|
|
||||||
* @endptr: reference to an object of type char *, whose value is set by the
|
|
||||||
* function to the next character in @s after the numerical value. This
|
|
||||||
* parameter can also be a null pointer, in which case it is not used.
|
|
||||||
* @base: x
|
|
||||||
*
|
|
||||||
* The function first discards as many whitespace characters as necessary until
|
|
||||||
* the first non-whitespace character is found. Then, starting from this character,
|
|
||||||
* takes as many characters as possible that are valid following a syntax that
|
|
||||||
* depends on the base parameter, and interprets them as a numerical value. Finally,
|
|
||||||
* a pointer to the first character following the integer representation in @s
|
|
||||||
* is stored in the object pointed by @endptr.
|
|
||||||
*
|
|
||||||
* If the value of base is zero, the syntax expected is similar to that of
|
|
||||||
* integer constants, which is formed by a succession of:
|
|
||||||
* - An optional plus or minus sign;
|
|
||||||
* - An optional prefix indicating octal or hexadecimal base ("0" or "0x" respectively)
|
|
||||||
* - A sequence of decimal digits (if no base prefix was specified) or either octal
|
|
||||||
* or hexadecimal digits if a specific prefix is present
|
|
||||||
*
|
|
||||||
* If the base value is between 2 and 36, the format expected for the integral number
|
|
||||||
* is a succession of the valid digits and/or letters needed to represent integers of
|
|
||||||
* the specified radix (starting from '0' and up to 'z'/'Z' for radix 36). The
|
|
||||||
* sequence may optionally be preceded by a plus or minus sign and, if base is 16,
|
|
||||||
* an optional "0x" or "0X" prefix.
|
|
||||||
*
|
|
||||||
* The strtol() function returns the converted integral number as a long int value.
|
|
||||||
* */
|
|
||||||
long
|
|
||||||
strtol(const char *s, char **endptr, int base) {
|
|
||||||
int neg = 0;
|
|
||||||
long val = 0;
|
|
||||||
|
|
||||||
// gobble initial whitespace
|
|
||||||
while (*s == ' ' || *s == '\t') {
|
|
||||||
s ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// plus/minus sign
|
|
||||||
if (*s == '+') {
|
|
||||||
s ++;
|
|
||||||
}
|
|
||||||
else if (*s == '-') {
|
|
||||||
s ++, neg = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hex or octal base prefix
|
|
||||||
if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x')) {
|
|
||||||
s += 2, base = 16;
|
|
||||||
}
|
|
||||||
else if (base == 0 && s[0] == '0') {
|
|
||||||
s ++, base = 8;
|
|
||||||
}
|
|
||||||
else if (base == 0) {
|
|
||||||
base = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// digits
|
|
||||||
while (1) {
|
|
||||||
int dig;
|
|
||||||
|
|
||||||
if (*s >= '0' && *s <= '9') {
|
|
||||||
dig = *s - '0';
|
|
||||||
}
|
|
||||||
else if (*s >= 'a' && *s <= 'z') {
|
|
||||||
dig = *s - 'a' + 10;
|
|
||||||
}
|
|
||||||
else if (*s >= 'A' && *s <= 'Z') {
|
|
||||||
dig = *s - 'A' + 10;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (dig >= base) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s ++, val = (val * base) + dig;
|
|
||||||
// we don't properly detect overflow!
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endptr) {
|
|
||||||
*endptr = (char *) s;
|
|
||||||
}
|
|
||||||
return (neg ? -val : val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* memset - sets the first @n bytes of the memory area pointed by @s
|
|
||||||
* to the specified value @c.
|
|
||||||
* @s: pointer the the memory area to fill
|
|
||||||
* @c: value to set
|
|
||||||
* @n: number of bytes to be set to the value
|
|
||||||
*
|
|
||||||
* The memset() function returns @s.
|
|
||||||
* */
|
|
||||||
void *
|
|
||||||
memset(void *s, char c, size_t n) {
|
|
||||||
#ifdef __HAVE_ARCH_MEMSET
|
|
||||||
return __memset(s, c, n);
|
|
||||||
#else
|
|
||||||
char *p = s;
|
|
||||||
while (n -- > 0) {
|
|
||||||
*p ++ = c;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
#endif /* __HAVE_ARCH_MEMSET */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* memmove - copies the values of @n bytes from the location pointed by @src to
|
|
||||||
* the memory area pointed by @dst. @src and @dst are allowed to overlap.
|
|
||||||
* @dst pointer to the destination array where the content is to be copied
|
|
||||||
* @src pointer to the source of data to by copied
|
|
||||||
* @n: number of bytes to copy
|
|
||||||
*
|
|
||||||
* The memmove() function returns @dst.
|
|
||||||
* */
|
|
||||||
void *
|
|
||||||
memmove(void *dst, const void *src, size_t n) {
|
|
||||||
#ifdef __HAVE_ARCH_MEMMOVE
|
|
||||||
return __memmove(dst, src, n);
|
|
||||||
#else
|
|
||||||
const char *s = src;
|
|
||||||
char *d = dst;
|
|
||||||
if (s < d && s + n > d) {
|
|
||||||
s += n, d += n;
|
|
||||||
while (n -- > 0) {
|
|
||||||
*-- d = *-- s;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (n -- > 0) {
|
|
||||||
*d ++ = *s ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
#endif /* __HAVE_ARCH_MEMMOVE */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* memcpy - copies the value of @n bytes from the location pointed by @src to
|
|
||||||
* the memory area pointed by @dst.
|
|
||||||
* @dst pointer to the destination array where the content is to be copied
|
|
||||||
* @src pointer to the source of data to by copied
|
|
||||||
* @n: number of bytes to copy
|
|
||||||
*
|
|
||||||
* The memcpy() returns @dst.
|
|
||||||
*
|
|
||||||
* Note that, the function does not check any terminating null character in @src,
|
|
||||||
* it always copies exactly @n bytes. To avoid overflows, the size of arrays pointed
|
|
||||||
* by both @src and @dst, should be at least @n bytes, and should not overlap
|
|
||||||
* (for overlapping memory area, memmove is a safer approach).
|
|
||||||
* */
|
|
||||||
void *
|
|
||||||
memcpy(void *dst, const void *src, size_t n) {
|
|
||||||
#ifdef __HAVE_ARCH_MEMCPY
|
|
||||||
return __memcpy(dst, src, n);
|
|
||||||
#else
|
|
||||||
const char *s = src;
|
|
||||||
char *d = dst;
|
|
||||||
while (n -- > 0) {
|
|
||||||
*d ++ = *s ++;
|
|
||||||
}
|
|
||||||
return dst;
|
|
||||||
#endif /* __HAVE_ARCH_MEMCPY */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* memcmp - compares two blocks of memory
|
|
||||||
* @v1: pointer to block of memory
|
|
||||||
* @v2: pointer to block of memory
|
|
||||||
* @n: number of bytes to compare
|
|
||||||
*
|
|
||||||
* The memcmp() functions returns an integral value indicating the
|
|
||||||
* relationship between the content of the memory blocks:
|
|
||||||
* - A zero value indicates that the contents of both memory blocks are equal;
|
|
||||||
* - A value greater than zero indicates that the first byte that does not
|
|
||||||
* match in both memory blocks has a greater value in @v1 than in @v2
|
|
||||||
* as if evaluated as unsigned char values;
|
|
||||||
* - And a value less than zero indicates the opposite.
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
memcmp(const void *v1, const void *v2, size_t n) {
|
|
||||||
const char *s1 = (const char *)v1;
|
|
||||||
const char *s2 = (const char *)v2;
|
|
||||||
while (n -- > 0) {
|
|
||||||
if (*s1 != *s2) {
|
|
||||||
return (int)((unsigned char)*s1 - (unsigned char)*s2);
|
|
||||||
}
|
|
||||||
s1 ++, s2 ++;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
#ifndef __LIBS_STRING_H__
|
|
||||||
#define __LIBS_STRING_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
|
|
||||||
size_t strlen(const char *s);
|
|
||||||
size_t strnlen(const char *s, size_t len);
|
|
||||||
|
|
||||||
char *strcpy(char *dst, const char *src);
|
|
||||||
char *strncpy(char *dst, const char *src, size_t len);
|
|
||||||
char *strcat(char *dst, const char *src);
|
|
||||||
char *strdup(const char *src);
|
|
||||||
char *stradd(const char *src1, const char *src2);
|
|
||||||
|
|
||||||
int strcmp(const char *s1, const char *s2);
|
|
||||||
int strncmp(const char *s1, const char *s2, size_t n);
|
|
||||||
|
|
||||||
char *strchr(const char *s, char c);
|
|
||||||
char *strfind(const char *s, char c);
|
|
||||||
long strtol(const char *s, char **endptr, int base);
|
|
||||||
|
|
||||||
void *memset(void *s, char c, size_t n);
|
|
||||||
void *memmove(void *dst, const void *src, size_t n);
|
|
||||||
void *memcpy(void *dst, const void *src, size_t n);
|
|
||||||
int memcmp(const void *v1, const void *v2, size_t n);
|
|
||||||
|
|
||||||
#endif /* !__LIBS_STRING_H__ */
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
#ifndef __LIBS_UNISTD_H__
|
|
||||||
#define __LIBS_UNISTD_H__
|
|
||||||
|
|
||||||
#define T_SYSCALL 0x80
|
|
||||||
|
|
||||||
/* syscall number */
|
|
||||||
#define SYS_exit 1
|
|
||||||
#define SYS_fork 2
|
|
||||||
#define SYS_wait 3
|
|
||||||
#define SYS_exec 4
|
|
||||||
#define SYS_clone 5
|
|
||||||
#define SYS_yield 10
|
|
||||||
#define SYS_sleep 11
|
|
||||||
#define SYS_kill 12
|
|
||||||
#define SYS_gettime 17
|
|
||||||
#define SYS_getpid 18
|
|
||||||
#define SYS_mmap 20
|
|
||||||
#define SYS_munmap 21
|
|
||||||
#define SYS_shmem 22
|
|
||||||
#define SYS_putc 30
|
|
||||||
#define SYS_pgdir 31
|
|
||||||
#define SYS_open 100
|
|
||||||
#define SYS_close 101
|
|
||||||
#define SYS_read 102
|
|
||||||
#define SYS_write 103
|
|
||||||
#define SYS_seek 104
|
|
||||||
#define SYS_fstat 110
|
|
||||||
#define SYS_fsync 111
|
|
||||||
#define SYS_getcwd 121
|
|
||||||
#define SYS_getdirentry 128
|
|
||||||
#define SYS_dup 130
|
|
||||||
/* OLNY FOR LAB6 */
|
|
||||||
#define SYS_lab6_set_priority 255
|
|
||||||
|
|
||||||
/* SYS_fork flags */
|
|
||||||
#define CLONE_VM 0x00000100 // set if VM shared between processes
|
|
||||||
#define CLONE_THREAD 0x00000200 // thread group
|
|
||||||
#define CLONE_FS 0x00000800 // set if shared between processes
|
|
||||||
|
|
||||||
/* VFS flags */
|
|
||||||
// flags for open: choose one of these
|
|
||||||
#define O_RDONLY 0 // open for reading only
|
|
||||||
#define O_WRONLY 1 // open for writing only
|
|
||||||
#define O_RDWR 2 // open for reading and writing
|
|
||||||
// then or in any of these:
|
|
||||||
#define O_CREAT 0x00000004 // create file if it does not exist
|
|
||||||
#define O_EXCL 0x00000008 // error if O_CREAT and the file exists
|
|
||||||
#define O_TRUNC 0x00000010 // truncate file upon open
|
|
||||||
#define O_APPEND 0x00000020 // append on each write
|
|
||||||
// additonal related definition
|
|
||||||
#define O_ACCMODE 3 // mask for O_RDONLY / O_WRONLY / O_RDWR
|
|
||||||
|
|
||||||
#define NO_FD -0x9527 // invalid fd
|
|
||||||
|
|
||||||
/* lseek codes */
|
|
||||||
#define LSEEK_SET 0 // seek relative to beginning of file
|
|
||||||
#define LSEEK_CUR 1 // seek relative to current position in file
|
|
||||||
#define LSEEK_END 2 // seek relative to end of file
|
|
||||||
|
|
||||||
#define FS_MAX_DNAME_LEN 31
|
|
||||||
#define FS_MAX_FNAME_LEN 255
|
|
||||||
#define FS_MAX_FPATH_LEN 4095
|
|
||||||
|
|
||||||
#define EXEC_MAX_ARG_NUM 32
|
|
||||||
#define EXEC_MAX_ARG_LEN 4095
|
|
||||||
|
|
||||||
#endif /* !__LIBS_UNISTD_H__ */
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
#include <defs.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
#include <stat.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <file.h>
|
|
||||||
#include <dir.h>
|
|
||||||
#include <error.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
DIR dir, *dirp=&dir;
|
|
||||||
DIR *
|
|
||||||
opendir(const char *path) {
|
|
||||||
|
|
||||||
if ((dirp->fd = open(path, O_RDONLY)) < 0) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
struct stat __stat, *stat = &__stat;
|
|
||||||
if (fstat(dirp->fd, stat) != 0 || !S_ISDIR(stat->st_mode)) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
dirp->dirent.offset = 0;
|
|
||||||
return dirp;
|
|
||||||
|
|
||||||
failed:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dirent *
|
|
||||||
readdir(DIR *dirp) {
|
|
||||||
if (sys_getdirentry(dirp->fd, &(dirp->dirent)) == 0) {
|
|
||||||
return &(dirp->dirent);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
closedir(DIR *dirp) {
|
|
||||||
close(dirp->fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
getcwd(char *buffer, size_t len) {
|
|
||||||
return sys_getcwd(buffer, len);
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
|||||||
#ifndef __USER_LIBS_DIR_H__
|
|
||||||
#define __USER_LIBS_DIR_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int fd;
|
|
||||||
struct dirent dirent;
|
|
||||||
} DIR;
|
|
||||||
|
|
||||||
DIR *opendir(const char *path);
|
|
||||||
struct dirent *readdir(DIR *dirp);
|
|
||||||
void closedir(DIR *dirp);
|
|
||||||
int chdir(const char *path);
|
|
||||||
int getcwd(char *buffer, size_t len);
|
|
||||||
|
|
||||||
#endif /* !__USER_LIBS_DIR_H__ */
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
#include <defs.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stat.h>
|
|
||||||
#include <error.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
open(const char *path, uint32_t open_flags) {
|
|
||||||
return sys_open(path, open_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
close(int fd) {
|
|
||||||
return sys_close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
read(int fd, void *base, size_t len) {
|
|
||||||
return sys_read(fd, base, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
write(int fd, void *base, size_t len) {
|
|
||||||
return sys_write(fd, base, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
seek(int fd, off_t pos, int whence) {
|
|
||||||
return sys_seek(fd, pos, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fstat(int fd, struct stat *stat) {
|
|
||||||
return sys_fstat(fd, stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fsync(int fd) {
|
|
||||||
return sys_fsync(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dup2(int fd1, int fd2) {
|
|
||||||
return sys_dup(fd1, fd2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char
|
|
||||||
transmode(struct stat *stat) {
|
|
||||||
uint32_t mode = stat->st_mode;
|
|
||||||
if (S_ISREG(mode)) return 'r';
|
|
||||||
if (S_ISDIR(mode)) return 'd';
|
|
||||||
if (S_ISLNK(mode)) return 'l';
|
|
||||||
if (S_ISCHR(mode)) return 'c';
|
|
||||||
if (S_ISBLK(mode)) return 'b';
|
|
||||||
return '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
print_stat(const char *name, int fd, struct stat *stat) {
|
|
||||||
cprintf("[%03d] %s\n", fd, name);
|
|
||||||
cprintf(" mode : %c\n", transmode(stat));
|
|
||||||
cprintf(" links : %lu\n", stat->st_nlinks);
|
|
||||||
cprintf(" blocks : %lu\n", stat->st_blocks);
|
|
||||||
cprintf(" size : %lu\n", stat->st_size);
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
#ifndef __USER_LIBS_FILE_H__
|
|
||||||
#define __USER_LIBS_FILE_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
|
|
||||||
struct stat;
|
|
||||||
|
|
||||||
int open(const char *path, uint32_t open_flags);
|
|
||||||
int close(int fd);
|
|
||||||
int read(int fd, void *base, size_t len);
|
|
||||||
int write(int fd, void *base, size_t len);
|
|
||||||
int seek(int fd, off_t pos, int whence);
|
|
||||||
int fstat(int fd, struct stat *stat);
|
|
||||||
int fsync(int fd);
|
|
||||||
int dup(int fd);
|
|
||||||
int dup2(int fd1, int fd2);
|
|
||||||
int pipe(int *fd_store);
|
|
||||||
int mkfifo(const char *name, uint32_t open_flags);
|
|
||||||
|
|
||||||
void print_stat(const char *name, int fd, struct stat *stat);
|
|
||||||
|
|
||||||
#endif /* !__USER_LIBS_FILE_H__ */
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
|||||||
#ifndef __USER_LIBS_LOCK_H__
|
|
||||||
#define __USER_LIBS_LOCK_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
#include <atomic.h>
|
|
||||||
#include <ulib.h>
|
|
||||||
|
|
||||||
#define INIT_LOCK {0}
|
|
||||||
|
|
||||||
typedef volatile bool lock_t;
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
lock_init(lock_t *l) {
|
|
||||||
*l = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
try_lock(lock_t *l) {
|
|
||||||
return test_and_set_bit(0, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
lock(lock_t *l) {
|
|
||||||
if (try_lock(l)) {
|
|
||||||
int step = 0;
|
|
||||||
do {
|
|
||||||
yield();
|
|
||||||
if (++ step == 100) {
|
|
||||||
step = 0;
|
|
||||||
sleep(10);
|
|
||||||
}
|
|
||||||
} while (try_lock(l));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
unlock(lock_t *l) {
|
|
||||||
test_and_clear_bit(0, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !__USER_LIBS_LOCK_H__ */
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
#include <defs.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ulib.h>
|
|
||||||
#include <error.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
__panic(const char *file, int line, const char *fmt, ...) {
|
|
||||||
// print the 'message'
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
cprintf("user panic at %s:%d:\n ", file, line);
|
|
||||||
vcprintf(fmt, ap);
|
|
||||||
cprintf("\n");
|
|
||||||
va_end(ap);
|
|
||||||
exit(-E_PANIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__warn(const char *file, int line, const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
cprintf("user warning at %s:%d:\n ", file, line);
|
|
||||||
vcprintf(fmt, ap);
|
|
||||||
cprintf("\n");
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
|||||||
#include <defs.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
#include <file.h>
|
|
||||||
#include <ulib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* cputch - writes a single character @c to stdout, and it will
|
|
||||||
* increace the value of counter pointed by @cnt.
|
|
||||||
* */
|
|
||||||
static void
|
|
||||||
cputch(int c, int *cnt) {
|
|
||||||
sys_putc(c);
|
|
||||||
(*cnt) ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* vcprintf - format a string and writes it to stdout
|
|
||||||
*
|
|
||||||
* The return value is the number of characters which would be
|
|
||||||
* written to stdout.
|
|
||||||
*
|
|
||||||
* Call this function if you are already dealing with a va_list.
|
|
||||||
* Or you probably want cprintf() instead.
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
vcprintf(const char *fmt, va_list ap) {
|
|
||||||
int cnt = 0;
|
|
||||||
vprintfmt((void*)cputch, NO_FD, &cnt, fmt, ap);
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* cprintf - formats a string and writes it to stdout
|
|
||||||
*
|
|
||||||
* The return value is the number of characters which would be
|
|
||||||
* written to stdout.
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
cprintf(const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
int cnt = vcprintf(fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* *
|
|
||||||
* cputs- writes the string pointed by @str to stdout and
|
|
||||||
* appends a newline character.
|
|
||||||
* */
|
|
||||||
int
|
|
||||||
cputs(const char *str) {
|
|
||||||
int cnt = 0;
|
|
||||||
char c;
|
|
||||||
while ((c = *str ++) != '\0') {
|
|
||||||
cputch(c, &cnt);
|
|
||||||
}
|
|
||||||
cputch('\n', &cnt);
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
fputch(char c, int *cnt, int fd) {
|
|
||||||
write(fd, &c, sizeof(char));
|
|
||||||
(*cnt) ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
vfprintf(int fd, const char *fmt, va_list ap) {
|
|
||||||
int cnt = 0;
|
|
||||||
vprintfmt((void*)fputch, fd, &cnt, fmt, ap);
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fprintf(int fd, const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
int cnt = vfprintf(fd, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return cnt;
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
#include <defs.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
#include <stat.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_ARGS 5
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
syscall(int num, ...) {
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, num);
|
|
||||||
uint32_t a[MAX_ARGS];
|
|
||||||
int i, ret;
|
|
||||||
for (i = 0; i < MAX_ARGS; i ++) {
|
|
||||||
a[i] = va_arg(ap, uint32_t);
|
|
||||||
}
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
asm volatile (
|
|
||||||
"lw a0, %1\n"
|
|
||||||
"lw a1, %2\n"
|
|
||||||
"lw a2, %3\n"
|
|
||||||
"lw a3, %4\n"
|
|
||||||
"lw a4, %5\n"
|
|
||||||
"lw a5, %6\n"
|
|
||||||
"ecall\n"
|
|
||||||
"sw a0, %0"
|
|
||||||
: "=m" (ret)
|
|
||||||
: "m" (num),
|
|
||||||
"m" (a[0]),
|
|
||||||
"m" (a[1]),
|
|
||||||
"m" (a[2]),
|
|
||||||
"m" (a[3]),
|
|
||||||
"m" (a[4])
|
|
||||||
: "memory"
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_exit(int error_code) {
|
|
||||||
return syscall(SYS_exit, error_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_fork(void) {
|
|
||||||
return syscall(SYS_fork);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_wait(int pid, int *store) {
|
|
||||||
return syscall(SYS_wait, pid, store);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_yield(void) {
|
|
||||||
return syscall(SYS_yield);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_kill(int pid) {
|
|
||||||
return syscall(SYS_kill, pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_getpid(void) {
|
|
||||||
return syscall(SYS_getpid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_putc(int c) {
|
|
||||||
return syscall(SYS_putc, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_pgdir(void) {
|
|
||||||
return syscall(SYS_pgdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_lab6_set_priority(uint32_t priority)
|
|
||||||
{
|
|
||||||
syscall(SYS_lab6_set_priority, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_sleep(unsigned int time) {
|
|
||||||
return syscall(SYS_sleep, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_gettime(void) {
|
|
||||||
return syscall(SYS_gettime);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_exec(const char *name, int argc, const char **argv) {
|
|
||||||
return syscall(SYS_exec, name, argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_open(const char *path, uint32_t open_flags) {
|
|
||||||
return syscall(SYS_open, path, open_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_close(int fd) {
|
|
||||||
return syscall(SYS_close, fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_read(int fd, void *base, size_t len) {
|
|
||||||
return syscall(SYS_read, fd, base, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_write(int fd, void *base, size_t len) {
|
|
||||||
return syscall(SYS_write, fd, base, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_seek(int fd, off_t pos, int whence) {
|
|
||||||
return syscall(SYS_seek, fd, pos, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_fstat(int fd, struct stat *stat) {
|
|
||||||
return syscall(SYS_fstat, fd, stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_fsync(int fd) {
|
|
||||||
return syscall(SYS_fsync, fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_getcwd(char *buffer, size_t len) {
|
|
||||||
return syscall(SYS_getcwd, buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_getdirentry(int fd, struct dirent *dirent) {
|
|
||||||
return syscall(SYS_getdirentry, fd, dirent);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sys_dup(int fd1, int fd2) {
|
|
||||||
return syscall(SYS_dup, fd1, fd2);
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef __USER_LIBS_SYSCALL_H__
|
|
||||||
#define __USER_LIBS_SYSCALL_H__
|
|
||||||
|
|
||||||
int sys_exit(int error_code);
|
|
||||||
int sys_fork(void);
|
|
||||||
int sys_wait(int pid, int *store);
|
|
||||||
int sys_exec(const char *name, int argc, const char **argv);
|
|
||||||
int sys_yield(void);
|
|
||||||
int sys_kill(int pid);
|
|
||||||
int sys_getpid(void);
|
|
||||||
int sys_putc(int c);
|
|
||||||
int sys_pgdir(void);
|
|
||||||
int sys_sleep(unsigned int time);
|
|
||||||
int sys_gettime(void);
|
|
||||||
|
|
||||||
struct stat;
|
|
||||||
struct dirent;
|
|
||||||
|
|
||||||
int sys_open(const char *path, uint32_t open_flags);
|
|
||||||
int sys_close(int fd);
|
|
||||||
int sys_read(int fd, void *base, size_t len);
|
|
||||||
int sys_write(int fd, void *base, size_t len);
|
|
||||||
int sys_seek(int fd, off_t pos, int whence);
|
|
||||||
int sys_fstat(int fd, struct stat *stat);
|
|
||||||
int sys_fsync(int fd);
|
|
||||||
int sys_getcwd(char *buffer, size_t len);
|
|
||||||
int sys_getdirentry(int fd, struct dirent *dirent);
|
|
||||||
int sys_dup(int fd1, int fd2);
|
|
||||||
void sys_lab6_set_priority(uint32_t priority); //only for lab6
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__USER_LIBS_SYSCALL_H__ */
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
|||||||
#include <defs.h>
|
|
||||||
#include <syscall.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ulib.h>
|
|
||||||
#include <stat.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <lock.h>
|
|
||||||
|
|
||||||
static lock_t fork_lock = INIT_LOCK;
|
|
||||||
|
|
||||||
void
|
|
||||||
lock_fork(void) {
|
|
||||||
lock(&fork_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
unlock_fork(void) {
|
|
||||||
unlock(&fork_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
exit(int error_code) {
|
|
||||||
sys_exit(error_code);
|
|
||||||
cprintf("BUG: exit failed.\n");
|
|
||||||
while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fork(void) {
|
|
||||||
return sys_fork();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
wait(void) {
|
|
||||||
return sys_wait(0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
waitpid(int pid, int *store) {
|
|
||||||
return sys_wait(pid, store);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
yield(void) {
|
|
||||||
sys_yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kill(int pid) {
|
|
||||||
return sys_kill(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
getpid(void) {
|
|
||||||
return sys_getpid();
|
|
||||||
}
|
|
||||||
|
|
||||||
//print_pgdir - print the PDT&PT
|
|
||||||
void
|
|
||||||
print_pgdir(void) {
|
|
||||||
sys_pgdir();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
lab6_set_priority(uint32_t priority)
|
|
||||||
{
|
|
||||||
sys_lab6_set_priority(priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sleep(unsigned int time) {
|
|
||||||
return sys_sleep(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
gettime_msec(void) {
|
|
||||||
return (unsigned int)sys_gettime();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__exec(const char *name, const char **argv) {
|
|
||||||
int argc = 0;
|
|
||||||
while (argv[argc] != NULL) {
|
|
||||||
argc ++;
|
|
||||||
}
|
|
||||||
return sys_exec(name, argc, argv);
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
#ifndef __USER_LIBS_ULIB_H__
|
|
||||||
#define __USER_LIBS_ULIB_H__
|
|
||||||
|
|
||||||
#include <defs.h>
|
|
||||||
|
|
||||||
void __warn(const char *file, int line, const char *fmt, ...);
|
|
||||||
void __noreturn __panic(const char *file, int line, const char *fmt, ...);
|
|
||||||
|
|
||||||
#define warn(...) \
|
|
||||||
__warn(__FILE__, __LINE__, __VA_ARGS__)
|
|
||||||
|
|
||||||
#define panic(...) \
|
|
||||||
__panic(__FILE__, __LINE__, __VA_ARGS__)
|
|
||||||
|
|
||||||
#define assert(x) \
|
|
||||||
do { \
|
|
||||||
if (!(x)) { \
|
|
||||||
panic("assertion failed: %s", #x); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
// static_assert(x) will generate a compile-time error if 'x' is false.
|
|
||||||
#define static_assert(x) \
|
|
||||||
switch (x) { case 0: case (x): ; }
|
|
||||||
|
|
||||||
int fprintf(int fd, const char *fmt, ...);
|
|
||||||
|
|
||||||
void __noreturn exit(int error_code);
|
|
||||||
int fork(void);
|
|
||||||
int wait(void);
|
|
||||||
int waitpid(int pid, int *store);
|
|
||||||
void yield(void);
|
|
||||||
int kill(int pid);
|
|
||||||
int getpid(void);
|
|
||||||
void print_pgdir(void);
|
|
||||||
int sleep(unsigned int time);
|
|
||||||
unsigned int gettime_msec(void);
|
|
||||||
int __exec(const char *name, const char **argv);
|
|
||||||
|
|
||||||
#define __exec0(name, path, ...) \
|
|
||||||
({ const char *argv[] = {path, ##__VA_ARGS__, NULL}; __exec(name, argv); })
|
|
||||||
|
|
||||||
#define exec(path, ...) __exec0(NULL, path, ##__VA_ARGS__)
|
|
||||||
#define nexec(name, path, ...) __exec0(name, path, ##__VA_ARGS__)
|
|
||||||
|
|
||||||
void lab6_set_priority(uint32_t priority); //only for lab6
|
|
||||||
|
|
||||||
#endif /* !__USER_LIBS_ULIB_H__ */
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
#include <ulib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <file.h>
|
|
||||||
#include <stat.h>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]);
|
|
||||||
|
|
||||||
static int
|
|
||||||
initfd(int fd2, const char *path, uint32_t open_flags) {
|
|
||||||
int fd1, ret;
|
|
||||||
if ((fd1 = open(path, open_flags)) < 0) {
|
|
||||||
return fd1;
|
|
||||||
}
|
|
||||||
if (fd1 != fd2) {
|
|
||||||
close(fd2);
|
|
||||||
ret = dup2(fd1, fd2);
|
|
||||||
close(fd1);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
umain(int argc, char *argv[]) {
|
|
||||||
int fd;
|
|
||||||
if ((fd = initfd(0, "stdin:", O_RDONLY)) < 0) {
|
|
||||||
warn("open <stdin> failed: %e.\n", fd);
|
|
||||||
}
|
|
||||||
if ((fd = initfd(1, "stdout:", O_WRONLY)) < 0) {
|
|
||||||
warn("open <stdout> failed: %e.\n", fd);
|
|
||||||
}
|
|
||||||
int ret = main(argc, argv);
|
|
||||||
exit(ret);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in new issue