--- /dev/null
+target remote localhost:1234
+symbol-file test.sym
*.bin
test
*.map
+*.sym
+*.disasm
+*.img
+*.log
+*.tga
+*.png
+
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)
$(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
--- /dev/null
+#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_ */
# 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)
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
jnz 1f
call video_newline
-1: popa
+1: popal
ret
# expects string pointer in esi
# expects number in eax
print_num:
# save registers
- pusha
+ pushal
mov $numbuf + 16, %esi
movb $0, (%esi)
call putstr
# restore regs
- popa
+ popal
ret
0: ret
scrollup:
- pusha
+ pushal
# move 80 * 24 lines from b80a0 -> b8000
mov $0xb8000, %edi
mov $0xb80a0, %esi
xor %eax, %eax
mov $40, %ecx
addr32 rep stosl
- popa
+ popal
ret
clearscr:
--- /dev/null
+#ifndef PCBOOT_CONFIG_H_
+#define PCBOOT_CONFIG_H_
+
+#define CON_TEXTMODE
+#define CON_SERIAL
+
+#endif /* PCBOOT_CONFIG_H_ */
--- /dev/null
+#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);
+}
--- /dev/null
+#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_ */
--- /dev/null
+#include <stdio.h>
+#include "contty.h"
+
+static int foo = 42;
+
+void pcboot_main(void)
+{
+ con_init();
+
+ printf("hello world: %d\n", foo);
+}
--- /dev/null
+#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_ */
--- /dev/null
+#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;
+}
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+#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++);
+ }
+ }
+}
+
--- /dev/null
+#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_ */
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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_ */
--- /dev/null
+#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;
+}
--- /dev/null
+#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_ */
--- /dev/null
+#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
--- /dev/null
+#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_ */
.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