From: John Tsiombikas Date: Tue, 8 Jun 2021 14:27:53 +0000 (+0300) Subject: vga text output and libc expansion X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=3sys;a=commitdiff_plain;h=d49aa763f9b7c4ae66cf80f0cbfc3456789fc0ac vga text output and libc expansion --- diff --git a/sys1/kern/src/asmutil.h b/sys1/kern/src/asmutil.h new file mode 100644 index 0000000..fb852a1 --- /dev/null +++ b/sys1/kern/src/asmutil.h @@ -0,0 +1,44 @@ +#ifndef ASMUTIL_H_ +#define ASMUTIL_H_ + +#include + +/* inline assembly utility macros */ + +#define enable_intr() asm volatile("sti") +#define disable_intr() asm volatile("cli") + +#define set_intr_state(en) \ + do { if(en) enable_intr(); else disable_intr(); } while(0) + +static inline int get_intr_state(void) +{ + int res; + asm volatile ( + "\r\tpushf" + "\r\tpop %0" + : "=r"(res)); + return (res >> 9) & 1; /* IF is bit 9 of eflags */ +} + +#define outp(port, val) \ + asm volatile("out %%al, %%dx" :: "d"(port), "a"((unsigned char)val)) +#define outp16(port, val) \ + asm volatile("out %%ax, %%dx" :: "d"(port), "a"((unsigned short)val)) + +static inline uint8_t inp(int port) +{ + uint8_t res; + asm volatile("in %%dx, %%al" : "=a"(res) : "d"(port)); + return res; +} + +static inline uint16_t inp16(int port) +{ + uint16_t res; + asm volatile("in %%dx, %%ax" : "=a"(res) : "d"(port)); + return res; +} + + +#endif /* ASMUTIL_H_ */ diff --git a/sys1/kern/src/libc/ctype.c b/sys1/kern/src/libc/ctype.c new file mode 100644 index 0000000..f720566 --- /dev/null +++ b/sys1/kern/src/libc/ctype.c @@ -0,0 +1,56 @@ +#include "ctype.h" + +int isalnum(int c) +{ + return isalpha(c) || isdigit(c); +} + +int isalpha(int c) +{ + return isupper(c) || islower(c); +} + +int isblank(int c) +{ + return c == ' ' || c == '\t'; +} + +int isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +int isupper(int c) +{ + return c >= 'A' && c <= 'Z'; +} + +int islower(int c) +{ + return c >= 'a' && c <= 'z'; +} + +int isgraph(int c) +{ + return c > ' ' && c <= '~'; +} + +int isprint(int c) +{ + return isgraph(c) || c == ' '; +} + +int isspace(int c) +{ + return isblank(c) || c == '\f' || c == '\n' || c == '\r' || c == '\v'; +} + +int toupper(int c) +{ + return islower(c) ? (c + ('A' - 'a')) : c; +} + +int tolower(int c) +{ + return isupper(c) ? (c - ('A' - 'a')) : c; +} diff --git a/sys1/kern/src/libc/ctype.h b/sys1/kern/src/libc/ctype.h new file mode 100644 index 0000000..5b010d4 --- /dev/null +++ b/sys1/kern/src/libc/ctype.h @@ -0,0 +1,17 @@ +#ifndef CTYPE_H_ +#define CTYPE_H_ + +int isalnum(int c); +int isalpha(int c); +#define isascii(c) ((c) < 128) +int isblank(int c); +int isdigit(int c); +int isupper(int c); +int islower(int c); +int isprint(int c); +int isspace(int c); + +int toupper(int c); +int tolower(int c); + +#endif /* CTYPE_H_ */ diff --git a/sys1/kern/src/libc/limits.h b/sys1/kern/src/libc/limits.h new file mode 100644 index 0000000..33dfd5c --- /dev/null +++ b/sys1/kern/src/libc/limits.h @@ -0,0 +1,19 @@ +#ifndef KLIBC_LIMITS_H_ +#define KLIBC_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 /* KLIBC_LIMITS_H_ */ diff --git a/sys1/kern/src/libc/stdarg.h b/sys1/kern/src/libc/stdarg.h new file mode 100644 index 0000000..f870438 --- /dev/null +++ b/sys1/kern/src/libc/stdarg.h @@ -0,0 +1,12 @@ +#ifndef STDARG_H_ +#define STDARG_H_ + +/* Assumes that arguments are passed on the stack 4-byte aligned */ + +typedef int* va_list; + +#define va_start(ap, last) ((ap) = (int*)&(last) + 1) +#define va_arg(ap, type) (*(type*)(ap)++) +#define va_end(ap) + +#endif /* STDARG_H_ */ diff --git a/sys1/kern/src/libc/stddef.h b/sys1/kern/src/libc/stddef.h new file mode 100644 index 0000000..629ed8b --- /dev/null +++ b/sys1/kern/src/libc/stddef.h @@ -0,0 +1,11 @@ +#ifndef KLIBC_STDDEF_H_ +#define KLIBC_STDDEF_H_ + +#include + +typedef int32_t ssize_t; +typedef uint32_t size_t; + +typedef uint32_t intptr_t; + +#endif /* KLIBC_STDDEF_H_ */ diff --git a/sys1/kern/src/libc/stdio.c b/sys1/kern/src/libc/stdio.c new file mode 100644 index 0000000..2035cf8 --- /dev/null +++ b/sys1/kern/src/libc/stdio.c @@ -0,0 +1,320 @@ +#include +#include +#include + +enum { + OUT_DEF, + OUT_BUF +}; + +static int intern_printf(int out, char *buf, size_t sz, 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); +} + +/* 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 + +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 sscanf(const char *str, const char *fmt, ...); +int vsscanf(const char *ptr, const char *fmt, va_list ap); +*/ + +#endif /* STDIO_H_ */ diff --git a/sys1/kern/src/libc/stdlib.c b/sys1/kern/src/libc/stdlib.c new file mode 100644 index 0000000..859372f --- /dev/null +++ b/sys1/kern/src/libc/stdlib.c @@ -0,0 +1,193 @@ +#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; +} + +#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/sys1/kern/src/libc/stdlib.h b/sys1/kern/src/libc/stdlib.h index dfd634f..4c173c6 100644 --- a/sys1/kern/src/libc/stdlib.h +++ b/sys1/kern/src/libc/stdlib.h @@ -1,7 +1,23 @@ #ifndef KLIBC_STDLIB_H_ #define KLIBC_STDLIB_H_ -typedef int ssize_t; -typedef unsigned int size_t; +#include + +#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); + +void qsort(void *arr, size_t count, size_t size, int (*cmp)(const void*, const void*)); + +/* defined in malloc.c */ +void *malloc(size_t sz); +void *calloc(size_t num, size_t sz); +void *realloc(void *ptr, size_t sz); +void free(void *ptr); #endif /* KLIBC_STDLIB_H_ */ diff --git a/sys1/kern/src/libc/string.c b/sys1/kern/src/libc/string.c index 3b11896..913ffc1 100644 --- a/sys1/kern/src/libc/string.c +++ b/sys1/kern/src/libc/string.c @@ -1,5 +1,6 @@ #include "string.h" #include "stdint.h" +#include "ctype.h" void *memset(void *dest, int val, size_t num) { @@ -28,3 +29,205 @@ void *memcpy(void *dest, void *src, size_t num) return dest; } + +void *memmove(void *dest, const void *src, size_t n) +{ + 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; +} + +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; +} diff --git a/sys1/kern/src/libc/string.h b/sys1/kern/src/libc/string.h index 8024665..be784be 100644 --- a/sys1/kern/src/libc/string.h +++ b/sys1/kern/src/libc/string.h @@ -5,6 +5,29 @@ void *memset(void *dest, int val, size_t num); void *memset16(void *dest, int val, size_t num); + void *memcpy(void *dest, void *src, size_t num); +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); #endif /* KLIBC_STRING_H_ */ diff --git a/sys1/kern/src/main.c b/sys1/kern/src/main.c index b89a98b..f0441e5 100644 --- a/sys1/kern/src/main.c +++ b/sys1/kern/src/main.c @@ -1,22 +1,22 @@ +#include #include #include - -void clearscr(void) -{ - memset((void*)0xb8000, 0, 80 * 25 * 2); -} +#include "vga.h" void drawtext(int x, int y, const char *s) { - uint16_t *vptr = (uint16_t*)0xb8000 + y * 80 + x; - while(*s) { - *vptr++ = 0x0c00 | *s++; + vga_drawchar(x++, y, *s++); } } void kmain(void) { - clearscr(); - drawtext(10, 5, "3sys kernel 1"); + char buf[64]; + + vga_reset(); + vga_setcolor(VGA_YELLOW | VGA_BRIGHT, VGA_BLACK); + + sprintf(buf, "kmain addr: %p", (void*)kmain); + drawtext(10, 5, buf); } diff --git a/sys1/kern/src/start.asm b/sys1/kern/src/start.asm index f9baf52..38219e6 100644 --- a/sys1/kern/src/start.asm +++ b/sys1/kern/src/start.asm @@ -1,5 +1,5 @@ bits 32 - section .text + section .startup extern _bss_start extern _bss_size diff --git a/sys1/kern/src/vga.c b/sys1/kern/src/vga.c new file mode 100644 index 0000000..2967299 --- /dev/null +++ b/sys1/kern/src/vga.c @@ -0,0 +1,56 @@ +#include +#include "vga.h" +#include "asmutil.h" + +#define CRTC_ADDR_PORT 0x3d4 +#define CRTC_DATA_PORT 0x3d5 + +/* CRTC registers */ +#define CRTC_START_H 0x0c +#define CRTC_START_L 0x0d +#define CRTC_CURPOS_H 0x0e +#define CRTC_CURPOS_L 0x0f + +static void crtc_write(int reg, unsigned char val); + +static uint16_t attr = 0x0700; +static int yoffs; + +void vga_setcolor(int fg, int bg) +{ + attr = ((bg & 7) << 12) | ((fg & 0xf) << 8); +} + +void vga_setcursor(int x, int y) +{ + int loc = (y + yoffs) * 80 + x; + crtc_write(CRTC_CURPOS_H, loc >> 8); + crtc_write(CRTC_CURPOS_L, loc); +} + +void vga_setstart(int start) +{ + yoffs = start; + crtc_write(CRTC_START_H, start >> 8); + crtc_write(CRTC_START_L, start); +} + +void vga_reset(void) +{ + vga_setcolor(VGA_WHITE, VGA_BLACK); + vga_setstart(0); + vga_setcursor(0, 0); + memset((void*)0xb8000, 0, 80 * 25 * 2); +} + +void vga_drawchar(int x, int y, int c) +{ + uint16_t *ptr = (uint16_t*)0xb8000 + (y + yoffs) * 80 + x; + *ptr = (c & 0xff) | attr; +} + +static void crtc_write(int reg, unsigned char val) +{ + outp(CRTC_ADDR_PORT, reg); + outp(CRTC_DATA_PORT, val); +} diff --git a/sys1/kern/src/vga.h b/sys1/kern/src/vga.h index 19571f3..e8be27a 100644 --- a/sys1/kern/src/vga.h +++ b/sys1/kern/src/vga.h @@ -11,9 +11,14 @@ enum { VGA_YELLOW, VGA_WHITE }; -#define VGA_BRIGHT 0x80 +#define VGA_BRIGHT 8 void vga_setcolor(int fg, int bg); void vga_setcursor(int x, int y); +void vga_setstart(int start); + +void vga_reset(void); + +void vga_drawchar(int x, int y, int c); #endif /* VGA_H_ */