add lab answers

This commit is contained in:
chyyuu
2014-08-20 15:42:20 +08:00
parent d9ec12887b
commit f9773095fe
731 changed files with 92876 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
#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));
/* *
* 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) {
asm volatile ("btsl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
}
/* *
* 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) {
asm volatile ("btrl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
}
/* *
* 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) {
asm volatile ("btcl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr));
}
/* *
* 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) {
int oldbit;
asm volatile ("btl %2, %1; sbbl %0,%0" : "=r" (oldbit) : "m" (*(volatile long *)addr), "Ir" (nr));
return oldbit != 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) {
int oldbit;
asm volatile ("btsl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory");
return oldbit != 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) {
int oldbit;
asm volatile ("btrl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory");
return oldbit != 0;
}
#endif /* !__LIBS_ATOMIC_H__ */

View File

@@ -0,0 +1,68 @@
#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))
/* Represents true-or-false values */
typedef int 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 int32_t intptr_t;
typedef uint32_t uintptr_t;
/* size_t is used for memory object sizes */
typedef uintptr_t size_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)); \
})
/* 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__ */

View File

@@ -0,0 +1,48 @@
#ifndef __LIBS_ELF_H__
#define __LIBS_ELF_H__
#include <defs.h>
#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
uint32_t e_entry; // entry point if executable
uint32_t e_phoff; // file position of program header or 0
uint32_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_offset; // file offset of segment
uint32_t p_va; // virtual address to map segment
uint32_t p_pa; // physical address, not used
uint32_t p_filesz; // size of segment in file
uint32_t p_memsz; // size of segment in memory (bigger if contains bss
uint32_t p_flags; // read/write/execute bits
uint32_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__ */

View File

@@ -0,0 +1,33 @@
#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__ */

View File

@@ -0,0 +1,18 @@
#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));
}

View File

@@ -0,0 +1,163 @@
#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__ */

View File

@@ -0,0 +1,343 @@
#include <defs.h>
#include <x86.h>
#include <error.h>
#include <stdio.h>
#include <string.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",
};
/* *
* printnum - print a number (base <= 16) in reverse order
* @putch: specified putch function, print a single character
* @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*), 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, putdat, result, base, width - 1, padc);
} else {
// print any needed pad characters before first digit
while (-- width > 0)
putch(padc, putdat);
}
// then print this (the least significant) digit
putch("0123456789abcdef"[mod], putdat);
}
/* *
* 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
* @putdat: used by @putch function
* @fmt: the format string to use
* */
void
printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vprintfmt(putch, 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
* @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*), 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);
}
// 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);
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, putdat, "error %d", err);
}
else {
printfmt(putch, 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);
}
}
for (; (ch = *p ++) != '\0' && (precision < 0 || -- precision >= 0); width --) {
if (altflag && (ch < ' ' || ch > '~')) {
putch('?', putdat);
}
else {
putch(ch, putdat);
}
}
for (; width > 0; width --) {
putch(' ', putdat);
}
break;
// (signed) decimal
case 'd':
num = getint(&ap, lflag);
if ((long long)num < 0) {
putch('-', putdat);
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);
putch('x', putdat);
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, putdat, num, base, width, padc);
break;
// escaped '%' character
case '%':
putch(ch, putdat);
break;
// unrecognized escape sequence - just print it literally
default:
putch('%', putdat);
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, &b, fmt, ap);
// null terminate the buffer
*b.buf = '\0';
return b.cnt;
}

View File

@@ -0,0 +1,26 @@
#include <x86.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;
}

View File

@@ -0,0 +1,87 @@
#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__ */

View File

@@ -0,0 +1,12 @@
#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__ */

View File

@@ -0,0 +1,24 @@
#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 *), void *putdat, const char *fmt, ...);
void vprintfmt(void (*putch)(int, void *), 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__ */

View File

@@ -0,0 +1,17 @@
#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__ */

View File

@@ -0,0 +1,367 @@
#include <string.h>
#include <x86.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;
}
/* *
* 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;
}

View File

@@ -0,0 +1,25 @@
#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);
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__ */

View File

@@ -0,0 +1,31 @@
#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_brk 19
#define SYS_mmap 20
#define SYS_munmap 21
#define SYS_shmem 22
#define SYS_putc 30
#define SYS_pgdir 31
/* 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
#endif /* !__LIBS_UNISTD_H__ */

View File

