From: John Tsiombikas Date: Thu, 12 Nov 2020 04:52:42 +0000 (+0200) Subject: cleanup X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=rpikern;a=commitdiff_plain;h=32ccc707bc0821d7ff4248fe9f58e92e9c6ebef9 cleanup --- diff --git a/Makefile b/Makefile index ac7afa8..24a3fb6 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,8 @@ endif warn = -pedantic -Wall dbg = -g -inc = -Isrc/libc -gccopt = -marm -fpic -ffreestanding -nostdinc +inc = -Isrc -Isrc/libc +gccopt = -marm -fpic -ffreestanding -nostdinc -ffast-math -fno-math-errno #arch = -mcpu=arm1176jzf-s arch = -mcpu=cortex-a7 diff --git a/src/asm.h b/src/asm.h index 61d29ac..425a8ee 100644 --- a/src/asm.h +++ b/src/asm.h @@ -10,4 +10,6 @@ "bne 0b\n\t" \ :: "r"(x) : "cc") +#define halt_cpu() asm volatile("wfe"); + #endif /* ASM_H_ */ diff --git a/src/contty.c b/src/contty.c new file mode 100644 index 0000000..581d2c8 --- /dev/null +++ b/src/contty.c @@ -0,0 +1,17 @@ +#include "contty.h" +#include "serial.h" + +int con_init(void) +{ + return 0; +} + +void con_putchar(int c) +{ + ser_putchar(c); +} + +int con_getchar(void) +{ + return ser_getchar(); +} diff --git a/src/contty.h b/src/contty.h new file mode 100644 index 0000000..b71e836 --- /dev/null +++ b/src/contty.h @@ -0,0 +1,9 @@ +#ifndef CONTTY_H_ +#define CONTTY_H_ + +int con_init(void); + +void con_putchar(int c); +int con_getchar(void); + +#endif /* CONTTY_H_ */ diff --git a/src/libc/alloca.h b/src/libc/alloca.h new file mode 100644 index 0000000..2c86643 --- /dev/null +++ b/src/libc/alloca.h @@ -0,0 +1,6 @@ +#ifndef ALLOCA_H_ +#define ALLOCA_H_ + +#define alloca(x) __builtin_alloca(x) + +#endif /* ALLOCA_H_ */ diff --git a/src/libc/assert.h b/src/libc/assert.h new file mode 100644 index 0000000..4ac0d15 --- /dev/null +++ b/src/libc/assert.h @@ -0,0 +1,11 @@ +#ifndef ASSERT_H_ +#define ASSERT_H_ + +#include "panic.h" + +#define assert(x) \ + if(!(x)) { \ + panic("Kernel assertion failed at " __FILE__ ":%d: " #x "\n", __LINE__); \ + } + +#endif /* ASSERT_H_ */ diff --git a/src/libc/ctype.c b/src/libc/ctype.c index 9676441..f720566 100644 --- a/src/libc/ctype.c +++ b/src/libc/ctype.c @@ -52,5 +52,5 @@ int toupper(int c) int tolower(int c) { - return isupper(c) ? (c + ('A' - 'a')) : c; + return isupper(c) ? (c - ('A' - 'a')) : c; } diff --git a/src/libc/ctype.h b/src/libc/ctype.h index a36c694..5b010d4 100644 --- a/src/libc/ctype.h +++ b/src/libc/ctype.h @@ -1,5 +1,5 @@ -#ifndef CTYPES_H_ -#define CTYPES_H_ +#ifndef CTYPE_H_ +#define CTYPE_H_ int isalnum(int c); int isalpha(int c); @@ -14,5 +14,4 @@ int isspace(int c); int toupper(int c); int tolower(int c); - -#endif /* CTYPES_H_ */ +#endif /* CTYPE_H_ */ diff --git a/src/libc/errno.h b/src/libc/errno.h new file mode 100644 index 0000000..4bc9f6a --- /dev/null +++ b/src/libc/errno.h @@ -0,0 +1,24 @@ +#ifndef ERRNO_H_ +#define ERRNO_H_ + +#define EFOO 1 +#define EAGAIN 2 +#define EINVAL 3 +#define ECHILD 4 +#define EBUSY 5 +#define ENOMEM 6 +#define EIO 7 +#define ENOENT 8 +#define ENAMETOOLONG 9 +#define ENOSPC 10 +#define EPERM 11 +#define ENOTDIR 12 +#define EISDIR 13 +#define EEXIST 14 +#define ERANGE 34 + +#define EBUG 127 /* for missing features and known bugs */ + +int errno; + +#endif /* ERRNO_H_ */ diff --git a/src/libc/float.h b/src/libc/float.h new file mode 100644 index 0000000..974e00e --- /dev/null +++ b/src/libc/float.h @@ -0,0 +1,7 @@ +#ifndef FLOAT_H_ +#define FLOAT_H_ + +#define FLT_MIN __FLT_MIN__ +#define FLT_MAX __FLT_MAX__ + +#endif /* FLOAT_H_ */ diff --git a/src/libc/inttypes.h b/src/libc/inttypes.h new file mode 100644 index 0000000..1f10b06 --- /dev/null +++ b/src/libc/inttypes.h @@ -0,0 +1,14 @@ +#ifndef INTTYPES_H_ +#define INTTYPES_H_ + +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +#endif /* INTTYPES_H_ */ diff --git a/src/libc/limits.h b/src/libc/limits.h new file mode 100644 index 0000000..7a09d92 --- /dev/null +++ b/src/libc/limits.h @@ -0,0 +1,19 @@ +#ifndef LIMITS_H_ +#define LIMITS_H_ + +#define CHAR_BIT 8 + +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 +#define INT_MIN (-2147483648) +#define INT_MAX 2147483647 +#define LONG_MIN (-2147483648) +#define LONG_MAX 2147483647 + +#define USHRT_MAX 65535 +#define UINT_MAX 0xffffffff +#define ULONG_MAX 0xffffffff + +#define PATH_MAX 256 + +#endif /* LIMITS_H_ */ diff --git a/src/libc/math.c b/src/libc/math.c new file mode 100644 index 0000000..8da9a15 --- /dev/null +++ b/src/libc/math.c @@ -0,0 +1,38 @@ +#include "math.h" + +static double calc_pow(double x, double y, double precision); + +double pow(double x, double y) +{ + if(y == 0.0 || y == -0.0) { + return 1.0; + } + if(y == 1.0) { + return x; + } + if(y == -INFINITY) { + return fabs(x) < 1.0 ? INFINITY : 0.0; + } + if(y == INFINITY) { + return fabs(x) < 1.0 ? 0.0 : INFINITY; + } + return calc_pow(x, y, 1e-6); +} + +static double calc_pow(double x, double y, double precision) +{ + if(y < 0.0) { + return 1.0 / calc_pow(x, -y, precision); + } + if(y >= 10.0) { + double p = calc_pow(x, y / 2.0, precision / 2.0); + return p * p; + } + if(y >= 1.0) { + return x * calc_pow(x, y - 1.0, precision); + } + if(precision >= 1) { + return __builtin_sqrt(x); + } + return __builtin_sqrt(calc_pow(x, y * 2.0, precision * 2.0)); +} diff --git a/src/libc/math.h b/src/libc/math.h new file mode 100644 index 0000000..6e6b2e9 --- /dev/null +++ b/src/libc/math.h @@ -0,0 +1,19 @@ +#ifndef MATH_H_ +#define MATH_H_ + +#define INFINITY __builtin_inff() +#define NAN __builtin_nanf + +#define M_PI 3.141592653589793 + +#define sin(x) __builtin_sin(x) +#define cos(x) __builtin_cos(x) +#define tan(x) __builtin_tan(x) +#define fabs(x) __builtin_fabs(x) +#define fmod(x, y) __builtin_fmod(x, y) +#define sqrt(x) __builtin_sqrt(x) +#define atan2(y, x) __builtin_atan2(y, x) + +double pow(double x, double y); + +#endif /* MATH_H_ */ diff --git a/src/libc/rand.c b/src/libc/rand.c new file mode 100644 index 0000000..6ea2624 --- /dev/null +++ b/src/libc/rand.c @@ -0,0 +1,48 @@ +/* random number generator, based on this description of the algorithm + * used by the GNU libc: https://www.mathstat.dal.ca/~selinger/random + */ +#include +#include + +static int init_done; +static int32_t rng[34]; +static int32_t *ptr0, *ptr1; + +int rand(void) +{ + int res; + + if(!init_done) { + srand(1); + } + + *ptr1 += *ptr0; + res = (uint32_t)*ptr1 >> 1; + if(++ptr0 >= rng + 34) ptr0 = rng; + if(++ptr1 >= rng + 34) ptr1 = rng; + + return res; +} + +void srand(unsigned int seed) +{ + int i; + + init_done = 1; + if(seed == 0) seed = 1; + + rng[0] = seed; + for(i=1; i<31; i++) { + rng[i] = (16807 * rng[i - 1]) % RAND_MAX; + if(rng[i] < 0) rng[i] += RAND_MAX; + } + for(i=31; i<34; i++) { + rng[i] = rng[i - 31]; + } + ptr0 = rng + 3; + ptr1 = rng + 31; + + for(i=34; i<344; i++) { + rand(); + } +} diff --git a/src/libc/setjmp.c b/src/libc/setjmp.c new file mode 100644 index 0000000..5cadbde --- /dev/null +++ b/src/libc/setjmp.c @@ -0,0 +1,11 @@ +#include + +int setjmp(jmp_buf buf) +{ + return __builtin_setjmp(buf); +} + +void longjmp(jmp_buf buf, int val) +{ + __builtin_longjmp(buf, 1); +} diff --git a/src/libc/setjmp.h b/src/libc/setjmp.h new file mode 100644 index 0000000..6712313 --- /dev/null +++ b/src/libc/setjmp.h @@ -0,0 +1,9 @@ +#ifndef SETJMP_H_ +#define SETJMP_H_ + +typedef unsigned long jmp_buf[5]; + +int setjmp(jmp_buf buf); +void longjmp(jmp_buf buf, int val); + +#endif /* SETJMP_H_ */ diff --git a/src/libc/stdarg.h b/src/libc/stdarg.h new file mode 100644 index 0000000..696aab2 --- /dev/null +++ b/src/libc/stdarg.h @@ -0,0 +1,10 @@ +#ifndef STDARG_H_ +#define STDARG_H_ + +typedef __builtin_va_list va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) + +#endif /* STDARG_H_ */ diff --git a/src/libc/stddef.h b/src/libc/stddef.h new file mode 100644 index 0000000..b22543f --- /dev/null +++ b/src/libc/stddef.h @@ -0,0 +1,15 @@ +#ifndef STDDEF_H_ +#define STDDEF_H_ + +#include + +typedef int32_t ssize_t; +typedef uint32_t size_t; +typedef int wchar_t; + +typedef int32_t ptrdiff_t; +typedef uint32_t intptr_t; + +#define NULL 0 + +#endif /* STDDEF_H_ */ diff --git a/src/libc/stdint.h b/src/libc/stdint.h index 7050344..c9f87e4 100644 --- a/src/libc/stdint.h +++ b/src/libc/stdint.h @@ -1,12 +1,6 @@ #ifndef LIBC_STDINT_H_ #define LIBC_STDINT_H_ -typedef char int8_t; -typedef short int16_t; -typedef long int32_t; - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned long uint32_t; +#include "inttypes.h" #endif /* LIBC_STDINT_H_ */ diff --git a/src/libc/stdio.c b/src/libc/stdio.c new file mode 100644 index 0000000..4c72114 --- /dev/null +++ b/src/libc/stdio.c @@ -0,0 +1,393 @@ +#include +#include +#include +#include +#include "contty.h" +#include "serial.h" +#include "panic.h" + +enum { + OUT_DEF, + OUT_BUF, + OUT_SCR, + OUT_SER +}; + +static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list ap); +static int intern_scanf(const char *instr, FILE *infile, const char *fmt, va_list ap); +static void bwrite(int out, char *buf, size_t buf_sz, char *str, int sz); +/*static int readchar(const char *str, FILE *fp);*/ + +int putchar(int c) +{ + con_putchar(c); + return c; +} + +int puts(const char *s) +{ + while(*s) { + putchar(*s++); + } + putchar('\n'); + return 0; +} + +/* -- printf and friends -- */ + +int printf(const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(OUT_DEF, 0, 0, fmt, ap); + va_end(ap); + return res; +} + +int vprintf(const char *fmt, va_list ap) +{ + return intern_printf(OUT_DEF, 0, 0, fmt, ap); +} + +int sprintf(char *buf, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(OUT_BUF, buf, 0, fmt, ap); + va_end(ap); + return res; +} + +int vsprintf(char *buf, const char *fmt, va_list ap) +{ + return intern_printf(OUT_BUF, buf, 0, fmt, ap); +} + +int snprintf(char *buf, size_t sz, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(OUT_BUF, buf, sz, fmt, ap); + va_end(ap); + return res; +} + +int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap) +{ + return intern_printf(OUT_BUF, buf, sz, fmt, ap); +} + +int fprintf(FILE *fp, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = vfprintf(fp, fmt, ap); + va_end(ap); + return res; +} + +int vfprintf(FILE *fp, const char *fmt, va_list ap) +{ + if(fp == stdout || fp == stderr) { + return vprintf(fmt, ap); + } + + panic("*fprintf for anything other than stdout/stderr, not implemented yet\n"); + return 0; +} + +int ser_printf(const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(OUT_SER, 0, 0, fmt, ap); + va_end(ap); + return res; +} + +int ser_vprintf(const char *fmt, va_list ap) +{ + return intern_printf(OUT_SER, 0, 0, fmt, ap); +} + +void perror(const char *s) +{ + printf("%s: %s\n", s, strerror(errno)); +} + +int getchar(void) +{ + return con_getchar(); +} + +/* intern_printf provides all the functionality needed by all the printf + * variants. + * - buf: optional buffer onto which the formatted results are written. If null + * then the output goes to the terminal through putchar calls. This is used + * by the (v)sprintf variants which write to an array of char. + * - sz: optional maximum size of the output, 0 means unlimited. This is used + * by the (v)snprintf variants to avoid buffer overflows. + * The rest are obvious, format string and variable argument list. + */ +static char *convc = "dioxXucsfeEgGpn%"; + +#define IS_CONV(c) strchr(convc, c) + +#define BUF(x) ((x) ? (x) + cnum : (x)) +#define SZ(x) ((x) ? (x) - cnum : (x)) + +static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list ap) +{ + char conv_buf[32]; + char *str; + int i, slen; + const char *fstart = 0; + + /* state */ + int cnum = 0; + int base = 10; + int alt = 0; + int fwidth = 0; + int padc = ' '; + int sign = 0; + int left_align = 0; + int hex_caps = 0; + int unsig = 0; + int num, unum; + + while(*fmt) { + if(*fmt == '%') { + fstart = fmt++; + continue; + } + + if(fstart) { + if(IS_CONV(*fmt)) { + switch(*fmt) { + case 'X': + hex_caps = 1; + + case 'x': + case 'p': + base = 16; + + if(alt) { + bwrite(out, BUF(buf), SZ(sz), "0x", 2); + cnum += 2; + } + + case 'u': + unsig = 1; + + if(0) { + case 'o': + base = 8; + + if(alt) { + bwrite(out, BUF(buf), SZ(sz), "0", 1); + cnum++; + } + } + + case 'd': + case 'i': + if(unsig) { + unum = va_arg(ap, unsigned int); + utoa(unum, conv_buf, base); + } else { + num = va_arg(ap, int); + itoa(num, conv_buf, base); + } + if(hex_caps) { + for(i=0; conv_buf[i]; i++) { + conv_buf[i] = toupper(conv_buf[i]); + } + } + + slen = strlen(conv_buf); + + if(left_align) { + if(!unsig && sign && num >= 0) { + bwrite(out, BUF(buf), SZ(sz), "+", 1); + cnum++; + } + bwrite(out, BUF(buf), SZ(sz), conv_buf, slen); + cnum += slen; + padc = ' '; + } + for(i=slen; i= 0) { + bwrite(out, BUF(buf), SZ(sz), "+", 1); + cnum++; + } + bwrite(out, BUF(buf), SZ(sz), conv_buf, slen); + cnum += slen; + } + break; + + case 'c': + { + char c = va_arg(ap, int); + bwrite(out, BUF(buf), SZ(sz), &c, 1); + cnum++; + } + break; + + case 's': + str = va_arg(ap, char*); + slen = strlen(str); + + if(left_align) { + bwrite(out, BUF(buf), SZ(sz), str, slen); + cnum += slen; + padc = ' '; + } + for(i=slen; i +#include + +typedef struct FILE FILE; + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define EOF (-1) + +#define stdin ((FILE*)0) +#define stdout ((FILE*)1) +#define stderr ((FILE*)2) + +int putchar(int c); +int puts(const char *s); + +int printf(const char *fmt, ...); +int vprintf(const char *fmt, va_list ap); + +int sprintf(char *buf, const char *fmt, ...); +int vsprintf(char *buf, const char *fmt, va_list ap); + +int snprintf(char *buf, size_t sz, const char *fmt, ...); +int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap); + +/* TODO */ +int fprintf(FILE *fp, const char *fmt, ...); +int vfprintf(FILE *fp, const char *fmt, va_list ap); + +/* TODO +int fscanf(FILE *fp, const char *fmt, ...); +int vfscanf(FILE *fp, const char *fmt, va_list ap); + +int sscanf(const char *str, const char *fmt, ...); +int vsscanf(const char *ptr, const char *fmt, va_list ap); +*/ + +/* printf to the serial port */ +int ser_printf(const char *fmt, ...); +int ser_vprintf(const char *fmt, va_list ap); + +void perror(const char *s); + +int getchar(void); + +#endif /* STDIO_H_ */ diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c new file mode 100644 index 0000000..386cae7 --- /dev/null +++ b/src/libc/stdlib.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include + +int atoi(const char *str) +{ + return strtol(str, 0, 10); +} + +long atol(const char *str) +{ + return strtol(str, 0, 10); +} + +long strtol(const char *str, char **endp, int base) +{ + long acc = 0; + int sign = 1; + int valid = 0; + const char *start = str; + + while(isspace(*str)) str++; + + if(base == 0) { + if(str[0] == '0') { + if(str[1] == 'x' || str[1] == 'X') { + base = 16; + } else { + base = 8; + } + } else { + base = 10; + } + } + + if(*str == '+') { + str++; + } else if(*str == '-') { + sign = -1; + str++; + } + + while(*str) { + long val = LONG_MAX; + char c = tolower(*str); + + if(isdigit(c)) { + val = *str - '0'; + } else if(c >= 'a' && c <= 'f') { + val = 10 + c - 'a'; + } else { + break; + } + if(val >= base) { + break; + } + valid = 1; + + acc = acc * base + val; + str++; + } + + if(endp) { + *endp = (char*)(valid ? str : start); + } + + return sign > 0 ? acc : -acc; +} + +void itoa(int val, char *buf, int base) +{ + static char rbuf[16]; + char *ptr = rbuf; + int neg = 0; + + if(val < 0) { + neg = 1; + val = -val; + } + + if(val == 0) { + *ptr++ = '0'; + } + + while(val) { + int digit = val % base; + *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a'); + val /= base; + } + + if(neg) { + *ptr++ = '-'; + } + + ptr--; + + while(ptr >= rbuf) { + *buf++ = *ptr--; + } + *buf = 0; +} + +void utoa(unsigned int val, char *buf, int base) +{ + static char rbuf[16]; + char *ptr = rbuf; + + if(val == 0) { + *ptr++ = '0'; + } + + while(val) { + unsigned int digit = val % base; + *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a'); + val /= base; + } + + ptr--; + + while(ptr >= rbuf) { + *buf++ = *ptr--; + } + *buf = 0; +} + +double atof(const char *str) +{ + return strtod(str, 0); +} + + +double strtod(const char *str, char **endp) +{ + char *ep; + const char *start = str; + int valid = 0; + long ival = 0, dval = 0; + int ddig = 0; + double res; + + /* integer part */ + ival = strtol(str, &ep, 10); + if(ep == str && *str != '.') { + if(endp) *endp = (char*)str; + return 0.0; + } + if(ep != str) valid = 1; + str = *ep == '.' ? ep + 1 : ep; + if(!isdigit(*str)) { + goto done; + } + valid = 1; + + dval = strtol(str, &ep, 10); + assert(dval >= 0); + ddig = ep - str; + str = ep; + +done: + if(*endp) { + *endp = (char*)(valid ? str : start); + } + + res = (double)ival; + if(ddig) { + double d = (double)dval; + while(ddig-- > 0) { + d /= 10.0; + } + res += d; + } + return res; +} + +void abort(void) +{ + panic("Aborted\n"); +} + +#define QSORT_THRESHOLD 4 +#define ITEM(idx) ((char*)arr + (idx) * itemsz) + +#define SWAP(p, q) \ + do { \ + int nn = itemsz; \ + char *pp = (p); \ + char *qq = (q); \ + do { \ + char tmp = *pp; \ + *pp++ = *qq; \ + *qq++ = tmp; \ + } while(--nn > 0); \ + } while(0) + +static void ins_sort(void *arr, size_t count, size_t itemsz, int (*cmp)(const void*, const void*)) +{ + int i; + char *it, *a, *b; + + if(count <= 1) return; + + it = (char*)arr + itemsz; + for(i=1; i (char*)arr && cmp(a, (b = a - itemsz)) < 0) { + SWAP(a, b); + a -= itemsz; + } + } +} + +void qsort(void *arr, size_t count, size_t itemsz, int (*cmp)(const void*, const void*)) +{ + char *ma, *mb, *mc, *left, *right; + size_t sepidx, nleft, nright; + + if(count <= 1) return; + + if(count < QSORT_THRESHOLD) { + ins_sort(arr, count, itemsz, cmp); + return; + } + + ma = arr; + mb = ITEM(count / 2); + mc = ITEM(count - 1); + if(cmp(ma, mb) < 0) SWAP(ma, mb); + if(cmp(mc, ma) < 0) SWAP(mc, ma); + + left = ma + itemsz; + right = mc - itemsz; + for(;;) { + while(cmp(left, ma) < 0) left += itemsz; + while(cmp(ma, right) < 0) right -= itemsz; + if(left >= right) break; + SWAP(left, right); + } + SWAP(ma, right); + sepidx = (right - (char*)arr) / itemsz; + nleft = sepidx; + nright = count - nleft - 1; + + qsort(ma, nleft, itemsz, cmp); + qsort(right + itemsz, nright, itemsz, cmp); +} diff --git a/src/libc/stdlib.h b/src/libc/stdlib.h new file mode 100644 index 0000000..6368187 --- /dev/null +++ b/src/libc/stdlib.h @@ -0,0 +1,29 @@ +#ifndef STDLIB_H_ +#define STDLIB_H_ + +#include + +#define RAND_MAX 2147483647 + +#define abs(x) __builtin_abs(x) + +int atoi(const char *str); +long atol(const char *str); +long strtol(const char *str, char **endp, int base); + +void itoa(int val, char *buf, int base); +void utoa(unsigned int val, char *buf, int base); + +double atof(const char *str); +double strtod(const char *str, char **endp); + +void exit(int x) __attribute__((noreturn)); /* defined in startup.s */ +void abort(void); + +void qsort(void *arr, size_t count, size_t size, int (*cmp)(const void*, const void*)); + +int rand(void); +int rand_r(unsigned int *seedp); +void srand(unsigned int seed); + +#endif /* STDLIB_H_ */ diff --git a/src/libc/string.c b/src/libc/string.c index 9ffb5ec..36b964e 100644 --- a/src/libc/string.c +++ b/src/libc/string.c @@ -1,6 +1,8 @@ -#include "string.h" +#include +#include +#include -void *memset(void *ptr, int val, int size) +void *memset(void *ptr, int val, size_t size) { unsigned char *p = ptr; while(size--) { @@ -9,26 +11,249 @@ void *memset(void *ptr, int val, int size) return ptr; } -void *memcpy(void *dest, void *src, int size) +void *memcpy(void *dest, const void *src, size_t n) { unsigned char *d = dest; - unsigned char *s = src; - while(size--) { + const unsigned char *s = src; + while(n--) { *d++ = *s++; } return dest; } -int strcmp(const char *a, const char *b) +void *memmove(void *dest, const void *src, size_t n) { - while(*a && *a == *b) { - a++; - b++; + int i; + char *dptr; + const char *sptr; + + if(dest <= src) { + /* forward copy */ + dptr = dest; + sptr = src; + for(i=0; i= 4) { + if(*a32 != *b32) break; + a32++; + b32++; + n -= 4; + } + + /* update byte pointers to contine with the tail */ + a = (unsigned char*)a32; + b = (unsigned char*)b32; + } + + /* we're here both for the tail-end of same-alignment buffers, or for the + * whole length of mis-aligned buffers. + */ + while(n-- > 0) { + if((diff = *a++ - *b++) != 0) { + return diff; + } + } + return 0; +} + +size_t strlen(const char *s) +{ + size_t len = 0; + while(*s++) len++; + return len; +} + +char *strchr(const char *s, int c) +{ + while(*s) { + if(*s == c) { + return (char*)s; + } + s++; + } + return 0; +} + +char *strrchr(const char *s, int c) +{ + const char *ptr = s; + + /* find the end */ + while(*ptr) ptr++; + + /* go back checking for c */ + while(--ptr >= s) { + if(*ptr == c) { + return (char*)ptr; + } + } + return 0; +} + +char *strstr(const char *str, const char *substr) +{ + while(*str) { + const char *s1 = str; + const char *s2 = substr; + + while(*s1 && *s1 == *s2) { + s1++; + s2++; + } + if(!*s2) { + return (char*)str; + } + str++; + } + return 0; +} + +char *strcasestr(const char *str, const char *substr) +{ + while(*str) { + const char *s1 = str; + const char *s2 = substr; + + while(*s1 && tolower(*s1) == tolower(*s2)) { + s1++; + s2++; + } + if(!*s2) { + return (char*)str; + } + str++; + } + return 0; +} - if(!*a) return -1; - if(!*b) return 1; - return *a - *b > 0 ? 1 : -1; +int strcmp(const char *s1, const char *s2) +{ + while(*s1 && *s1 == *s2) { + s1++; + s2++; + } + return *s1 - *s2; +} + +int strcasecmp(const char *s1, const char *s2) +{ + while(*s1 && tolower(*s1) == tolower(*s2)) { + s1++; + s2++; + } + return tolower(*s1) - tolower(*s2); +} + +int strncmp(const char *s1, const char *s2, int n) +{ + if(n <= 0) return 0; + + while(n-- > 0 && *s1 && *s2 && *s1 == *s2) { + s1++; + s2++; + } + + if(n <= 0) return 0; + return *s1 - *s2; +} + +int strncasecmp(const char *s1, const char *s2, int n) +{ + if(n <= 0) return 0; + + while(n-- > 0 && *s1 && *s2 && tolower(*s1) == tolower(*s2)) { + s1++; + s2++; + } + + if(n <= 0) return 0; + return tolower(*s1) - tolower(*s2); +} + +char *strcpy(char *dest, const char *src) +{ + char *dptr = dest; + while((*dptr++ = *src++)); + return dest; +} + +char *strcat(char *dest, const char *src) +{ + strcpy(dest + strlen(dest), src); + return dest; +} + +char *strncpy(char *dest, const char *src, int n) +{ + char *dptr = dest; + while(n-- > 0 && (*dptr++ = *src++)); + return dest; +} + + +static const char *errstr[] = { + "Success", + "Foo", + "Interrupted", + "Invalid", + "Child", + "Timeout", + "Out of memory", + "I/O error", + "Not found", + "Name too long", + "No space left on device", + "Permission denied", + "Not a directory", + "Is a directory", + "Does not exist", + 0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0, + "Bug" +}; + +char *strerror(int err) +{ + if(err < 0 || err > sizeof errstr / sizeof *errstr || !errstr[err]) { + return "Unknown"; + } + return (char*)errstr[err]; } diff --git a/src/libc/string.h b/src/libc/string.h index 4a1812f..09f7020 100644 --- a/src/libc/string.h +++ b/src/libc/string.h @@ -1,9 +1,34 @@ -#ifndef LIBC_STRING_H_ -#define LIBC_STRING_H_ +#ifndef STRING_H_ +#define STRING_H_ -void *memset(void *ptr, int val, int size); -void *memcpy(void *dest, void *src, int size); +#include -int strcmp(const char *a, const char *b); +void *memset(void *s, int c, size_t n); -#endif /* LIBC_STRING_H_ */ +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); + +int memcmp(void *aptr, void *bptr, size_t n); + +size_t strlen(const char *s); + +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); + +char *strstr(const char *str, const char *substr); +char *strcasestr(const char *str, const char *substr); + +int strcmp(const char *s1, const char *s2); +int strcasecmp(const char *s1, const char *s2); + +int strncmp(const char *s1, const char *s2, int n); +int strncasecmp(const char *s1, const char *s2, int n); + +char *strcpy(char *dest, const char *src); +char *strcat(char *dest, const char *src); + +char *strncpy(char *dest, const char *src, int n); + +char *strerror(int err); + +#endif /* STRING_H_ */ diff --git a/src/main.c b/src/main.c index 0c8bdf5..db2ab86 100644 --- a/src/main.c +++ b/src/main.c @@ -1,14 +1,16 @@ #include "config.h" +#include #include #include #include #include "asm.h" +#include "rpi.h" +#include "contty.h" #include "serial.h" #include "video.h" void dbgled(int x); -void exit(int x); static void cmdrun(char *cmd); @@ -18,14 +20,17 @@ int main(void) static char cmdbuf[256]; static int cmdend; + rpi_init(); init_serial(115200); - ser_printstr("Starting rpikern\n"); + con_init(); + + printf("Detected raspberry pi %d, I/O base: %x\n", rpi_model, rpi_iobase); video_init(); - ser_printstr("Going interactive\n"); + printf("Going interactive\n"); for(;;) { - int c = ser_getchar(); + int c = getchar(); switch(c) { case '\r': @@ -41,7 +46,7 @@ int main(void) case -1: lastnl = 0; - ser_printstr("error!\n"); + printf("error!\n"); break; default: @@ -56,12 +61,6 @@ int main(void) return 0; } -void panic(void) -{ - ser_printstr("PANIC!\n"); - exit(0); -} - static void cmdrun(char *cmd) { char *ptr, *args; @@ -73,12 +72,10 @@ static void cmdrun(char *cmd) args = ptr + 1; if(strcmp(cmd, "help") == 0) { - ser_printstr("help not implemented yet\n"); + printf("help not implemented yet\n"); } else if(strcmp(cmd, "ver") == 0) { - ser_printstr("rpikern version 0.0\n"); + printf("rpikern version 0.0\n"); } else { - ser_printstr("Unknown command: "); - ser_printstr(cmd); - ser_printstr("\n"); + printf("Unknown command: %s\n", cmd); } } diff --git a/src/panic.c b/src/panic.c new file mode 100644 index 0000000..34cda75 --- /dev/null +++ b/src/panic.c @@ -0,0 +1,12 @@ +#include +#include "asm.h" + +void panic(const char *fmt, ...) +{ + disable_intr(); + + printf("~~~~~ rpikern panic ~~~~~\n"); + printf("TODO: reg dump\n"); + + for(;;) halt_cpu(); +} diff --git a/src/panic.h b/src/panic.h new file mode 100644 index 0000000..1b29a63 --- /dev/null +++ b/src/panic.h @@ -0,0 +1,6 @@ +#ifndef PANIC_H_ +#define PANIC_H_ + +void panic(const char *fmt, ...) __attribute__((noreturn)); + +#endif /* PANIC_H_ */ diff --git a/src/rpi.c b/src/rpi.c new file mode 100644 index 0000000..ba39596 --- /dev/null +++ b/src/rpi.c @@ -0,0 +1,111 @@ +#include "rpi.h" +#include "asm.h" + +#define IOREG(offs) (*(volatile uint32_t*)(rpi_iobase | offs)) + +/* System timer */ +#define STM_CTL_REG IOREG(0x3000) +#define STM_STAT_REG STM_CTL_REG +#define STM_LCNT_REG IOREG(0x3004) +#define STM_HCNT_REG IOREG(0x3008) +#define STM_CMP0_REG IOREG(0x300c) +#define STM_CMP1_REG IOREG(0x3010) +#define STM_CMP2_REG IOREG(0x3014) +#define STM_CMP3_REG IOREG(0x3018) + +#define STMCTL_M0 1 +#define STMCTL_M1 2 +#define STMCTL_M2 4 +#define STMCTL_M3 8 + +/* TIMER */ +#define TM_LOAD_REG IOREG(0xb400) +#define TM_VALUE_REG IOREG(0xb404) +#define TM_CTL_REG IOREG(0xb408) +#define TM_ICLR_REG IOREG(0xb40c) +#define TM_IRAW_REG IOREG(0xb410) +#define TM_IMSK_REG IOREG(0xb414) +#define TM_RELOAD_REG IOREG(0xb418) +#define TM_PREDIV_REG IOREG(0xb41c) +#define TM_COUNT_REG IOREG(0xb420) + +#define TMCTL_23BIT 0x000002 +#define TMCTL_DIV16 0x000004 +#define TMCTL_DIV256 0x000008 +#define TMCTL_DIV1 0x00000c +#define TMCTL_IEN 0x000020 +#define TMCTL_EN 0x000080 +#define TMCTL_DBGHALT 0x000100 +#define TMCTL_CNTEN 0x000200 + +#define TMCTL_PRESCALER(x) (((uint32_t)(x) & 0xff) << 16) + + +/* MAILBOX */ +#define MBOX_READ_REG IOREG(0xb880) +#define MBOX_POLL_REG IOREG(0xb890) +#define MBOX_SENDER_REG IOREG(0xb894) +#define MBOX_STATUS_REG IOREG(0xb898) +#define MBOX_CFG_REG IOREG(0xb89c) +#define MBOX_WRITE_REG IOREG(0xb8a0) + +/* the full bit is set when there's no space to append messages */ +#define MBOX_STAT_FULL 0x80000000 +/* the empty bit is set when there are no pending messages to be read */ +#define MBOX_STAT_EMPTY 0x40000000 + +static int detect(void); + +int rpi_model; +uint32_t rpi_iobase; +uint32_t rpi_memsize, rpi_vc_memsize; + +void rpi_init(void) +{ + if((rpi_model = detect()) == -1) { + for(;;) halt_cpu(); + } + + /* TODO */ +} + +static int detect(void) +{ + int i, j; + uint32_t tm0, tm1; + static uint32_t base[] = {0x20000000, 0x3f000000, 0xfe000000}; + + for(i=0; i<3; i++) { + rpi_iobase = base[i]; + tm0 = STM_LCNT_REG; + for(j=0; j<256; j++) { + tm1 = STM_LCNT_REG; + } + if(tm0 != tm1) { + return i + 1; + } + } + return -1; +} + + +void rpi_mbox_send(int chan, uint32_t msg) +{ + while(MBOX_STATUS_REG & MBOX_STAT_FULL); + MBOX_WRITE_REG = (msg & 0xfffffff0) | chan; +} + +uint32_t rpi_mbox_recv(int chan) +{ + uint32_t msg; + do { + while(MBOX_STATUS_REG & MBOX_STAT_EMPTY); + msg = MBOX_READ_REG; + } while((msg & 0xf) != chan); + return msg & 0xfffffff0; +} + +int rpi_mbox_pending(int chan) +{ + return (MBOX_STATUS_REG & MBOX_STAT_EMPTY) == 0; +} diff --git a/src/rpi.h b/src/rpi.h new file mode 100644 index 0000000..36f8ac4 --- /dev/null +++ b/src/rpi.h @@ -0,0 +1,50 @@ +#ifndef RPI_H_ +#define RPI_H_ + +#include + +#define RPI_MBOX_FRAMEBUF 1 +#define RPI_MBOX_PROP 8 + +#define RPI_TAG_GETMODEL 0x010001 +#define RPI_TAG_GETRAM 0x010005 +#define RPI_TAG_GETVRAM 0x010006 +#define RPI_TAG_SETCLOCK 0x038002 + +#define RPI_TAG_ALLOCFB 0x040001 +#define RPI_TAG_RELEASEFB 0x048001 +#define RPI_TAG_SETFBPHYS 0x048003 +#define RPI_TAG_SETFBVIRT 0x048004 +#define RPI_TAG_SETFBDEPTH 0x048005 + +struct rpi_tag_getmodel { + uint32_t id, size, res; + uint32_t model; +}; + +struct rpi_tag_getram { + uint32_t id, size, res; + uint32_t membase, memsize; +}; + +struct rpi_tag_setclock { + uint32_t id, size, res; + uint32_t clock_id, rate, skip_turbo; +}; + +struct rpi_prop_header { + uint32_t size; + uint32_t res; +}; + +extern int rpi_model; +extern uint32_t rpi_iobase; +extern uint32_t rpi_memsize, rpi_vc_memsize; + +void rpi_init(void); + +void rpi_mbox_send(int chan, uint32_t msg); +uint32_t rpi_mbox_recv(int chan); +int rpi_mbox_pending(int chan); + +#endif /* RPI_H_ */ diff --git a/src/serial.c b/src/serial.c index 9d1b2be..1bc13fe 100644 --- a/src/serial.c +++ b/src/serial.c @@ -36,6 +36,8 @@ void init_serial(int baud) void ser_putchar(int c) { + if(c == '\n') ser_putchar('\r'); + while(REG_FR & FR_TXFF); REG_DR = c & 0xff; } @@ -49,9 +51,6 @@ int ser_getchar(void) void ser_printstr(const char *s) { while(*s) { - if(*s == '\n') { - ser_putchar('\r'); - } ser_putchar(*s++); } } diff --git a/src/timer.h b/src/timer.h deleted file mode 100644 index 065fdcf..0000000 --- a/src/timer.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TIMER_H_ -#define TIMER_H_ - -#include "config.h" - -#define TM_BASE (IO_BASE | 0xb000) - -#define TM_REG(x) (*(volatile uint32_t*)(TIMER_BASE | (x))) -#define TM_LOAD TM_REG(0x400) -#define TM_VALUE TM_REG(0x404) -#define TM_CTL TM_REG(0x408) -#define TM_ICLR TM_REG(0x40c) -#define TM_IRAW TM_REG(0x410) -#define TM_IMSK TM_REG(0x414) -#define TM_RELOAD TM_REG(0x418) -#define TM_PREDIV TM_REG(0x41c) -#define TM_COUNT TM_REG(0x420) - -#define TMCTL_23BIT 0x000002 -#define TMCTL_DIV16 0x000004 -#define TMCTL_DIV256 0x000008 -#define TMCTL_DIV1 0x00000c -#define TMCTL_IEN 0x000020 -#define TMCTL_EN 0x000080 -#define TMCTL_DBGHALT 0x000100 -#define TMCTL_CNTEN 0x000200 - -#define TMCTL_PRESCALER(x) (((uint32_t)(x) & 0xff) << 16) - -#endif /* TIMER_H_ */ diff --git a/src/video.c b/src/video.c index 33b740f..9b552dc 100644 --- a/src/video.c +++ b/src/video.c @@ -1,68 +1,18 @@ #include "config.h" +#include #include #include +#include "rpi.h" #include "video.h" -#include "serial.h" #include "mem.h" -#define MBOX_READ_REG (*(volatile uint32_t*)(IO_BASE | 0xb880)) -#define MBOX_POLL_REG (*(volatile uint32_t*)(IO_BASE | 0xb890)) -#define MBOX_SENDER_REG (*(volatile uint32_t*)(IO_BASE | 0xb894)) -#define MBOX_STATUS_REG (*(volatile uint32_t*)(IO_BASE | 0xb898)) -#define MBOX_CFG_REG (*(volatile uint32_t*)(IO_BASE | 0xb89c)) -#define MBOX_WRITE_REG (*(volatile uint32_t*)(IO_BASE | 0xb8a0)) - -#define MBOX_STAT_WRBUSY 0x80000000 -#define MBOX_STAT_RDBUSY 0x40000000 - -struct vc_fbinfo { - uint32_t phys_width, phys_height; - uint32_t virt_width, virt_height; - uint32_t pitch; /* filled by videocore */ - uint32_t depth; - uint32_t x, y; - void *addr; /* filled by videocore */ - uint32_t size; /* filled by videocore */ -}; - -void mbox_write(int mbox, uint32_t msg); -uint32_t mbox_read(int mbox); - -static struct vc_fbinfo fbinf __attribute__((aligned(16))); +/* needs to by 16-byte aligned, because the address we send over the mailbox + * interface, will have its 4 least significant bits masked off and taken over + * by the mailbox id + */ +static uint8_t propbuf[64] __attribute__((aligned(16))); int video_init(void) { - memset(&fbinf, 0, sizeof fbinf); - fbinf.phys_width = fbinf.virt_width = 1024; - fbinf.phys_height = fbinf.virt_height = 600; - fbinf.depth = 32; - fbinf.x = fbinf.y = 0; - - mbox_write(1, MEM_BUS_COHERENT(&fbinf)); - if(mbox_read(1) != 0) { - ser_printstr("Failed to initialize display\n"); - return -1; - } - - ser_printstr("Video init successful\n"); - memset(fbinf.addr, 0, fbinf.size); return 0; } - -void mbox_write(int mbox, uint32_t msg) -{ - while(MBOX_STATUS_REG & MBOX_STAT_WRBUSY); - MBOX_WRITE_REG = (msg & 0xfffffff0) | mbox; -} - -uint32_t mbox_read(int mbox) -{ - uint32_t msg; - - do { - while(MBOX_STATUS_REG & MBOX_STAT_RDBUSY); - msg = MBOX_READ_REG; - } while((msg & 0xf) != mbox); - - return msg & 0xfffffff0; -}