From: John Tsiombikas Date: Wed, 25 Apr 2018 14:07:21 +0000 (+0300) Subject: main kernel startup, libc, console tty, asmops, build flags fixes X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=bootcensus;a=commitdiff_plain;h=d1e8a437c1fab4535f82c4c214ec3330ac32e48d main kernel startup, libc, console tty, asmops, build flags fixes --- diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..06d68b4 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,2 @@ +target remote localhost:1234 +symbol-file test.sym diff --git a/.gitignore b/.gitignore index 50d3557..87a02c0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,10 @@ *.bin test *.map +*.sym +*.disasm +*.img +*.log +*.tga +*.png + diff --git a/Makefile b/Makefile index 0722ce4..1a2f734 100644 --- a/Makefile +++ b/Makefile @@ -6,12 +6,14 @@ elf = test bin = test.bin warn = -pedantic -Wall +#opt = -O2 dbg = -g inc = -Isrc -Isrc/libc +gccopt = -fno-pic -ffreestanding -nostdinc -fno-builtin -CFLAGS = $(ccarch) -march=i386 $(warn) $(dbg) -nostdinc -fno-builtin $(inc) $(def) +CFLAGS = $(ccarch) -march=i386 $(warn) $(opt) $(dbg) $(gccopt) $(inc) $(def) ASFLAGS = $(asarch) -march=i386 $(dbg) -nostdinc -fno-builtin $(inc) -LDFLAGS = $(ldarch) -T pcboot.ld -print-gc-sections +LDFLAGS = $(ldarch) -nostdlib -T pcboot.ld -print-gc-sections ifneq ($(shell uname -m), i386) @@ -60,6 +62,16 @@ bootldr.disasm: $(elf) $(elf).disasm: $(elf) objdump -d $< -j .startup -j .text -m i386 >$@ +$(elf).sym: $(elf) + objcopy --only-keep-debug $< $@ + .PHONY: run run: $(bin) qemu-system-i386 -fda floppy.img -serial file:serial.log + +.PHONY: debug +debug: $(bin) $(elf).sym + qemu-system-i386 -fda floppy.img -serial file:serial.log -s -S + +.PHONY: sym +sym: $(elf).sym diff --git a/src/asmops.h b/src/asmops.h new file mode 100644 index 0000000..2578467 --- /dev/null +++ b/src/asmops.h @@ -0,0 +1,58 @@ +#ifndef ASMOPS_H_ +#define ASMOPS_H_ + +#include + +#define enable_intr() asm volatile("sti") +#define disable_intr() asm volatile("cli") +#define halt_cpu() asm volatile("hlt") + +static inline uint8_t inb(uint16_t port) +{ + uint8_t res; + asm volatile ( + "inb %1, %0\n\t" + : "=a" (res) + : "dN" (port)); + return res; +} + +static inline uint16_t inw(uint16_t port) +{ + uint16_t res; + asm volatile ( + "inw %1, %0\n\t" + : "=a" (res) + : "dN" (port)); + return res; +} + +static inline uint32_t inl(uint16_t port) +{ + uint32_t res; + asm volatile ( + "inl %1, %0\n\t" + : "=a" (res) + : "dN" (port)); + return res; +} + +#define outb(src, port) \ + asm volatile( \ + "outb %0, %1\n\t" \ + :: "a" ((uint8_t)(src)), "dN" ((uint16_t)(port))) + +#define outw(src, port) \ + asm volatile( \ + "outw %0, %1\n\t" \ + :: "a" ((uint16_t)(src)), "dN" ((uint16_t)(port))) + +#define outl(src, port) \ + asm volatile( \ + "outl %0, %1\n\t" \ + :: "a" ((uint32_t)(src)), "dN" ((uint16_t)(port))) + +#define iodelay() outb(0, 0x80) + + +#endif /* ASMOPS_H_ */ diff --git a/src/boot/boot2.s b/src/boot/boot2.s index 5422c0b..59918b8 100644 --- a/src/boot/boot2.s +++ b/src/boot/boot2.s @@ -37,8 +37,8 @@ # load the whole program into memory starting at 1MB call load_main - mov $0x13, %ax - int $0x10 + #mov $0x13, %ax + #int $0x10 # load initial GDT lgdt (gdt_lim) @@ -349,14 +349,15 @@ abort_read: jmp 0b - # better print routines, since we're not constrainted by the 512b of # the boot sector. + .global cursor_x + .global cursor_y cursor_x: .long 0 cursor_y: .long 0 putchar: - pusha + pushal call ser_putchar cmp $10, %al @@ -382,7 +383,7 @@ putchar: jnz 1f call video_newline -1: popa +1: popal ret # expects string pointer in esi @@ -398,7 +399,7 @@ putstr: # expects number in eax print_num: # save registers - pusha + pushal mov $numbuf + 16, %esi movb $0, (%esi) @@ -415,7 +416,7 @@ convloop: call putstr # restore regs - popa + popal ret @@ -429,7 +430,7 @@ video_newline: 0: ret scrollup: - pusha + pushal # move 80 * 24 lines from b80a0 -> b8000 mov $0xb8000, %edi mov $0xb80a0, %esi @@ -440,7 +441,7 @@ scrollup: xor %eax, %eax mov $40, %ecx addr32 rep stosl - popa + popal ret clearscr: diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..f01bf9d --- /dev/null +++ b/src/config.h @@ -0,0 +1,7 @@ +#ifndef PCBOOT_CONFIG_H_ +#define PCBOOT_CONFIG_H_ + +#define CON_TEXTMODE +#define CON_SERIAL + +#endif /* PCBOOT_CONFIG_H_ */ diff --git a/src/contty.c b/src/contty.c new file mode 100644 index 0000000..9a78ca2 --- /dev/null +++ b/src/contty.c @@ -0,0 +1,202 @@ +#include +#include +#include "contty.h" +#include "serial.h" +#include "asmops.h" +#include "config.h" + +#define VIRT_ROWS 200 + +#define NCOLS 80 +#define NROWS 25 +#define TEXT_ADDR ((char*)0xb8000) + +#define CRTC_ADDR 0x3d4 +#define CRTC_DATA 0x3d5 + +#define CRTC_REG_CURSTART 0x0a +#define CRTC_REG_CUREND 0x0b +#define CRTC_REG_START_H 0x0c +#define CRTC_REG_START_L 0x0d +#define CRTC_REG_CURLOC_H 0x0e +#define CRTC_REG_CURLOC_L 0x0f + +#define VMEM_CHAR(c, attr) \ + ((uint16_t)(c) | ((uint16_t)(attr) << 8)) + +static void scroll(void); +static void crtc_cursor(int x, int y); +static void crtc_setstart(int y); +static inline unsigned char crtc_read(int reg); +static inline void crtc_write(int reg, unsigned char val); +static inline void crtc_write_bits(int reg, unsigned char val, unsigned char mask); + +extern int cursor_x, cursor_y; +static unsigned char txattr = 0x07; +static int start_line; + +int con_init(void) +{ +#ifdef CON_SERIAL + ser_open(0, 9600, SER_8N1); +#endif + +#ifdef CON_TEXTMODE + con_show_cursor(1); + crtc_setstart(0); + crtc_cursor(cursor_x, cursor_y); + /* + printf("curloc: %x %x\n", (unsigned int)crtc_read(CRTC_REG_CURLOC_H), + (unsigned int)crtc_read(CRTC_REG_CURLOC_L)); + printf("curstart: %x\n", (unsigned int)crtc_read(CRTC_REG_CURSTART)); + printf("curend: %x\n", (unsigned int)crtc_read(CRTC_REG_CUREND)); + */ +#endif + + return 0; +} + +void con_show_cursor(int show) +{ +#ifdef CON_TEXTMODE + unsigned char val = show ? 0 : 0x20; + + crtc_write_bits(CRTC_REG_CURSTART, val, 0x20); +#endif +} + +void con_cursor(int x, int y) +{ +#ifdef CON_TEXTMODE + cursor_x = x; + cursor_y = y; + crtc_cursor(x, y); +#endif +} + +void con_fgcolor(int c) +{ + txattr = (txattr & 0xf0) | c; +} + +void con_bgcolor(int c) +{ + txattr = (txattr & 0x0f) | (c << 4); +} + +void con_clear(void) +{ +#ifdef CON_TEXTMODE + memset(TEXT_ADDR, 0, NCOLS * NROWS * 2); + + start_line = 0; + crtc_setstart(0); + + cursor_x = cursor_y = 0; + crtc_cursor(0, 0); +#endif +} + +static inline void linefeed(void) +{ + if(++cursor_y >= NROWS) { + scroll(); + --cursor_y; + } +} + +void con_putchar(int c) +{ +#ifdef CON_TEXTMODE + uint16_t *ptr; + + switch(c) { + case '\n': + linefeed(); + case '\r': + cursor_x = 0; + crtc_cursor(cursor_x, cursor_y); + break; + + case '\t': + cursor_x = (cursor_x & 0x7) + 8; + if(cursor_x >= NCOLS) { + linefeed(); + cursor_x = 0; + } + crtc_cursor(cursor_x, cursor_y); + break; + + default: + ptr = (uint16_t*)TEXT_ADDR; + ptr[(cursor_y + start_line) * NCOLS + cursor_x] = VMEM_CHAR(c, txattr); + + if(++cursor_x >= NCOLS) { + linefeed(); + cursor_x = 0; + } + crtc_cursor(cursor_x, cursor_y); + } +#endif + +#ifdef CON_SERIAL + ser_putchar(c); +#endif +} + +static void scroll(void) +{ + int new_line; + + if(++start_line > VIRT_ROWS - NROWS) { + /* The bottom of the visible range reached the end of our text buffer. + * Copy the rest of the lines to the top and reset start_line. + */ + memcpy(TEXT_ADDR, TEXT_ADDR + start_line * NCOLS, (NROWS - 1) * NCOLS * 2); + start_line = 0; + } + + /* clear the next line that will be revealed by scrolling */ + new_line = start_line + NROWS - 1; + memset16(TEXT_ADDR + new_line * NCOLS, VMEM_CHAR(' ', txattr), NCOLS); + crtc_setstart(start_line); +} + +static void crtc_cursor(int x, int y) +{ + unsigned int addr; + + addr = (y + start_line) * NCOLS + x; + + crtc_write(CRTC_REG_CURLOC_L, addr); + crtc_write(CRTC_REG_CURLOC_H, addr >> 8); +} + +static void crtc_setstart(int y) +{ + unsigned int addr = y * NCOLS; + + crtc_write(CRTC_REG_START_L, addr); + crtc_write(CRTC_REG_START_H, addr >> 8); +} + +static inline unsigned char crtc_read(int reg) +{ + outb(reg, CRTC_ADDR); + return inb(CRTC_DATA); +} + +static inline void crtc_write(int reg, unsigned char val) +{ + outb(reg, CRTC_ADDR); + outb(val, CRTC_DATA); +} + +static inline void crtc_write_bits(int reg, unsigned char val, unsigned char mask) +{ + unsigned char prev; + outb(reg, CRTC_ADDR); + prev = inb(CRTC_DATA); + val = (prev & ~mask) | (val & mask); + outb(val, CRTC_DATA); +} diff --git a/src/contty.h b/src/contty.h new file mode 100644 index 0000000..c8013e6 --- /dev/null +++ b/src/contty.h @@ -0,0 +1,12 @@ +#ifndef CONTTY_H_ +#define CONTTY_H_ + +int con_init(void); +void con_show_cursor(int show); +void con_cursor(int x, int y); +void con_fgcolor(int c); +void con_bgcolor(int c); +void con_clear(void); +void con_putchar(int c); + +#endif /* CONTTY_H_ */ diff --git a/src/kmain.c b/src/kmain.c new file mode 100644 index 0000000..f1533b2 --- /dev/null +++ b/src/kmain.c @@ -0,0 +1,11 @@ +#include +#include "contty.h" + +static int foo = 42; + +void pcboot_main(void) +{ + con_init(); + + printf("hello world: %d\n", foo); +} 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 new file mode 100644 index 0000000..9676441 --- /dev/null +++ b/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/src/libc/ctype.h b/src/libc/ctype.h new file mode 100644 index 0000000..5b010d4 --- /dev/null +++ b/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/src/libc/errno.h b/src/libc/errno.h new file mode 100644 index 0000000..a63ec24 --- /dev/null +++ b/src/libc/errno.h @@ -0,0 +1,19 @@ +#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 EBUG 127 /* for missing features and known bugs */ + +#endif /* ERRNO_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/stdarg.h b/src/libc/stdarg.h new file mode 100644 index 0000000..f870438 --- /dev/null +++ b/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/src/libc/stdio.c b/src/libc/stdio.c new file mode 100644 index 0000000..82f036f --- /dev/null +++ b/src/libc/stdio.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include "contty.h" + +extern void pcboot_putchar(int c); + +static void bwrite(char *buf, size_t buf_sz, char *str, int sz); +static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap); + +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 -- */ + +static char *convc = "dioxXucsfeEgGpn%"; + +#define IS_CONV(c) strchr(convc, c) + +int printf(const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(0, 0, fmt, ap); + va_end(ap); + return res; +} + +int vprintf(const char *fmt, va_list ap) +{ + return intern_printf(0, 0, fmt, ap); +} + +int sprintf(char *buf, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(buf, 0, fmt, ap); + va_end(ap); + return res; +} + +int vsprintf(char *buf, const char *fmt, va_list ap) +{ + return intern_printf(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(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(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. + */ + +#define BUF(x) ((x) ? (x) + cnum : (x)) +#define SZ(x) ((x) ? (x) - cnum : (x)) + +static int intern_printf(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; /* not implemented yet */ + int hex_caps = 0; + int unsig = 0; + + 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(BUF(buf), SZ(sz), "0x", 2); + } + + case 'u': + unsig = 1; + + if(0) { + case 'o': + base = 8; + + if(alt) { + bwrite(BUF(buf), SZ(sz), "0", 1); + } + } + + case 'd': + case 'i': + if(unsig) { + utoa(va_arg(ap, unsigned int), conv_buf, base); + } else { + itoa(va_arg(ap, int), conv_buf, base); + } + if(hex_caps) { + for(i=0; conv_buf[i]; i++) { + conv_buf[i] = toupper(conv_buf[i]); + } + } + + slen = strlen(conv_buf); + 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); + +#endif /* STDIO_H_ */ diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c new file mode 100644 index 0000000..9b8dcc4 --- /dev/null +++ b/src/libc/stdlib.c @@ -0,0 +1,119 @@ +#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; + + 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; + char c = tolower(*str); + + if(isdigit(c)) { + val = *str - '0'; + } else if(c >= 'a' || c <= 'f') { + val = 10 + c - 'a'; + } + if(val >= base) { + break; + } + + acc = acc * base + val; + str++; + } + + if(endp) { + *endp = (char*)str; + } + + 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; +} + diff --git a/src/libc/stdlib.h b/src/libc/stdlib.h new file mode 100644 index 0000000..9c28e74 --- /dev/null +++ b/src/libc/stdlib.h @@ -0,0 +1,20 @@ +#ifndef STDLIB_H_ +#define STDLIB_H_ + +#include + +typedef int32_t ssize_t; +typedef uint32_t size_t; + +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); + +/* defined in malloc.c */ +void *malloc(size_t sz); +void free(void *ptr); + +#endif /* STDLIB_H_ */ diff --git a/src/libc/string.c b/src/libc/string.c new file mode 100644 index 0000000..a651d53 --- /dev/null +++ b/src/libc/string.c @@ -0,0 +1,117 @@ +#include + +void memset(void *s, int c, size_t n) +{ + char *ptr = s; + while(n--) { + *ptr++ = c; + } +} + +/* Does the same thing as memset only with 16bit values. + * n in this case is the number of values, not the number of bytes. + */ +void memset16(void *s, int c, size_t n) +{ + int16_t *ptr = s; + while(n--) { + *ptr++ = c; + } +} + +void *memcpy(void *dest, const void *src, size_t n) +{ + char *dptr = dest; + const char *sptr = src; + + while(n--) { + *dptr++ = *sptr++; + } + 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= 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; +} + +int strcmp(const char *s1, const char *s2) +{ + while(*s1 && *s1 == *s2) { + s1++; + s2++; + } + return *s1 - *s2; +} diff --git a/src/libc/string.h b/src/libc/string.h new file mode 100644 index 0000000..9710520 --- /dev/null +++ b/src/libc/string.h @@ -0,0 +1,21 @@ +#ifndef STRING_H_ +#define STRING_H_ + +#include + +void memset(void *s, int c, size_t n); +void memset16(void *s, int c, size_t n); + +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, 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); + +int strcmp(const char *s1, const char *s2); + +#endif /* STRING_H_ */ diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 0000000..c707591 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,321 @@ +#include +#include +#include "serial.h" +#include "asmops.h" + +#define UART1_BASE 0x3f8 +#define UART2_BASE 0x2f8 +#define UART1_IRQ 4 +#define UART2_IRQ 3 + +#define UART_DATA 0 +#define UART_INTR 1 +#define UART_DIVLO 0 +#define UART_DIVHI 1 +#define UART_FIFO 2 +#define UART_IID 2 +#define UART_LCTL 3 +#define UART_MCTL 4 +#define UART_LSTAT 5 +#define UART_MSTAT 6 + +/* interrupt enable register bits */ +#define INTR_RECV 1 +#define INTR_SEND 2 +#define INTR_LSTAT 4 +#define INTR_DELTA 8 + +/* fifo control register bits */ +#define FIFO_ENABLE 0x01 +#define FIFO_RECV_CLEAR 0x02 +#define FIFO_SEND_CLEAR 0x04 +#define FIFO_DMA 0x08 +#define FIFO_TRIG_4 0x40 +#define FIFO_TRIG_8 0x80 +#define FIFO_TRIG_14 0xc0 + +/* interrupt id register bits */ +#define IID_PENDING 0x01 +#define IID_ID0 0x02 +#define IID_ID1 0x04 +#define IID_ID2 0x08 +#define IID_FIFO_EN 0xc0 + +#define IID_SOURCE 0xe + +#define IID_DELTA 0 +#define IID_SEND 0x2 +#define IID_RECV 0x4 +#define IID_FIFO 0xc +#define IID_STATUS 0x6 + +/* line control register bits */ +#define LCTL_BITS_8 0x03 +#define LCTL_STOP_2 0x04 +#define LCTL_DLAB 0x80 +#define LCTL_8N1 LCTL_BITS_8 +#define LCTL_8N2 (LCTL_BITS_8 | LCTL_STOP_2) + +/* modem control register bits */ +#define MCTL_DTR 0x01 +#define MCTL_RTS 0x02 +#define MCTL_OUT1 0x04 +#define MCTL_OUT2 0x08 +#define MCTL_LOOP 0x10 + +/* line status register bits */ +#define LST_DRDY 0x01 +#define LST_ERR_OVER 0x02 +#define LST_ERR_PARITY 0x04 +#define LST_ERR_FRAME 0x08 +#define LST_ERR_BRK 0x10 +#define LST_TREG_EMPTY 0x20 +#define LST_TIDLE 0x40 +#define LST_ERROR 0x80 + +/* modem status register bits */ +#define MST_DELTA_CTS 0x01 +#define MST_DELTA_DSR 0x02 +#define MST_TERI 0x04 +#define MST_DELTA_DCD 0x08 +#define MST_CTS 0x10 +#define MST_DSR 0x20 +#define MST_RING 0x40 +#define MST_DCD 0x80 + +/* interrupt controller stuff */ +#define PIC1_CMD_PORT 0x20 +#define PIC1_DATA_PORT 0x21 +#define PIC2_CMD_PORT 0xa0 +#define PIC2_DATA_PORT 0xa1 +#define OCW2_EOI 0x20 + +#define COM_FMT_8N1 LCTL_8N1 +#define COM_FMT_8N2 LCTL_8N2 + +struct serial_port { + int base, intr; + int blocking; + + char inbuf[256]; + int inbuf_ridx, inbuf_widx; +}; + +#define BNEXT(x) (((x) + 1) & 0xff) +#define BEMPTY(b) (b##_ridx == b##_widx) + +/* +static int have_recv(int base); +static void recv_intr(void);*/ + +static struct serial_port ports[2]; +static int num_open; + +static int uart_base[] = {UART1_BASE, UART2_BASE}; +/*static int uart_irq[] = {UART1_IRQ, UART2_IRQ};*/ + +int ser_open(int pidx, int baud, unsigned int mode) +{ + unsigned short div = 115200 / baud; + int base; /*intr*/ + unsigned int fmt; + /*int prev_if;*/ + + if(pidx < 0 || pidx > 1) { + printf("ser_open: invalid serial port: %d\n", pidx); + return -1; + } + + if(ports[pidx].base) { + printf("ser_open: port %d already open!\n", pidx); + return -1; + } + memset(ports + pidx, 0, sizeof ports[pidx]); + + base = uart_base[pidx]; + /*intr = uart_irq[pidx] | 8;*/ + + if(mode & SER_8N2) { + fmt = COM_FMT_8N2; + } else { + fmt = COM_FMT_8N1; + } + + /*prev_if = disable_intr();*/ + /* TODO set interrupt handler */ + /* unmask the appropriate interrupt */ + /*outb(inb(PIC1_DATA_PORT) & ~(1 << uart_irq[pidx]), PIC1_DATA_PORT);*/ + + outb(LCTL_DLAB, base + UART_LCTL); + outb(div & 0xff, base + UART_DIVLO); + outb((div >> 8) & 0xff, base + UART_DIVHI); + outb(fmt, base + UART_LCTL); /* fmt should be LCTL_8N1, LCTL_8N2 etc */ + outb(FIFO_ENABLE | FIFO_SEND_CLEAR | FIFO_RECV_CLEAR, base + UART_FIFO); + outb(MCTL_DTR | MCTL_RTS | MCTL_OUT2, base + UART_MCTL); + /*outb(INTR_RECV, base + UART_INTR); + + restore_intr(prev_if);*/ + + ports[pidx].base = base; + /*ports[pidx].intr = intr;*/ + ports[pidx].blocking = 1; + ++num_open; + return pidx; +} + +void ser_close(int fd) +{ + if(--num_open == 0) { + /*int prev_if = disable_intr();*/ + /*outb(0, ports[fd].base + UART_INTR);*/ + outb(0, ports[fd].base + UART_MCTL); + /*restore_intr(prev_if);*/ + } + + ports[fd].base = 0; +} + +int ser_block(int fd) +{ + ports[fd].blocking = 1; + return 0; +} + +int ser_nonblock(int fd) +{ + ports[fd].blocking = 0; + return 0; +} + +int ser_pending(int fd) +{ + return !BEMPTY(ports[fd].inbuf); +} + +/* if msec < 0: wait for ever */ +int ser_wait(int fd, long msec) +{ + int res; + while(!(res = ser_pending(fd))) { + /* TODO timeout */ + } + return res; +} + +static int can_send(int fd) +{ + int base = ports[fd].base; + return inb(base + UART_LSTAT) & LST_TREG_EMPTY; +} + +void ser_putc(int fd, char c) +{ + int base = ports[fd].base; + while(!can_send(fd)); + while((inb(base + UART_MSTAT) & MST_CTS) == 0); + outb(c, base + UART_DATA); +} + +int ser_getc(int fd) +{ + struct serial_port *p = ports + fd; + int have, c = -1; + + if(p->blocking) { + while(!(have = ser_pending(fd))); + } else { + have = ser_pending(fd); + } + + if(have) { + c = p->inbuf[p->inbuf_ridx]; + p->inbuf_ridx = BNEXT(p->inbuf_ridx); + } + return c; +} + +int ser_write(int fd, const char *buf, int count) +{ + int n = count; + while(n--) { + ser_putc(fd, *buf++); + } + return count; +} + +int ser_read(int fd, char *buf, int count) +{ + int c, n = 0; + while(n < count && (c = ser_getc(fd)) != -1) { + *buf++ = c; + ++n; + } + return n; +} + +char *ser_getline(int fd, char *buf, int bsz) +{ + static char linebuf[512]; + static int widx; + int i, rd, size, offs; + + size = sizeof linebuf - widx; + while(size && (rd = ser_read(fd, linebuf + widx, size)) > 0) { + widx += rd; + size -= rd; + } + + linebuf[widx] = 0; + + for(i=0; i= bsz ? bsz - 1 : i; + memcpy(buf, linebuf, size); + buf[size] = 0; + + offs = i + 1; + memmove(linebuf, linebuf + offs, widx - offs); + widx -= offs; + return buf; + } + } + return 0; +} + +#if 0 +static int have_recv(int base) +{ + unsigned short stat = inb(base + UART_LSTAT); + if(stat & LST_ERROR) { + printf("serial receive error\n"); + panic(); + } + return stat & LST_DRDY; +} + +static void __interrupt __far recv_intr() +{ + int i, idreg, c; + + for(i=0; i<2; i++) { + int base = uart_base[i]; + struct serial_port *p = ports + i; + + while(((idreg = inb(base + UART_IID)) & IID_PENDING) == 0) { + while(have_recv(base)) { + c = inb(base + UART_DATA); + + p->inbuf[p->inbuf_widx] = inb(base + UART_DATA); + p->inbuf_widx = BNEXT(p->inbuf_widx); + + if(p->inbuf_widx == p->inbuf_ridx) { + /* we overflowed, drop the oldest */ + p->inbuf_ridx = BNEXT(p->inbuf_ridx); + } + } + } + } + + outb(OCW2_EOI, PIC1_CMD_PORT); +} +#endif diff --git a/src/serial.h b/src/serial.h new file mode 100644 index 0000000..40d518d --- /dev/null +++ b/src/serial.h @@ -0,0 +1,29 @@ +#ifndef SERIAL_H_ +#define SERIAL_H_ + +#define SER_8N1 0 +#define SER_8N2 1 +#define SER_HWFLOW 2 + +int ser_open(int pidx, int baud, unsigned int mode); +void ser_close(int fd); + +int ser_block(int fd); +int ser_nonblock(int fd); + +int ser_pending(int fd); +/* if msec < 0: wait for ever */ +int ser_wait(int fd, long msec); + +void ser_putc(int fd, char c); +int ser_getc(int fd); + +int ser_write(int fd, const char *buf, int count); +int ser_read(int fd, char *buf, int count); + +#define ser_putchar(c) ser_putc(0, c) + +char *ser_getline(int fd, char *buf, int bsz); + + +#endif /* SERIAL_H_ */ diff --git a/src/startup.s b/src/startup.s index bff3991..4e32389 100644 --- a/src/startup.s +++ b/src/startup.s @@ -19,6 +19,7 @@ .extern _bss_start .extern _bss_end + .extern pcboot_main # zero the BSS section xor %eax, %eax @@ -29,7 +30,13 @@ rep stosl skip_bss_zero: + call pcboot_main + # pcboot_main never returns +0: cli + hlt + jmp 0b + .global logohack logohack: # copy palette mov $logo_pal, %esi