@@ -0,0 +1,302 @@
#ifndef __LIBS_X86_H__
#define __LIBS_X86_H__
#include <defs.h>
#define do_div(n, base) ({ \
unsigned long __upper, __low, __high, __mod, __base; \
__base = (base); \
asm ("" : "=a" (__low), "=d" (__high) : "A" (n)); \
__upper = __high; \
if (__high != 0) { \
__upper = __high % __base; \
__high = __high / __base; \
} \
asm ("divl %2" : "=a" (__low), "=d" (__mod) \
: "rm" (__base), "0" (__low), "1" (__upper)); \
asm ("" : "=A" (n) : "a" (__low), "d" (__high)); \
__mod; \
})
#define barrier() __asm__ __volatile__ ("" ::: "memory")
static inline uint8_t inb(uint16_t port) __attribute__((always_inline));
static inline void insl(uint32_t port, void *addr, int cnt) __attribute__((always_inline));
static inline void outb(uint16_t port, uint8_t data) __attribute__((always_inline));
static inline void outw(uint16_t port, uint16_t data) __attribute__((always_inline));
static inline void outsl(uint32_t port, const void *addr, int cnt) __attribute__((always_inline));
static inline uint32_t read_ebp(void) __attribute__((always_inline));
static inline void breakpoint(void) __attribute__((always_inline));
static inline uint32_t read_dr(unsigned regnum) __attribute__((always_inline));
static inline void write_dr(unsigned regnum, uint32_t value) __attribute__((always_inline));
/* Pseudo-descriptors used for LGDT, LLDT(not used) and LIDT instructions. */
struct pseudodesc {
uint16_t pd_lim; // Limit
uintptr_t pd_base; // Base address
} __attribute__ ((packed));
static inline void lidt(struct pseudodesc *pd) __attribute__((always_inline));
static inline void sti(void) __attribute__((always_inline));
static inline void cli(void) __attribute__((always_inline));
static inline void ltr(uint16_t sel) __attribute__((always_inline));
static inline uint32_t read_eflags(void) __attribute__((always_inline));
static inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
static inline void lcr0(uintptr_t cr0) __attribute__((always_inline));
static inline void lcr3(uintptr_t cr3) __attribute__((always_inline));
static inline uintptr_t rcr0(void) __attribute__((always_inline));
static inline uintptr_t rcr1(void) __attribute__((always_inline));
static inline uintptr_t rcr2(void) __attribute__((always_inline));
static inline uintptr_t rcr3(void) __attribute__((always_inline));
static inline void invlpg(void *addr) __attribute__((always_inline));
static inline uint8_t
inb(uint16_t port) {
uint8_t data;
asm volatile ("inb %1, %0" : "=a" (data) : "d" (port) : "memory");
return data;
}
static inline void
insl(uint32_t port, void *addr, int cnt) {
asm volatile (
"cld;"
"repne; insl;"
: "=D" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "memory", "cc");
}
static inline void
outb(uint16_t port, uint8_t data) {
asm volatile ("outb %0, %1" :: "a" (data), "d" (port) : "memory");
}
static inline void
outw(uint16_t port, uint16_t data) {
asm volatile ("outw %0, %1" :: "a" (data), "d" (port) : "memory");
}
static inline void
outsl(uint32_t port, const void *addr, int cnt) {
asm volatile (
"cld;"
"repne; outsl;"
: "=S" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "memory", "cc");
}
static inline uint32_t
read_ebp(void) {
uint32_t ebp;
asm volatile ("movl %%ebp, %0" : "=r" (ebp));
return ebp;
}
static inline void
breakpoint(void) {
asm volatile ("int $3");
}
static inline uint32_t
read_dr(unsigned regnum) {
uint32_t value = 0;
switch (regnum) {
case 0: asm volatile ("movl %%db0, %0" : "=r" (value)); break;
case 1: asm volatile ("movl %%db1, %0" : "=r" (value)); break;
case 2: asm volatile ("movl %%db2, %0" : "=r" (value)); break;
case 3: asm volatile ("movl %%db3, %0" : "=r" (value)); break;
case 6: asm volatile ("movl %%db6, %0" : "=r" (value)); break;
case 7: asm volatile ("movl %%db7, %0" : "=r" (value)); break;
}
return value;
}
static void
write_dr(unsigned regnum, uint32_t value) {
switch (regnum) {
case 0: asm volatile ("movl %0, %%db0" :: "r" (value)); break;
case 1: asm volatile ("movl %0, %%db1" :: "r" (value)); break;
case 2: asm volatile ("movl %0, %%db2" :: "r" (value)); break;
case 3: asm volatile ("movl %0, %%db3" :: "r" (value)); break;
case 6: asm volatile ("movl %0, %%db6" :: "r" (value)); break;
case 7: asm volatile ("movl %0, %%db7" :: "r" (value)); break;
}
}
static inline void
lidt(struct pseudodesc *pd) {
asm volatile ("lidt (%0)" :: "r" (pd) : "memory");
}
static inline void
sti(void) {
asm volatile ("sti");
}
static inline void
cli(void) {
asm volatile ("cli" ::: "memory");
}
static inline void
ltr(uint16_t sel) {
asm volatile ("ltr %0" :: "r" (sel) : "memory");
}
static inline uint32_t
read_eflags(void) {
uint32_t eflags;
asm volatile ("pushfl; popl %0" : "=r" (eflags));
return eflags;
}
static inline void
write_eflags(uint32_t eflags) {
asm volatile ("pushl %0; popfl" :: "r" (eflags));
}
static inline void
lcr0(uintptr_t cr0) {
asm volatile ("mov %0, %%cr0" :: "r" (cr0) : "memory");
}
static inline void
lcr3(uintptr_t cr3) {
asm volatile ("mov %0, %%cr3" :: "r" (cr3) : "memory");
}
static inline uintptr_t
rcr0(void) {
uintptr_t cr0;
asm volatile ("mov %%cr0, %0" : "=r" (cr0) :: "memory");
return cr0;
}
static inline uintptr_t
rcr1(void) {
uintptr_t cr1;
asm volatile ("mov %%cr1, %0" : "=r" (cr1) :: "memory");
return cr1;
}
static inline uintptr_t
rcr2(void) {
uintptr_t cr2;
asm volatile ("mov %%cr2, %0" : "=r" (cr2) :: "memory");
return cr2;
}
static inline uintptr_t
rcr3(void) {
uintptr_t cr3;
asm volatile ("mov %%cr3, %0" : "=r" (cr3) :: "memory");
return cr3;
}
static inline void
invlpg(void *addr) {
asm volatile ("invlpg (%0)" :: "r" (addr) : "memory");
}
static inline int __strcmp(const char *s1, const char *s2) __attribute__((always_inline));
static inline char *__strcpy(char *dst, const char *src) __attribute__((always_inline));
static inline void *__memset(void *s, char c, size_t n) __attribute__((always_inline));
static inline void *__memmove(void *dst, const void *src, size_t n) __attribute__((always_inline));
static inline void *__memcpy(void *dst, const void *src, size_t n) __attribute__((always_inline));
#ifndef __HAVE_ARCH_STRCMP
#define __HAVE_ARCH_STRCMP
static inline int
__strcmp(const char *s1, const char *s2) {
int d0, d1, ret;
asm volatile (
"1: lodsb;"
"scasb;"
"jne 2f;"
"testb %%al, %%al;"
"jne 1b;"
"xorl %%eax, %%eax;"
"jmp 3f;"
"2: sbbl %%eax, %%eax;"
"orb $1, %%al;"
"3:"
: "=a" (ret), "=&S" (d0), "=&D" (d1)
: "1" (s1), "2" (s2)
: "memory");
return ret;
}
#endif /* __HAVE_ARCH_STRCMP */
#ifndef __HAVE_ARCH_STRCPY
#define __HAVE_ARCH_STRCPY
static inline char *
__strcpy(char *dst, const char *src) {
int d0, d1, d2;
asm volatile (
"1: lodsb;"
"stosb;"
"testb %%al, %%al;"
"jne 1b;"
: "=&S" (d0), "=&D" (d1), "=&a" (d2)
: "0" (src), "1" (dst) : "memory");
return dst;
}
#endif /* __HAVE_ARCH_STRCPY */
#ifndef __HAVE_ARCH_MEMSET
#define __HAVE_ARCH_MEMSET
static inline void *
__memset(void *s, char c, size_t n) {
int d0, d1;
asm volatile (
"rep; stosb;"
: "=&c" (d0), "=&D" (d1)
: "0" (n), "a" (c), "1" (s)
: "memory");
return s;
}
#endif /* __HAVE_ARCH_MEMSET */
#ifndef __HAVE_ARCH_MEMMOVE
#define __HAVE_ARCH_MEMMOVE
static inline void *
__memmove(void *dst, const void *src, size_t n) {
if (dst < src) {
return __memcpy(dst, src, n);
}
int d0, d1, d2;
asm volatile (
"std;"
"rep; movsb;"
"cld;"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
: "0" (n), "1" (n - 1 + src), "2" (n - 1 + dst)
: "memory");
return dst;
}
#endif /* __HAVE_ARCH_MEMMOVE */
#ifndef __HAVE_ARCH_MEMCPY
#define __HAVE_ARCH_MEMCPY
static inline void *
__memcpy(void *dst, const void *src, size_t n) {
int d0, d1, d2;
asm volatile (
"rep; movsl;"
"movl %4, %%ecx;"
"andl $3, %%ecx;"
"jz 1f;"
"rep; movsb;"
"1:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
: "0" (n / 4), "g" (n), "1" (dst), "2" (src)
: "memory");
return dst;
}
#endif /* __HAVE_ARCH_MEMCPY */
#endif /* !__LIBS_X86_H__ */