main kernel startup, libc, console tty, asmops, build flags fixes
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 25 Apr 2018 14:07:21 +0000 (17:07 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 25 Apr 2018 14:07:21 +0000 (17:07 +0300)
24 files changed:
.gdbinit [new file with mode: 0644]
.gitignore
Makefile
src/asmops.h [new file with mode: 0644]
src/boot/boot2.s
src/config.h [new file with mode: 0644]
src/contty.c [new file with mode: 0644]
src/contty.h [new file with mode: 0644]
src/kmain.c [new file with mode: 0644]
src/libc/assert.h [new file with mode: 0644]
src/libc/ctype.c [new file with mode: 0644]
src/libc/ctype.h [new file with mode: 0644]
src/libc/errno.h [new file with mode: 0644]
src/libc/inttypes.h [new file with mode: 0644]
src/libc/stdarg.h [new file with mode: 0644]
src/libc/stdio.c [new file with mode: 0644]
src/libc/stdio.h [new file with mode: 0644]
src/libc/stdlib.c [new file with mode: 0644]
src/libc/stdlib.h [new file with mode: 0644]
src/libc/string.c [new file with mode: 0644]
src/libc/string.h [new file with mode: 0644]
src/serial.c [new file with mode: 0644]
src/serial.h [new file with mode: 0644]
src/startup.s

diff --git a/.gdbinit b/.gdbinit
new file mode 100644 (file)
index 0000000..06d68b4
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1,2 @@
+target remote localhost:1234
+symbol-file test.sym
index 50d3557..87a02c0 100644 (file)
@@ -4,3 +4,10 @@
 *.bin
 test
 *.map
+*.sym
+*.disasm
+*.img
+*.log
+*.tga
+*.png
+
index 0722ce4..1a2f734 100644 (file)
--- 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 (file)
index 0000000..2578467
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef ASMOPS_H_
+#define ASMOPS_H_
+
+#include <inttypes.h>
+
+#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_ */
index 5422c0b..59918b8 100644 (file)
@@ -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 (file)
index 0000000..f01bf9d
--- /dev/null
@@ -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 (file)
index 0000000..9a78ca2
--- /dev/null
@@ -0,0 +1,202 @@
+#include <stdio.h>
+#include <string.h>
+#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 (file)
index 0000000..c8013e6
--- /dev/null
@@ -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 (file)
index 0000000..f1533b2
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#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 (file)
index 0000000..4ac0d15
--- /dev/null
@@ -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 (file)
index 0000000..9676441
--- /dev/null
@@ -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 (file)
index 0000000..5b010d4
--- /dev/null
@@ -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 (file)
index 0000000..a63ec24
--- /dev/null
@@ -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 (file)
index 0000000..1f10b06
--- /dev/null
@@ -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 (file)
index 0000000..f870438
--- /dev/null
@@ -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 (file)
index 0000000..82f036f
--- /dev/null
@@ -0,0 +1,264 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#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<fwidth; i++) {
+                                               bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+
+                                       bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
+                                       cnum += slen;
+                                       break;
+
+                               case 'c':
+                                       {
+                                               char c = va_arg(ap, int);
+                                               bwrite(BUF(buf), SZ(sz), &c, 1);
+                                               cnum++;
+                                       }
+                                       break;
+
+                               case 's':
+                                       str = va_arg(ap, char*);
+                                       slen = strlen(str);
+
+                                       for(i=slen; i<fwidth; i++) {
+                                               bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+                                       bwrite(BUF(buf), SZ(sz), str, slen);
+                                       cnum += slen;
+                                       break;
+
+                               case 'n':
+                                       *va_arg(ap, int*) = cnum;
+                                       break;
+
+                               default:
+                                       break;
+                               }
+
+                               /* restore default conversion state */
+                               base = 10;
+                               alt = 0;
+                               fwidth = 0;
+                               padc = ' ';
+                               hex_caps = 0;
+
+                               fstart = 0;
+                               fmt++;
+                       } else {
+                               switch(*fmt) {
+                               case '#':
+                                       alt = 1;
+                                       break;
+
+                               case '+':
+                                       sign = 1;
+                                       break;
+
+                               case '-':
+                                       left_align = 1;
+                                       break;
+
+                               case 'l':
+                               case 'L':
+                                       break;
+
+                               case '0':
+                                       padc = '0';
+                                       break;
+
+                               default:
+                                       if(isdigit(*fmt)) {
+                                               const char *fw = fmt;
+                                               while(*fmt && isdigit(*fmt)) fmt++;
+
+                                               fwidth = atoi(fw);
+                                               continue;
+                                       }
+                               }
+                               fmt++;
+                       }
+               } else {
+                       bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1);
+                       cnum++;
+               }
+       }
+
+       return 0;
+}
+
+
+/* bwrite is called by intern_printf to transparently handle writing into a
+ * buffer (if buf is non-null) or to the terminal (if buf is null).
+ */
+static void bwrite(char *buf, size_t buf_sz, char *str, int sz)
+{
+       if(buf) {
+               if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
+               memcpy(buf, str, sz);
+
+               buf[sz] = 0;
+       } else {
+               int i;
+               for(i=0; i<sz; i++) {
+                       putchar(*str++);
+               }
+       }
+}
+
diff --git a/src/libc/stdio.h b/src/libc/stdio.h
new file mode 100644 (file)
index 0000000..866ed70
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef STDIO_H_
+#define STDIO_H_
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+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 (file)
index 0000000..9b8dcc4
--- /dev/null
@@ -0,0 +1,119 @@
+#include <stdlib.h>
+#include <ctype.h>
+
+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 (file)
index 0000000..9c28e74
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef STDLIB_H_
+#define STDLIB_H_
+
+#include <inttypes.h>
+
+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 (file)
index 0000000..a651d53
--- /dev/null
@@ -0,0 +1,117 @@
+#include <string.h>
+
+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<n; i++) {
+                       *dptr++ = *sptr++;
+               }
+       } else {
+               /* backwards copy */
+               dptr = (char*)dest + n - 1;
+               sptr = (const char*)src + n - 1;
+               for(i=0; i<n; i++) {
+                       *dptr-- = *sptr--;
+               }
+       }
+
+       return dest;
+}
+
+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;
+}
+
+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 (file)
index 0000000..9710520
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef STRING_H_
+#define STRING_H_
+
+#include <stdlib.h>
+
+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 (file)
index 0000000..c707591
--- /dev/null
@@ -0,0 +1,321 @@
+#include <stdio.h>
+#include <string.h>
+#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<widx; i++) {
+               if(linebuf[i] == '\r' || linebuf[i] == '\n') {
+                       size = 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 (file)
index 0000000..40d518d
--- /dev/null
@@ -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_ */
index bff3991..4e32389 100644 (file)
@@ -19,6 +19,7 @@
 
        .extern _bss_start
        .extern _bss_end
+       .extern pcboot_main
 
        # zero the BSS section
        xor %eax, %eax
        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