backported fixes from 256boss
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 2 Sep 2019 00:24:29 +0000 (03:24 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 2 Sep 2019 00:24:29 +0000 (03:24 +0300)
41 files changed:
src/boot.h [new file with mode: 0644]
src/boot/boot.s
src/boot/boot2.s
src/contty.c
src/contty.h
src/intr.c
src/intr.h
src/kbregs.h
src/kbscan.h [new file with mode: 0644]
src/keyb.c
src/keyb.h
src/libc/alloca.h [new file with mode: 0644]
src/libc/ctype.c
src/libc/errno.h
src/libc/limits.h [new file with mode: 0644]
src/libc/malloc.c
src/libc/stddef.h [new file with mode: 0644]
src/libc/stdio.c
src/libc/stdio.h
src/libc/stdlib.c
src/libc/stdlib.h
src/libc/string.c
src/libc/string.h
src/libc/string_asm.s
src/lowcode.s
src/mem.c
src/mem.h
src/panic.c
src/panic.h
src/power.c [new file with mode: 0644]
src/power.h [new file with mode: 0644]
src/serial.c
src/startup.s
src/test/vbetest.c
src/timer.c
src/timer.h
src/vbe.c
src/vbe.h
src/video.c
src/video.h
src/video_asm.s

diff --git a/src/boot.h b/src/boot.h
new file mode 100644 (file)
index 0000000..e4bda1c
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef BOOT_H_
+#define BOOT_H_
+
+extern unsigned char low_mem_buffer[];
+extern int boot_drive_number;
+
+#endif /* BOOT_H_ */
index 4f0023a..fee0bb2 100644 (file)
@@ -1,5 +1,5 @@
 # pcboot - bootable PC demo/game kernel
-# Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+# Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
 # 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
index 68dffd4..53dff6d 100644 (file)
@@ -1,5 +1,5 @@
-# pcboot - bootable PC demo/game kernel
-# Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+# 256boss - bootable launcher for 256byte intros
+# Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
 # 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
index 6601ce8..9fdf1c7 100644 (file)
@@ -40,18 +40,20 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #define CRTC_REG_CURLOC_L      0x0f
 
 #define VMEM_CHAR(c, attr) \
-       ((uint16_t)(c) | ((uint16_t)(attr) << 8))
+       (((uint16_t)(c) & 0xff) | ((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;
+static unsigned char cy0, cy1;
+static int curvis;
+static int scr_on = 1;
 
 int con_init(void)
 {
@@ -60,26 +62,39 @@ int con_init(void)
 #endif
 
 #ifdef CON_TEXTMODE
+       cy0 = crtc_read(CRTC_REG_CURSTART);
+       curvis = cy0 & 0x20 ? 1 : 0;
+       cy0 &= 0x1f;
+       cy1 = crtc_read(CRTC_REG_CUREND) & 0x1f;
+
        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));
-       */
+       scr_on = 1;
 #endif
 
        return 0;
 }
 
+void con_scr_enable(void)
+{
+       scr_on = 1;
+}
+
+void con_scr_disable(void)
+{
+       scr_on = 0;
+}
+
 void con_show_cursor(int show)
 {
 #ifdef CON_TEXTMODE
-       unsigned char val = show ? 0 : 0x20;
-
-       crtc_write_bits(CRTC_REG_CURSTART, val, 0x20);
+       unsigned char val = cy0 & 0x1f;
+       if(!show) {
+               val |= 0x20;
+       }
+       crtc_write(CRTC_REG_CURSTART, val);
+       curvis = show;
 #endif
 }
 
@@ -92,6 +107,23 @@ void con_cursor(int x, int y)
 #endif
 }
 
+void con_curattr(int shape, int blink)
+{
+#ifdef CON_TEXTMODE
+       unsigned char start;
+       cy0 = (shape == CON_CURSOR_LINE) ? 0xd : 0;
+       cy1 = 0xe;
+
+       start = cy0;
+       if(curvis) {
+               start |= 0x20;
+       }
+
+       crtc_write(CRTC_REG_CURSTART, start);
+       crtc_write(CRTC_REG_CUREND, cy0);
+#endif
+}
+
 void con_fgcolor(int c)
 {
        txattr = (txattr & 0xf0) | c;
@@ -102,10 +134,20 @@ void con_bgcolor(int c)
        txattr = (txattr & 0x0f) | (c << 4);
 }
 
+void con_setattr(unsigned char attr)
+{
+       txattr = attr;
+}
+
+unsigned char con_getattr(void)
+{
+       return txattr;
+}
+
 void con_clear(void)
 {
 #ifdef CON_TEXTMODE
-       memset(TEXT_ADDR, 0, NCOLS * NROWS * 2);
+       memset16(TEXT_ADDR, VMEM_CHAR(' ', txattr), NCOLS * NROWS);
 
        start_line = 0;
        crtc_setstart(0);
@@ -126,33 +168,39 @@ static inline void linefeed(void)
 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:
-               con_putchar_scr(cursor_x, cursor_y, c);
-
-               if(++cursor_x >= NCOLS) {
+       if(scr_on) {
+               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;
+
+               case '\b':
+                       if(cursor_x > 0) cursor_x--;
+                       con_putchar_scr(cursor_x, cursor_y, ' ');
+                       crtc_cursor(cursor_x, cursor_y);
+                       break;
+
+               default:
+                       con_putchar_scr(cursor_x, cursor_y, c);
+
+                       if(++cursor_x >= NCOLS) {
+                               linefeed();
+                               cursor_x = 0;
+                       }
+                       crtc_cursor(cursor_x, cursor_y);
                }
-               crtc_cursor(cursor_x, cursor_y);
        }
 #endif
 
@@ -163,12 +211,15 @@ void con_putchar(int c)
 
 void con_putchar_scr(int x, int y, int c)
 {
+#ifdef CON_TEXTMODE
        uint16_t *ptr = (uint16_t*)TEXT_ADDR;
        ptr[(y + start_line) * NCOLS + x] = VMEM_CHAR(c, txattr);
+#endif
 }
 
-void con_printf(int x, int y, const char *fmt, ...)
+int con_printf(int x, int y, const char *fmt, ...)
 {
+#ifdef CON_TEXTMODE
        va_list ap;
        char buf[81];
        char *ptr = buf;
@@ -180,6 +231,10 @@ void con_printf(int x, int y, const char *fmt, ...)
        while(*ptr && x < 80) {
                con_putchar_scr(x++, y, *ptr++);
        }
+       return ptr - buf;
+#else
+       return 0;
+#endif
 }
 
 static void scroll(void)
@@ -229,12 +284,3 @@ 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);
-}
index bbd2775..fcc6e37 100644 (file)
@@ -18,15 +18,70 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #ifndef CONTTY_H_
 #define CONTTY_H_
 
+enum {
+       CON_CURSOR_LINE,
+       CON_CURSOR_BLOCK
+};
+
+enum {
+       BLACK,
+       BLUE,
+       GREEN,
+       CYAN,
+       RED,
+       MAGENTA,
+       BROWN,
+       LTGREY,
+       GREY,
+       LTBLUE,
+       LTGREEN,
+       LTCYAN,
+       LTRED,
+       LTMAGENTA,
+       YELLOW,
+       WHITE
+};
+#define BRIGHT         8
+#define FG_BRIGHT      0x08
+#define BG_BRIGHT      0x80
+
+enum {
+       G_DIAMOND       = 0x04,
+       G_CHECKER       = 0xb1,
+       G_LR_CORNER     = 0xd9,
+       G_UR_CORNER     = 0xbf,
+       G_UL_CORNER     = 0xda,
+       G_LL_CORNER     = 0xc0,
+       G_CROSS         = 0xc5,
+       G_HLINE         = 0xc4,
+       G_L_TEE         = 0xc3,
+       G_R_TEE         = 0xb4,
+       G_B_TEE         = 0xc1,
+       G_T_TEE         = 0xc2,
+       G_VLINE         = 0xb3,
+       G_CDOT          = 0xf8,
+
+       G_HDBL          = 0xcd,
+       G_UL_HDBL       = 0xd5,
+       G_UR_HDBL       = 0xb8,
+       G_T_HDBL_TEE = 0xd1
+};
+
+
 int con_init(void);
+void con_scr_enable(void);
+void con_scr_disable(void);
 void con_show_cursor(int show);
 void con_cursor(int x, int y);
+void con_curattr(int shape, int blink);
 void con_fgcolor(int c);
 void con_bgcolor(int c);
+void con_setattr(unsigned char attr);
+unsigned char con_getattr(void);
 void con_clear(void);
 void con_putchar(int c);
 
 void con_putchar_scr(int x, int y, int c);
-void con_printf(int x, int y, const char *fmt, ...);
+int con_printf(int x, int y, const char *fmt, ...);
 
 #endif /* CONTTY_H_ */
index 1946708..2ec1f1b 100644 (file)
@@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include <stdio.h>
+#include "config.h"
 #include "intr.h"
 #include "desc.h"
 #include "segm.h"
@@ -151,12 +152,17 @@ void dispatch_intr(struct intr_frame frm)
 
 void init_pic(void)
 {
+       prog_pic(IRQ_OFFSET);
+}
+
+void prog_pic(int offs)
+{
        /* send ICW1 saying we'll follow with ICW4 later on */
        outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC1_CMD);
        outb(ICW1_INIT | ICW1_ICW4_NEEDED, PIC2_CMD);
        /* send ICW2 with IRQ remapping */
-       outb(IRQ_OFFSET, PIC1_DATA);
-       outb(IRQ_OFFSET + 8, PIC2_DATA);
+       outb(offs, PIC1_DATA);
+       outb(offs + 8, PIC2_DATA);
        /* send ICW3 to setup the master/slave relationship */
        /* ... set bit3 = 3rd interrupt input has a slave */
        outb(4, PIC1_DATA);
@@ -257,3 +263,10 @@ void end_of_irq(int irq)
 
        set_intr_flag(intr_state);
 }
+
+#ifdef ENABLE_GDB_STUB
+void exceptionHandler(int id, void (*func)())
+{
+       set_intr_entry(id, func);
+}
+#endif
index fe6ed44..f33ec23 100644 (file)
@@ -72,6 +72,7 @@ void interrupt(int intr_num, intr_func_t func);
  */
 void set_intr_entry(int num, void (*handler)(void));
 
+void prog_pic(int offs);
 void set_pic_mask(int pic, unsigned char mask);
 unsigned char get_pic_mask(int pic);
 void mask_irq(int irq);
index 5c56c48..813fa1a 100644 (file)
@@ -27,6 +27,8 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 #define KB_ACK                 0xfa
 #define KB_NACK                        0xfe
+#define KB_TEST_PASSED 0x55
+#define KB_TEST_FAILED 0xfc
 
 #define KB_STAT_OUTBUF_FULL    0x01
 #define KB_STAT_INBUF_FULL     0x02
@@ -37,6 +39,8 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #define KB_STAT_TIMEOUT                0x40
 #define KB_STAT_PAR_ERROR      0x80
 
+#define KB_CMD_TEST                            0xaa
+
 /* keyboard commands */
 #define KB_CMD_GET_CMDBYTE             0x20
 #define KB_CMD_SET_CMDBYTE             0x60
diff --git a/src/kbscan.h b/src/kbscan.h
new file mode 100644 (file)
index 0000000..aaca8b8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef KBSCAN_H_
+#define KBSCAN_H_
+
+/* table with rough translations from set 1 scancodes to ASCII-ish */
+static int scantbl_set1[] = {
+       0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',            /* 0 - e */
+       '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',                 /* f - 1c */
+       KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',                          /* 1d - 29 */
+       KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT,                   /* 2a - 36 */
+       KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,                     /* 37 - 44 */
+       KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,      /* 45 - 4e */
+       KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,                                             /* 4d - 58 */
+       0, 0, 0, 0, 0, 0, 0,                                                                                                                    /* 59 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                                                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                                                                  /* 70 - 7f */
+};
+
+/* extended scancodes, after the 0xe0 prefix */
+static int scantbl_set1_ext[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 0 - f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r', KB_RCTRL, 0, 0,                       /* 10 - 1f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 20 - 2f */
+       0, 0, 0, 0, 0, KB_NUM_MINUS, 0, KB_SYSRQ, KB_RALT, 0, 0, 0, 0, 0, 0, 0,                 /* 30 - 3f */
+       0, 0, 0, 0, 0, 0, 0, KB_HOME, KB_UP, KB_PGUP, 0, KB_LEFT, 0, KB_RIGHT, 0, KB_END,       /* 40 - 4f */
+       KB_DOWN, KB_PGDN, KB_INSERT, KB_DEL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                        /* 50 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 70 - 7f */
+};
+
+
+#endif /* KBSCAN_H_ */
index 3e86f43..faf08a9 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -21,6 +21,9 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include "intr.h"
 #include "asmops.h"
 #include "kbregs.h"
+#include "kbscan.h"
+#include "power.h"
+#include "panic.h"
 
 #define delay7us() \
        do { \
@@ -28,19 +31,8 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
                iodelay(); iodelay(); iodelay(); \
        } while(0)
 
-/* table with rough translations from set 1 scancodes to ASCII-ish */
-static int scantbl[] = {
-       0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',            /* 0 - e */
-       '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',                 /* f - 1c */
-       KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',                          /* 1d - 29 */
-       KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT,                   /* 2a - 36 */
-       KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,                     /* 37 - 44 */
-       KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,      /* 45 - 4e */
-       KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,                                             /* 4d - 58 */
-       0, 0, 0, 0, 0, 0, 0,                                                                                                                    /* 59 - 5f */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                                                 /* 60 - 6f */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                                                                  /* 70 - 7f */
-};
+static void set_ccb(unsigned char ccb);
+static unsigned char get_ccb(void);
 
 static void kbintr();
 
@@ -53,13 +45,85 @@ static int buf_ridx, buf_widx;
 static unsigned int num_pressed;
 static unsigned char keystate[256];
 
+
 void kb_init(void)
 {
        buf_ridx = buf_widx = 0;
        num_pressed = 0;
        memset(keystate, 0, sizeof keystate);
 
+       /* make sure set1 translation is enabled */
+       kb_set_translate(1);
+
        interrupt(IRQ_TO_INTR(KB_IRQ), kbintr);
+       kb_intr_enable();
+}
+
+void kb_intr_enable(void)
+{
+       unsigned char ccb = get_ccb();
+       ccb |= KB_CCB_KB_INTREN;
+       set_ccb(ccb);
+}
+
+void kb_intr_disable(void)
+{
+       unsigned char ccb = get_ccb();
+       ccb &= ~KB_CCB_KB_INTREN;
+       set_ccb(ccb);
+}
+
+int kb_setmode(int mode)
+{
+       kb_send_data(0xf0);
+       if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+               return -1;
+       }
+       kb_send_data(mode);
+       if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+               return -1;
+       }
+       return 0;
+}
+
+int kb_getmode(void)
+{
+       int mode;
+
+       kb_send_data(0xf0);
+       if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+               return -1;
+       }
+       kb_send_data(0);
+       if(!kb_wait_read() || kb_read_data() != KB_ACK) {
+               return -1;
+       }
+       mode = kb_read_data();
+
+       switch(mode) {
+       case 0x43: return 1;
+       case 0x41: return 2;
+       case 0x3f: return 3;
+       default:
+               break;
+       }
+       return mode;
+}
+
+void kb_set_translate(int xlat)
+{
+       unsigned char ccb = get_ccb();
+       if(xlat) {
+               ccb |= KB_CCB_KB_XLAT;
+       } else {
+               ccb &= ~KB_CCB_KB_XLAT;
+       }
+       set_ccb(ccb);
+}
+
+int kb_get_translate(void)
+{
+       return get_ccb() & KB_CCB_KB_XLAT;
 }
 
 int kb_isdown(int key)
@@ -165,16 +229,38 @@ unsigned char kb_read_data(void)
        return inb(KB_DATA_PORT);
 }
 
+static void set_ccb(unsigned char ccb)
+{
+       kb_send_cmd(KB_CMD_SET_CMDBYTE);
+       kb_send_data(ccb);
+
+       if(kb_wait_read()) {
+               kb_read_data();
+       }
+}
+
+static unsigned char get_ccb(void)
+{
+       kb_send_cmd(KB_CMD_GET_CMDBYTE);
+       return kb_read_data();
+}
+
 static void kbintr()
 {
        unsigned char code;
        int key, press;
+       static int ext = 0;
 
        code = inb(KB_DATA_PORT);
 
-       if(code >= 128) {
+       if(code == 0xe0) {
+               ext = 1;
+               return;
+       }
+
+       if(code & 0x80) {
                press = 0;
-               code -= 128;
+               code &= 0x7f;
 
                if(num_pressed > 0) {
                        num_pressed--;
@@ -185,9 +271,13 @@ static void kbintr()
                num_pressed++;
        }
 
-       key = scantbl[code];
+       key = ext ? scantbl_set1_ext[code] : scantbl_set1[code];
+       ext = 0;
 
        if(press) {
+               if(key == KB_DEL && (keystate[KB_LALT] || keystate[KB_RALT]) && (keystate[KB_LCTRL] || keystate[KB_RCTRL])) {
+                       reboot();
+               }
                /* append to buffer */
                buffer[buf_widx] = key;
                ADVANCE(buf_widx);
index a5297e4..d031aee 100644 (file)
@@ -43,6 +43,15 @@ enum {
 
 void kb_init(void);
 
+void kb_intr_enable(void);
+void kb_intr_disable(void);
+
+int kb_setmode(int mode);
+int kb_getmode(void);
+
+void kb_set_translate(int xlat);
+int kb_get_translate(void);
+
 /* Boolean predicate for testing the current state of a particular key.
  * You may also pass KB_ANY to test if any key is held down.
  */
diff --git a/src/libc/alloca.h b/src/libc/alloca.h
new file mode 100644 (file)
index 0000000..ae27a71
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef ALLOCA_H_
+#define ALLOCA_H_
+
+#define alloca(x)      __builtin_alloca(x)
+
+#endif /* ALLOCA_H_ */
index 76746dd..89e7b93 100644 (file)
@@ -69,5 +69,5 @@ int toupper(int c)
 
 int tolower(int c)
 {
-       return isupper(c) ? (c + ('A' - 'a')) : c;
+       return isupper(c) ? (c - ('A' - 'a')) : c;
 }
index d7ab369..a4cf483 100644 (file)
@@ -30,6 +30,9 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #define ENOSPC                 10
 #define EPERM                  11
 #define ENOTDIR                        12
+#define EISDIR                 13
+#define EEXIST                 14
+#define ERANGE                 34
 
 #define EBUG                   127     /* for missing features and known bugs */
 
diff --git a/src/libc/limits.h b/src/libc/limits.h
new file mode 100644 (file)
index 0000000..b3abdad
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef LIMITS_H_
+#define LIMITS_H_
+
+#define CHAR_BIT       8
+
+#define SHRT_MIN       (-32768)
+#define SHRT_MAX       32767
+#define INT_MIN                (-2147483648)
+#define INT_MAX                2147483647
+#define LONG_MIN       (-2147483648)
+#define LONG_MAX       2147483647
+
+#define USHRT_MAX      65535
+#define UINT_MAX       0xffffffff
+#define ULONG_MAX      0xffffffff
+
+#define PATH_MAX       256
+
+#endif /* LIMITS_H_ */
index 3610d24..363ce03 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -19,20 +19,37 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
+#include "config.h"
 #include "mem.h"
 #include "panic.h"
 
+#define SINGLE_POOL
+
 struct mem_desc {
        size_t size;
        uint32_t magic;
+#ifdef MALLOC_DEBUG
+       uint32_t dbg;
+#endif
        struct mem_desc *next;
 };
 
-#define MAGIC  0xdeadf00d
+#ifdef MALLOC_DEBUG
+static void check_cycles(struct mem_desc *mem);
+static void print_pool(void);
+#endif
+
+#define MAGIC_USED     0xdeadf00d
+#define MAGIC_FREE     0x1ee7d00d
 
 #define DESC_PTR(b)    ((void*)((struct mem_desc*)(b) + 1))
 #define PTR_DESC(p)    ((struct mem_desc*)(p) - 1)
 
+#ifdef SINGLE_POOL
+static struct mem_desc *pool;
+#else
+
 #define NUM_POOLS      16
 #define FIRST_POOL_POW2        5
 /* 2**(x+5) size pools: 0->32, 1->64, 2->128 .. 15->1048576 */
@@ -53,6 +70,150 @@ static int pool_index(int sz)
        }
        return x - FIRST_POOL_POW2;
 }
+#endif /* !SINGLE_POOL */
+
+
+#ifdef SINGLE_POOL
+#define MIN_BLOCK_SIZE         (sizeof(struct mem_desc) * 2)
+
+void *malloc(size_t sz)
+{
+       int pg0, npages;
+       size_t total_sz, rest_sz;
+       struct mem_desc *mem, *rest, *prev, dummy;
+       int found = 0;
+
+       total_sz = (sz + sizeof(struct mem_desc) + 3) & 0xfffffffc;
+
+       dummy.next = pool;
+       prev = &dummy;
+       while(prev->next) {
+               mem = prev->next;
+               /* give the whole block to the allocation if mem->size == total_sz or
+                * if it's larger, but not large enough to fit another mem_desc in there
+                * for the new block that we're going to split off + some reasonable
+                * amount of memory for the new block.
+                */
+               if(mem->size >= total_sz && mem->size < total_sz + MIN_BLOCK_SIZE) {
+                       prev->next = mem->next;
+                       found = 1;
+                       break;
+               }
+               /* if we have enough space, split the block and give the upper part
+                * to the allocation
+                */
+               if(mem->size > total_sz) {
+                       void *ptr = (char*)mem + mem->size - total_sz;
+                       mem->size -= total_sz;
+                       mem = ptr;
+                       found = 1;
+                       break;
+               }
+               prev = prev->next;
+       }
+       pool = dummy.next;
+
+       if(found) {
+               mem->size = total_sz;
+               mem->magic = MAGIC_USED;
+               mem->next = 0;
+               return DESC_PTR(mem);
+       }
+
+       /* did not find a free block, grab a new one */
+       npages = BYTES_TO_PAGES(total_sz);
+       if((pg0 = alloc_ppages(npages, 0)) == -1) {
+               errno = ENOMEM;
+               return 0;
+       }
+       mem = PAGE_TO_PTR(pg0);
+       mem->size = total_sz;
+       mem->next = 0;
+       mem->magic = MAGIC_USED;
+
+       /* add the rest of the block to pool */
+       rest_sz = npages * 4096 - total_sz;
+       if(rest_sz > 0) {
+               rest = (struct mem_desc*)((char*)mem + total_sz);
+               rest->size = rest_sz;
+               rest->next = 0;
+               rest->magic = MAGIC_USED;
+               free(DESC_PTR(rest));
+       }
+
+       return DESC_PTR(mem);
+}
+
+void free(void *p)
+{
+       struct mem_desc *mem, *prev, *cur, dummy;
+       char *end;
+
+       if(!p) return;
+       mem = PTR_DESC(p);
+
+       if(mem->magic != MAGIC_USED) {
+               if(mem->magic == MAGIC_FREE) {
+                       panic("free(%p): double-free\n", p);
+               } else {
+                       panic("free(%p): corrupted magic (%x)!\n", p, mem->magic);
+               }
+       }
+       mem->magic = MAGIC_FREE;
+       mem->next = 0;
+
+       /* nothing in the pool, just add this one */
+       if(!pool) {
+               pool = mem;
+               return;
+       }
+
+       end = (char*)mem + mem->size;
+
+       dummy.next = pool;
+       prev = &dummy;
+
+       while(prev->next) {
+               cur = prev->next;
+
+               /* block starts right at the end of mem: coalesce */
+               if((char*)cur == end) {
+                       mem->size += cur->size;
+                       mem->next = cur->next;
+                       cur->magic = 0;
+                       prev->next = mem;
+                       goto done;
+               }
+
+               /* block starts *after* the end of mem: add in front */
+               if((char*)cur > end) {
+                       mem->next = cur;
+                       prev->next = mem;
+                       goto done;
+               }
+
+               prev = prev->next;
+       }
+
+       /* our block starts at the end of the last block in the pool: coalesce */
+       if((char*)prev + prev->size == (char*)mem) {
+               mem->magic = 0;
+               prev->size += mem->size;
+               goto done;
+       }
+
+       /* so our block starts after the end of the last block: append */
+       prev->next = mem;
+
+done:
+       pool = dummy.next;
+
+#ifdef MALLOC_DEBUG
+       print_pool();
+#endif
+}
+
+#else  /* !SINGLE_POOL */
 
 void *malloc(size_t sz)
 {
@@ -64,12 +225,12 @@ void *malloc(size_t sz)
 
        if(total_sz > MAX_POOL_SIZE) {
                /*printf("  allocation too big, hitting sys_alloc directly\n");*/
-               if((pg0 = alloc_ppages(BYTES_TO_PAGES(total_sz))) == -1) {
+               if((pg0 = alloc_ppages(BYTES_TO_PAGES(total_sz), 0)) == -1) {
                        errno = ENOMEM;
                        return 0;
                }
                mem = PAGE_TO_PTR(pg0);
-               mem->magic = MAGIC;
+               mem->magic = MAGIC_USED;
                mem->size = total_sz;
                mem->next = 0;
                return DESC_PTR(mem);
@@ -94,7 +255,10 @@ void *malloc(size_t sz)
                                add_to_pool(other);
                        }
 
-                       mem->magic = MAGIC;
+                       if(mem->magic != MAGIC_FREE) {
+                               panic("Trying to allocate range surrounded by an aura of wrong MAGIC\n");
+                       }
+                       mem->magic = MAGIC_USED;
                        return DESC_PTR(mem);
                }
 
@@ -103,14 +267,14 @@ void *malloc(size_t sz)
 
        /* did not find a free block, add a new one */
        pidx = NUM_POOLS - 1;
-       if((pg0 = alloc_ppages(MAX_POOL_PAGES)) == -1) {
+       if((pg0 = alloc_ppages(MAX_POOL_PAGES, 0)) == -1) {
                errno = ENOMEM;
                return 0;
        }
        mem = PAGE_TO_PTR(pg0);
        mem->size = MAX_POOL_SIZE;
        mem->next = pools[pidx];
-       mem->magic = MAGIC;
+       mem->magic = MAGIC_FREE;
        pools[pidx] = mem;
 
        /* try again now that there is a free block */
@@ -121,10 +285,17 @@ void *malloc(size_t sz)
 void free(void *p)
 {
        int pg0;
-       struct mem_desc *mem = PTR_DESC(p);
+       struct mem_desc *mem;
+
+       if(!p) return;
 
-       if(mem->magic != MAGIC) {
-               panic("free: corrupted magic!\n");
+       mem = PTR_DESC(p);
+       if(mem->magic != MAGIC_USED) {
+               if(mem->magic == MAGIC_FREE) {
+                       panic("free(%p): double-free\n", p);
+               } else {
+                       panic("free(%p): corrupted magic (%x)!\n", p, mem->magic);
+               }
        }
 
        if(mem->size > MAX_POOL_SIZE) {
@@ -139,6 +310,8 @@ void free(void *p)
        add_to_pool(mem);
 }
 
+#endif /* !def SINGLE_POOL */
+
 
 void *calloc(size_t num, size_t size)
 {
@@ -166,11 +339,44 @@ void *realloc(void *ptr, size_t size)
        if(!(newp = malloc(size))) {
                return 0;
        }
+       memcpy(newp, ptr, mem->size);
        free(ptr);
        return newp;
 }
 
+#ifdef MALLOC_DEBUG
+static void check_cycles(struct mem_desc *mem)
+{
+       static uint32_t dbg = 42;
+       uint32_t cur_dbg = dbg++;
 
+       while(mem) {
+               if(mem->magic != MAGIC_FREE) {
+                       panic("check_cycles: NON-FREE MAGIC!\n");
+               }
+               if(mem->dbg == cur_dbg) {
+                       panic("CYCLE DETECTED\n");
+               }
+               mem->dbg = cur_dbg;
+               mem = mem->next;
+       }
+}
+
+static void print_pool(void)
+{
+       struct mem_desc *mem = pool;
+
+       printf("DBG: malloc pool:\n");
+       while(mem) {
+               printf(" %p (%ld) [%x]\n", mem, mem->size, mem->magic);
+               mem = mem->next;
+
+               assert((uint32_t)mem != MAGIC_USED);
+       }
+}
+#endif /* MALLOC_DEBUG */
+
+#ifndef SINGLE_POOL
 static int add_to_pool(struct mem_desc *mem)
 {
        int pidx;
@@ -187,20 +393,22 @@ static int add_to_pool(struct mem_desc *mem)
        while(iter->next) {
                pnode = iter->next;
                if(mem->size == pnode->size) {  /* only coalesce same-sized blocks */
-                       if((char*)mem == (char*)pnode - pnode->size) {
+                       size_t size = mem->size;
+
+                       if((char*)mem == (char*)pnode - size) {
                                iter->next = pnode->next;       /* unlink pnode */
                                pools[pidx] = head.next;
                                mem->next = 0;
-                               mem->size += pnode->size;
+                               mem->size += size;
 
                                /*printf("  coalescing %p with %p and ", (void*)mem, (void*)pnode);*/
                                return add_to_pool(mem);
                        }
-                       if((char*)mem == (char*)pnode + pnode->size) {
+                       if((char*)mem == (char*)pnode + size) {
                                iter->next = pnode->next;       /* unlink pnode */
                                pools[pidx] = head.next;
                                pnode->next = 0;
-                               pnode->size += mem->size;
+                               pnode->size += size;
 
                                /*printf("  coalescing %p with %p and ", (void*)mem, (void*)pnode);*/
                                return add_to_pool(pnode);
@@ -210,8 +418,13 @@ static int add_to_pool(struct mem_desc *mem)
        }
 
        /* otherwise just add it to the pool */
+       mem->magic = MAGIC_FREE;
        mem->next = pools[pidx];
        pools[pidx] = mem;
+
+#ifdef MALLOC_DEBUG
+       check_cycles(pools[pidx]);
+#endif
        return 0;
 }
-
+#endif /* !def SINGLE_POOL */
diff --git a/src/libc/stddef.h b/src/libc/stddef.h
new file mode 100644 (file)
index 0000000..9ec6bda
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef STDDEF_H_
+#define STDDEF_H_
+
+#include <inttypes.h>
+
+typedef int32_t ssize_t;
+typedef uint32_t size_t;
+typedef int wchar_t;
+
+typedef int32_t ptrdiff_t;
+typedef uint32_t intptr_t;
+
+#define NULL   0
+
+#endif /* STDDEF_H_ */
index 1f2bb13..1f12fd6 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,8 +18,10 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <errno.h>
 #include "contty.h"
 #include "serial.h"
+#include "panic.h"
 
 enum {
        OUT_DEF,
@@ -30,8 +32,10 @@ enum {
 
 extern void pcboot_putchar(int c);
 
-static void bwrite(int out, char *buf, size_t buf_sz, char *str, int sz);
 static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list ap);
+static int intern_scanf(const char *instr, FILE *infile, const char *fmt, va_list ap);
+static void bwrite(int out, char *buf, size_t buf_sz, char *str, int sz);
+/*static int readchar(const char *str, FILE *fp);*/
 
 int putchar(int c)
 {
@@ -50,10 +54,6 @@ int puts(const char *s)
 
 /* -- printf and friends -- */
 
-static char *convc = "dioxXucsfeEgGpn%";
-
-#define IS_CONV(c)     strchr(convc, c)
-
 int printf(const char *fmt, ...)
 {
        int res;
@@ -102,6 +102,27 @@ int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
        return intern_printf(OUT_BUF, buf, sz, fmt, ap);
 }
 
+int fprintf(FILE *fp, const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = vfprintf(fp, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vfprintf(FILE *fp, const char *fmt, va_list ap)
+{
+       if(fp == stdout || fp == stderr) {
+               return vprintf(fmt, ap);
+       }
+
+       panic("*fprintf for anything other than stdout/stderr, not implemented yet\n");
+       return 0;
+}
+
 int ser_printf(const char *fmt, ...)
 {
        int res;
@@ -118,6 +139,11 @@ int ser_vprintf(const char *fmt, va_list ap)
        return intern_printf(OUT_SER, 0, 0, fmt, ap);
 }
 
+void perror(const char *s)
+{
+       printf("%s: %s\n", s, strerror(errno));
+}
+
 /* intern_printf provides all the functionality needed by all the printf
  * variants.
  * - buf: optional buffer onto which the formatted results are written. If null
@@ -127,6 +153,9 @@ int ser_vprintf(const char *fmt, va_list ap)
  *   by the (v)snprintf variants to avoid buffer overflows.
  * The rest are obvious, format string and variable argument list.
  */
+static char *convc = "dioxXucsfeEgGpn%";
+
+#define IS_CONV(c)     strchr(convc, c)
 
 #define BUF(x) ((x) ? (x) + cnum : (x))
 #define SZ(x)  ((x) ? (x) - cnum : (x))
@@ -145,9 +174,10 @@ static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list
        int fwidth = 0;
        int padc = ' ';
        int sign = 0;
-       int left_align = 0;     /* not implemented yet */
+       int left_align = 0;
        int hex_caps = 0;
        int unsig = 0;
+       int num, unum;
 
        while(*fmt) {
                if(*fmt == '%') {
@@ -167,6 +197,7 @@ static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list
 
                                        if(alt) {
                                                bwrite(out, BUF(buf), SZ(sz), "0x", 2);
+                                               cnum += 2;
                                        }
 
                                case 'u':
@@ -178,15 +209,18 @@ static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list
 
                                                if(alt) {
                                                        bwrite(out, BUF(buf), SZ(sz), "0", 1);
+                                                       cnum++;
                                                }
                                        }
 
                                case 'd':
                                case 'i':
                                        if(unsig) {
-                                               utoa(va_arg(ap, unsigned int), conv_buf, base);
+                                               unum = va_arg(ap, unsigned int);
+                                               utoa(unum, conv_buf, base);
                                        } else {
-                                               itoa(va_arg(ap, int), conv_buf, base);
+                                               num = va_arg(ap, int);
+                                               itoa(num, conv_buf, base);
                                        }
                                        if(hex_caps) {
                                                for(i=0; conv_buf[i]; i++) {
@@ -195,13 +229,28 @@ static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list
                                        }
 
                                        slen = strlen(conv_buf);
+
+                                       if(left_align) {
+                                               if(!unsig && sign && num >= 0) {
+                                                       bwrite(out, BUF(buf), SZ(sz), "+", 1);
+                                                       cnum++;
+                                               }
+                                               bwrite(out, BUF(buf), SZ(sz), conv_buf, slen);
+                                               cnum += slen;
+                                               padc = ' ';
+                                       }
                                        for(i=slen; i<fwidth; i++) {
                                                bwrite(out, BUF(buf), SZ(sz), (char*)&padc, 1);
                                                cnum++;
                                        }
-
-                                       bwrite(out, BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
-                                       cnum += slen;
+                                       if(!left_align) {
+                                               if(!unsig && sign && num >= 0) {
+                                                       bwrite(out, BUF(buf), SZ(sz), "+", 1);
+                                                       cnum++;
+                                               }
+                                               bwrite(out, BUF(buf), SZ(sz), conv_buf, slen);
+                                               cnum += slen;
+                                       }
                                        break;
 
                                case 'c':
@@ -216,12 +265,19 @@ static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list
                                        str = va_arg(ap, char*);
                                        slen = strlen(str);
 
+                                       if(left_align) {
+                                               bwrite(out, BUF(buf), SZ(sz), str, slen);
+                                               cnum += slen;
+                                               padc = ' ';
+                                       }
                                        for(i=slen; i<fwidth; i++) {
                                                bwrite(out, BUF(buf), SZ(sz), (char*)&padc, 1);
                                                cnum++;
                                        }
-                                       bwrite(out, BUF(buf), SZ(sz), str, slen);
-                                       cnum += slen;
+                                       if(!left_align) {
+                                               bwrite(out, BUF(buf), SZ(sz), str, slen);
+                                               cnum += slen;
+                                       }
                                        break;
 
                                case 'n':
@@ -280,8 +336,20 @@ static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list
                }
        }
 
-       return 0;
+       return cnum;
+}
+
+
+#if 0
+static char *sconvc = "diouxcsefg%";
+
+#define IS_SCONV(c)    strchr(sconvc, c)
+
+static int intern_scanf(const char *instr, FILE *infile, const char *fmt, va_list ap)
+{
+       return -1;      /* TODO */
 }
+#endif
 
 
 /* bwrite is called by intern_printf to transparently handle writing into a
@@ -292,10 +360,9 @@ static void bwrite(int out, char *buf, size_t buf_sz, char *str, int sz)
        int i;
 
        if(out == OUT_BUF) {
-               if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
-               memcpy(buf, str, sz);
-
+               if(buf_sz && buf_sz <= sz) sz = buf_sz;
                buf[sz] = 0;
+               memcpy(buf, str, sz);
        } else {
                switch(out) {
                case OUT_DEF:
@@ -317,3 +384,24 @@ static void bwrite(int out, char *buf, size_t buf_sz, char *str, int sz)
        }
 }
 
+/*
+static int readchar(const char *str, FILE *fp)
+{
+       static const char *orig_str;
+       static const char *sptr;
+
+       if(str) {
+               if(str == orig_str) {
+                       if(!*sptr) return -1;
+                       return *sptr++;
+               } else {
+                       orig_str = sptr = str;
+                       return readchar(str, fp);
+               }
+       } else {
+               return fgetc(fp);
+       }
+
+       return -1;
+}
+*/
index fbc79b7..19abc10 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -21,6 +21,18 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <stdarg.h>
 
+typedef struct FILE FILE;
+
+#define SEEK_SET       0
+#define SEEK_CUR       1
+#define SEEK_END       2
+
+#define EOF    (-1)
+
+#define stdin  ((FILE*)0)
+#define stdout ((FILE*)1)
+#define stderr ((FILE*)2)
+
 int putchar(int c);
 int puts(const char *s);
 
@@ -33,8 +45,46 @@ int vsprintf(char *buf, const char *fmt, va_list ap);
 int snprintf(char *buf, size_t sz, const char *fmt, ...);
 int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap);
 
+/* TODO */
+int fprintf(FILE *fp, const char *fmt, ...);
+int vfprintf(FILE *fp, const char *fmt, va_list ap);
+
+/* TODO
+int fscanf(FILE *fp, const char *fmt, ...);
+int vfscanf(FILE *fp, const char *fmt, va_list ap);
+
+int sscanf(const char *str, const char *fmt, ...);
+int vsscanf(const char *ptr, const char *fmt, va_list ap);
+*/
+
 /* printf to the serial port */
 int ser_printf(const char *fmt, ...);
 int ser_vprintf(const char *fmt, va_list ap);
 
+void perror(const char *s);
+
+
+/* FILE I/O */
+FILE *fopen(const char *path, const char *mode);
+int fclose(FILE *fp);
+
+long filesize(FILE *fp);
+int fseek(FILE *fp, long offset, int from);
+void rewind(FILE *fp);
+long ftell(FILE *fp);
+
+size_t fread(void *buf, size_t size, size_t count, FILE *fp);
+size_t fwrite(const void *buf, size_t size, size_t count, FILE *fp);
+
+int fgetc(FILE *fp);
+char *fgets(char *buf, int size, FILE *fp);
+
+int fputc(int c, FILE *fp);
+
+int fflush(FILE *fp);
+
+int feof(FILE *fp);
+int ferror(FILE *fp);
+void clearerr(FILE *fp);
+
 #endif /* STDIO_H_ */
index b3acce2..6b130ed 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -16,7 +16,11 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include <stdlib.h>
+#include <string.h>
 #include <ctype.h>
+#include <limits.h>
+#include <assert.h>
+#include <alloca.h>
 
 int atoi(const char *str)
 {
@@ -32,6 +36,8 @@ long strtol(const char *str, char **endp, int base)
 {
        long acc = 0;
        int sign = 1;
+       int valid = 0;
+       const char *start = str;
 
        while(isspace(*str)) str++;
 
@@ -55,24 +61,27 @@ long strtol(const char *str, char **endp, int base)
        }
 
        while(*str) {
-               long val;
+               long val = LONG_MAX;
                char c = tolower(*str);
 
                if(isdigit(c)) {
                        val = *str - '0';
-               } else if(c >= 'a' || c <= 'f') {
+               } else if(c >= 'a' && c <= 'f') {
                        val = 10 + c - 'a';
+               } else {
+                       break;
                }
                if(val >= base) {
                        break;
                }
+               valid = 1;
 
                acc = acc * base + val;
                str++;
        }
 
        if(endp) {
-               *endp = (char*)str;
+               *endp = (char*)(valid ? str : start);
        }
 
        return sign > 0 ? acc : -acc;
@@ -134,3 +143,130 @@ void utoa(unsigned int val, char *buf, int base)
        *buf = 0;
 }
 
+double atof(const char *str)
+{
+       return strtod(str, 0);
+}
+
+
+double strtod(const char *str, char **endp)
+{
+       char *ep;
+       const char *start = str;
+       int valid = 0;
+       long ival = 0, dval = 0;
+       int ddig = 0;
+       double res;
+
+       /* integer part */
+       ival = strtol(str, &ep, 10);
+       if(ep == str && *str != '.') {
+               if(endp) *endp = (char*)str;
+               return 0.0;
+       }
+       if(ep != str) valid = 1;
+       str = *ep == '.' ? ep + 1 : ep;
+       if(!isdigit(*str)) {
+               goto done;
+       }
+       valid = 1;
+
+       dval = strtol(str, &ep, 10);
+       assert(dval >= 0);
+       ddig = ep - str;
+       str = ep;
+
+done:
+       if(*endp) {
+               *endp = (char*)(valid ? str : start);
+       }
+
+       res = (double)ival;
+       if(ddig) {
+               double d = (double)dval;
+               while(ddig-- > 0) {
+                       d /= 10.0;
+               }
+               res += d;
+       }
+       return res;
+}
+
+int atexit(void (*func)(void))
+{
+       /* there's no concept of exiting at the moment, so this does nothing */
+       return 0;
+}
+
+void abort(void)
+{
+       panic("Aborted\n");
+}
+
+#define QSORT_THRESHOLD        4
+#define ITEM(idx)      ((char*)arr + (idx) * itemsz)
+
+#define SWAP(p, q) \
+       do { \
+               int nn = itemsz; \
+               char *pp = (p); \
+               char *qq = (q); \
+               do { \
+                       char tmp = *pp; \
+                       *pp++ = *qq; \
+                       *qq++ = tmp; \
+               } while(--nn > 0); \
+       } while(0)
+
+static void ins_sort(void *arr, size_t count, size_t itemsz, int (*cmp)(const void*, const void*))
+{
+       int i;
+       char *it, *a, *b;
+
+       if(count <= 1) return;
+
+       it = (char*)arr + itemsz;
+       for(i=1; i<count; i++) {
+               a = it;
+               it += itemsz;
+               while(a > (char*)arr && cmp(a, (b = a - itemsz)) < 0) {
+                       SWAP(a, b);
+                       a -= itemsz;
+               }
+       }
+}
+
+void qsort(void *arr, size_t count, size_t itemsz, int (*cmp)(const void*, const void*))
+{
+       char *ma, *mb, *mc, *left, *right;
+       size_t sepidx, nleft, nright;
+
+       if(count <= 1) return;
+
+       if(count < QSORT_THRESHOLD) {
+               ins_sort(arr, count, itemsz, cmp);
+               return;
+       }
+
+       ma = arr;
+       mb = ITEM(count / 2);
+       mc = ITEM(count - 1);
+       if(cmp(ma, mb) < 0) SWAP(ma, mb);
+       if(cmp(mc, ma) < 0) SWAP(mc, ma);
+
+       left = ma + itemsz;
+       right = mc - itemsz;
+       for(;;) {
+               while(cmp(left, ma) < 0) left += itemsz;
+               while(cmp(ma, right) < 0) right -= itemsz;
+               if(left >= right) break;
+               SWAP(left, right);
+       }
+       SWAP(ma, right);
+       sepidx = (right - (char*)arr) / itemsz;
+       nleft = sepidx;
+       nright = count - nleft - 1;
+
+       qsort(ma, nleft, itemsz, cmp);
+       qsort(right + itemsz, nright, itemsz, cmp);
+}
index 9a0eab4..981cf69 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,10 +18,11 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #ifndef STDLIB_H_
 #define STDLIB_H_
 
-#include <inttypes.h>
+#include <stddef.h>
 
-typedef int32_t ssize_t;
-typedef uint32_t size_t;
+#define RAND_MAX       2147483647
+
+#define abs(x) __builtin_abs(x)
 
 int atoi(const char *str);
 long atol(const char *str);
@@ -30,6 +31,19 @@ long strtol(const char *str, char **endp, int base);
 void itoa(int val, char *buf, int base);
 void utoa(unsigned int val, char *buf, int base);
 
+double atof(const char *str);
+double strtod(const char *str, char **endp);
+
+int atexit(void (*func)(void));
+
+void abort(void);
+
+void qsort(void *arr, size_t count, size_t size, int (*cmp)(const void*, const void*));
+
+int rand(void);
+int rand_r(unsigned int *seedp);
+void srand(unsigned int seed);
+
 /* defined in malloc.c */
 void *malloc(size_t sz);
 void *calloc(size_t num, size_t sz);
index ce3c2e7..4246aad 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -16,41 +16,8 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #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;
-}
-*/
+#include <ctype.h>
+#include <stddef.h>
 
 void *memmove(void *dest, const void *src, size_t n)
 {
@@ -77,6 +44,49 @@ void *memmove(void *dest, const void *src, size_t n)
        return dest;
 }
 
+int memcmp(void *aptr, void *bptr, size_t n)
+{
+       int i, startoffs, diff;
+       uint32_t *a32, *b32;
+       unsigned char *a = aptr;
+       unsigned char *b = bptr;
+
+       a32 = (uint32_t*)((intptr_t)(a + 3) & 0xfffffffc);
+       b32 = (uint32_t*)((intptr_t)(b + 3) & 0xfffffffc);
+
+       /* if both are aligned the same way... */
+       if((startoffs = (unsigned char*)a32 - a) == (unsigned char*)b32 - b) {
+               /* catch-up to the 32bit alignment */
+               for(i=0; i<startoffs; i++) {
+                       if((diff = *a++ - *b++) != 0 || --n <= 0) {
+                               return diff;
+                       }
+               }
+
+               /* compare 32bit at once */
+               while(n >= 4) {
+                       if(*a32 != *b32) break;
+                       a32++;
+                       b32++;
+                       n -= 4;
+               }
+
+               /* update byte pointers to contine with the tail */
+               a = (unsigned char*)a32;
+               b = (unsigned char*)b32;
+       }
+
+       /* we're here both for the tail-end of same-alignment buffers, or for the
+        * whole length of mis-aligned buffers.
+        */
+       while(n-- > 0) {
+               if((diff = *a++ - *b++) != 0) {
+                       return diff;
+               }
+       }
+       return 0;
+}
+
 size_t strlen(const char *s)
 {
        size_t len = 0;
@@ -129,6 +139,24 @@ char *strstr(const char *str, const char *substr)
        return 0;
 }
 
+char *strcasestr(const char *str, const char *substr)
+{
+       while(*str) {
+               const char *s1 = str;
+               const char *s2 = substr;
+
+               while(*s1 && tolower(*s1) == tolower(*s2)) {
+                       s1++;
+                       s2++;
+               }
+               if(!*s2) {
+                       return (char*)str;
+               }
+               str++;
+       }
+       return 0;
+}
+
 int strcmp(const char *s1, const char *s2)
 {
        while(*s1 && *s1 == *s2) {
@@ -137,3 +165,93 @@ int strcmp(const char *s1, const char *s2)
        }
        return *s1 - *s2;
 }
+
+int strcasecmp(const char *s1, const char *s2)
+{
+       while(*s1 && tolower(*s1) == tolower(*s2)) {
+               s1++;
+               s2++;
+       }
+       return tolower(*s1) - tolower(*s2);
+}
+
+int strncmp(const char *s1, const char *s2, int n)
+{
+       if(n <= 0) return 0;
+
+       while(n-- > 0 && *s1 && *s2 && *s1 == *s2) {
+               s1++;
+               s2++;
+       }
+
+       if(n <= 0) return 0;
+       return *s1 - *s2;
+}
+
+int strncasecmp(const char *s1, const char *s2, int n)
+{
+       if(n <= 0) return 0;
+
+       while(n-- > 0 && *s1 && *s2 && tolower(*s1) == tolower(*s2)) {
+               s1++;
+               s2++;
+       }
+
+       if(n <= 0) return 0;
+       return tolower(*s1) - tolower(*s2);
+}
+
+char *strcpy(char *dest, const char *src)
+{
+       char *dptr = dest;
+       while((*dptr++ = *src++));
+       return dest;
+}
+
+char *strcat(char *dest, const char *src)
+{
+       strcpy(dest + strlen(dest), src);
+       return dest;
+}
+
+char *strncpy(char *dest, const char *src, int n)
+{
+       char *dptr = dest;
+       while(n-- > 0 && (*dptr++ = *src++));
+       return dest;
+}
+
+
+static const char *errstr[] = {
+       "Success",
+       "Foo",
+       "Interrupted",
+       "Invalid",
+       "Child",
+       "Timeout",
+       "Out of memory",
+       "I/O error",
+       "Not found",
+       "Name too long",
+       "No space left on device",
+       "Permission denied",
+       "Not a directory",
+       "Is a directory",
+       "Does not exist",
+       0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,
+       0,0,0,0,0,0,0,
+       "Bug"
+};
+
+char *strerror(int err)
+{
+       if(err < 0 || err > sizeof errstr / sizeof *errstr || !errstr[err]) {
+               return "Unknown";
+       }
+       return (char*)errstr[err];
+}
index 63bb299..85490b2 100644 (file)
@@ -1,6 +1,6 @@
 /*
 pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -20,19 +20,33 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 #include <stdlib.h>
 
-void memset(void *s, int c, size_t n);
-void memset16(void *s, int c, size_t n);
+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);
 
+int memcmp(void *aptr, void *bptr, size_t n);
+
 size_t strlen(const char *s);
 
 char *strchr(const char *s, int c);
 char *strrchr(const char *s, int c);
 
 char *strstr(const char *str, const char *substr);
+char *strcasestr(const char *str, const char *substr);
 
 int strcmp(const char *s1, const char *s2);
+int strcasecmp(const char *s1, const char *s2);
+
+int strncmp(const char *s1, const char *s2, int n);
+int strncasecmp(const char *s1, const char *s2, int n);
+
+char *strcpy(char *dest, const char *src);
+char *strcat(char *dest, const char *src);
+
+char *strncpy(char *dest, const char *src, int n);
+
+char *strerror(int err);
 
 #endif /* STRING_H_ */
index ce9b19a..a15a405 100644 (file)
@@ -22,6 +22,7 @@ memset:
        push %edi
 
        mov 8(%ebp), %edi
+       push %edi
        mov 12(%ebp), %al
        mov %al, %ah
        mov %ax, %cx
@@ -32,26 +33,29 @@ memset:
        cmp $0, %ecx
        jz msdone
 
+       # write 1, 2, or 3 times until we reache a 32bit-aligned dest address
        mov %edi, %edx
        and $3, %edx
        jz msmain
        jmp *mspre_tab(,%edx,4)
 
 mspre_tab: .long msmain, mspre1, mspre2, mspre3
-mspre1:        stosb
+mspre3:        stosb
        dec %ecx
 mspre2:        stosb
        dec %ecx
-mspre3:        stosb
+mspre1:        stosb
        dec %ecx
        jz msdone
 
+       # edi is 32bit-aligned here, write ecx>>2 32bit values
 msmain:
        push %ecx
        shr $2, %ecx
        rep stosl
        pop %ecx
 
+       # write any trailing bytes
        and $3, %ecx
        jmp *mspost_tab(,%ecx,4)
 
@@ -61,6 +65,7 @@ mspost2:stosb
 mspost1:stosb
 
 msdone:
+       pop %eax
        pop %edi
        pop %ebp
        ret
@@ -75,6 +80,7 @@ memset16:
        push %edi
 
        mov 8(%ebp), %edi
+       push %edi
        mov 12(%ebp), %ax
        shl $16, %eax
        mov 12(%ebp), %ax
@@ -127,7 +133,7 @@ ms16main:
        jz ms16done
        stosw
 ms16done:
-
+       pop %eax
        pop %edi
        pop %ebp
        ret
index 67901e4..48bf290 100644 (file)
@@ -35,6 +35,7 @@ saved_eax: .long 0
 saved_es: .word 0
 saved_ds: .word 0
 saved_flags: .word 0
+saved_if: .byte 0
 saved_pic1_mask: .byte 0
 saved_pic2_mask: .byte 0
 
@@ -44,6 +45,8 @@ int86:
        push %ebp
        mov %esp, %ebp
        pushal
+       call get_intr_flag
+       mov %al, saved_if
        cli
        # save protected mode IDTR and replace it with the real mode vectors
        sidt (saved_idtr)
@@ -80,6 +83,8 @@ int86:
        mov %ax, %ds
        mov %ax, %es
        mov %ax, %ss
+       mov %ax, %fs
+       mov %ax, %gs
        nop
 
        # load registers from the int86regs struct
@@ -93,6 +98,11 @@ int86:
        pop %ds
        # ignore fs and gs for now, don't think I'm going to need them
 
+       # move to the real-mode stack, at the top of conventional memory
+       #mov $0x9000, %sp
+       #mov %sp, %ss
+       #mov $0, %esp
+
        # move to the real-mode stack, accessible from ss=0
        # just in case the BIOS call screws up our unreal mode
        mov $0x7be0, %esp
@@ -124,6 +134,8 @@ int_op:     int $0
        mov %ax, %ds
        mov %ax, %es
        mov %ax, %ss
+       mov %ax, %fs
+       mov %ax, %gs
        nop
 
        # point the esp to our regs struct, to fill it with pusha/pushf
@@ -168,11 +180,14 @@ int_op:   int $0
        # can't receive any more keyboard interrupts afterwards. Reading from
        # the keyboard data port (60h) once, seems to resolve this. And it's
        # cheap enough, so why not... I give up.
-       push %eax
        in $0x60, %al
-       pop %eax
 
-       sti
+       # restore interrupts to their previous state
+       movzbl saved_if, %eax
+       pushl %eax
+       call set_intr_flag
+       add $4, %esp
+
        popal
        pop %ebp
        ret
index 4125fe4..a013607 100644 (file)
--- a/src/mem.c
+++ b/src/mem.c
@@ -17,6 +17,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include <stdio.h>
 #include <string.h>
+#include "config.h"
 #include "panic.h"
 #include "mem.h"
 #include "intr.h"
@@ -37,6 +38,8 @@ struct mem_range {
        uint32_t size;
 };
 
+void move_stack(uint32_t newaddr);     /* defined in startup.s */
+
 static void mark_page(int pg, int used);
 static void add_memory(uint32_t start, size_t size);
 
@@ -63,7 +66,7 @@ static int bmsize, last_alloc_idx;
 
 void init_mem(void)
 {
-       int i, pg, max_pg = 0;
+       int i, pg, max_used_pg, end_pg = 0;
        uint32_t used_end, start, end, sz, total = 0, rem;
        const char *suffix[] = {"bytes", "KB", "MB", "GB"};
 
@@ -107,8 +110,8 @@ void init_mem(void)
                total += sz;
 
                pg = ADDR_TO_PAGE(end);
-               if(max_pg < pg) {
-                       max_pg = pg;
+               if(end_pg < pg) {
+                       end_pg = pg;
                }
        }
 
@@ -123,21 +126,29 @@ void init_mem(void)
        /* size of the useful part of the bitmap in bytes padded to 4-byte
         * boundaries to allow 32bit at a time operations.
         */
-       bmsize = (max_pg / 32 + 1) * 4;
+       bmsize = (end_pg / 32) * 4;
 
        /* mark all pages occupied by the bitmap as used */
        used_end = (uint32_t)bitmap + bmsize - 1;
 
-       max_pg = ADDR_TO_PAGE(used_end);
-       printf("marking pages up to %x (page: %d) as used\n", used_end, max_pg);
-       for(i=0; i<=max_pg; i++) {
+       max_used_pg = ADDR_TO_PAGE(used_end);
+       printf("marking pages up to %x (page: %d) as used\n", used_end, max_used_pg);
+       for(i=0; i<=max_used_pg; i++) {
                mark_page(i, USED);
        }
+
+#ifdef MOVE_STACK_RAMTOP
+       /* allocate space for the stack at the top of RAM and move it there */
+       if((pg = alloc_ppages(STACK_PAGES, MEM_STACK)) != -1) {
+               printf("moving stack-top to: %x (%d pages)\n", PAGE_TO_ADDR(end_pg) - 4, STACK_PAGES);
+               move_stack(PAGE_TO_ADDR(pg + STACK_PAGES) - 4);
+       }
+#endif
 }
 
-int alloc_ppage(void)
+int alloc_ppage(int area)
 {
-       return alloc_ppages(1);
+       return alloc_ppages(1, area);
 }
 
 /* free_ppage marks the physical page, free in the allocation bitmap.
@@ -167,26 +178,34 @@ void free_ppage(int pg)
 }
 
 
-int alloc_ppages(int count)
+int alloc_ppages(int count, int area)
 {
-       int i, pg, idx, max, intr_state, found_free = 0;
+       int i, dir, pg, idx, max, intr_state, found_free = 0;
 
        intr_state = get_intr_flag();
        disable_intr();
 
-       idx = last_alloc_idx;
-       max = bmsize / 4;
+       if(area == MEM_STACK) {
+               idx = (bmsize - 1) / 4;
+               max = -1;
+               dir = -1;
+       } else {
+               idx = last_alloc_idx;
+               max = bmsize / 4;
+               dir = 1;
+       }
 
-       while(idx <= max) {
+       while(idx != max) {
                /* if at least one bit is 0 then we have at least
                 * one free page. find it and try to allocate a range starting from there
                 */
                if(bitmap[idx] != 0xffffffff) {
-                       for(i=0; i<32; i++) {
-                               pg = idx * 32 + i;
+                       pg = idx * 32;
+                       if(dir < 0) pg += 31;
 
+                       for(i=0; i<32; i++) {
                                if(IS_FREE(pg)) {
-                                       if(!found_free) {
+                                       if(!found_free && dir > 0) {
                                                last_alloc_idx = idx;
                                                found_free = 1;
                                        }
@@ -196,9 +215,10 @@ int alloc_ppages(int count)
                                                return pg;
                                        }
                                }
+                               pg += dir;
                        }
                }
-               idx++;
+               idx += dir;
        }
 
        set_intr_flag(intr_state);
@@ -278,3 +298,17 @@ static void mark_page(int pg, int used)
        }
 }
 
+void print_page_bitmap(void)
+{
+       int i;
+
+       for(i=0; i<bmsize/4; i++) {
+               if((i & 3) == 0) {
+                       uint32_t pg = i * 32;
+                       uint32_t addr = PAGE_TO_ADDR(pg);
+                       printf("\n%5d [%08x]:", (int)pg, (unsigned long)addr);
+               }
+               printf(" %08x", bitmap[i]);
+       }
+       printf("\n");
+}
index c28136b..40de366 100644 (file)
--- a/src/mem.h
+++ b/src/mem.h
@@ -24,13 +24,19 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 #define BYTES_TO_PAGES(x)              (((uint32_t)(x) + 4095) >> 12)
 
+/* for alloc_ppage/alloc_ppages */
+enum {
+       MEM_HEAP = 0,   /* start searching from the bottom */
+       MEM_STACK = 1   /* start searching from the top */
+};
+
 void init_mem(void);
 
-int alloc_ppage(void);
+int alloc_ppage(int area);
 void free_ppage(int pg);
 
 /* allocate a number of consecutive pages */
-int alloc_ppages(int count);
+int alloc_ppages(int count, int area);
 void free_ppages(int pg0, int count);
 
 /* allocate a specific range of pages.
index 3daff29..1e79be6 100644 (file)
@@ -18,6 +18,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+#include "video.h"
 #include "asmops.h"
 
 struct all_registers {
@@ -37,6 +38,7 @@ void panic(const char *fmt, ...)
        struct all_registers regs;
        uint32_t eip;
 
+       set_vga_mode(3);
        disable_intr();
 
        memset(&regs, 0, sizeof regs);
index 67650b4..012eecb 100644 (file)
@@ -18,6 +18,6 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #ifndef PANIC_H_
 #define PANIC_H_
 
-void panic(const char *fmt, ...);
+void panic(const char *fmt, ...) __attribute__((noreturn));
 
 #endif /* PANIC_H_ */
diff --git a/src/power.c b/src/power.c
new file mode 100644 (file)
index 0000000..8a677d0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include "power.h"
+#include "keyb.h"
+#include "kbregs.h"
+#include "timer.h"
+#include "panic.h"
+#include "asmops.h"
+
+/* defined in intr_asm.S */
+void set_idt(uint32_t addr, uint16_t limit);
+
+void reboot(void)
+{
+       int i;
+
+       printf("reboot: keyboard controller\n");
+       kb_send_cmd(KB_CMD_PULSE_RESET);
+
+       for(i=0; i<32768; i++) {
+               iodelay();
+       }
+
+       printf("reboot: triple-fault\n");
+       set_idt(0, 0);
+       asm volatile("int $3");
+
+       panic("can't reboot!");
+}
diff --git a/src/power.h b/src/power.h
new file mode 100644 (file)
index 0000000..5e0c9fb
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef POWER_H_
+#define POWER_H_
+
+void reboot(void);
+
+#endif /* POWER_H_ */
index e833672..164b806 100644 (file)
@@ -17,8 +17,11 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include <stdio.h>
 #include <string.h>
+#include "config.h"
 #include "serial.h"
 #include "asmops.h"
+#include "intr.h"
+#include "panic.h"
 
 #define UART1_BASE     0x3f8
 #define UART2_BASE     0x2f8
@@ -121,22 +124,20 @@ struct serial_port {
 #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 void recv_intr();
 
 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};*/
+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*/
+       int base, intr;
        unsigned int fmt;
-       /*int prev_if;*/
 
        if(pidx < 0 || pidx > 1) {
                printf("ser_open: invalid serial port: %d\n", pidx);
@@ -150,7 +151,7 @@ int ser_open(int pidx, int baud, unsigned int mode)
        memset(ports + pidx, 0, sizeof ports[pidx]);
 
        base = uart_base[pidx];
-       /*intr = uart_irq[pidx] | 8;*/
+       intr = uart_irq[pidx];
 
        if(mode & SER_8N2) {
                fmt = COM_FMT_8N2;
@@ -158,10 +159,7 @@ int ser_open(int pidx, int baud, unsigned int mode)
                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);*/
+       interrupt(IRQ_TO_INTR(uart_irq[pidx]), recv_intr);
 
        outb(LCTL_DLAB, base + UART_LCTL);
        outb(div & 0xff, base + UART_DIVLO);
@@ -169,12 +167,10 @@ int ser_open(int pidx, int baud, unsigned int mode)
        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);*/
+       outb(INTR_RECV, base + UART_INTR);
 
        ports[pidx].base = base;
-       /*ports[pidx].intr = intr;*/
+       ports[pidx].intr = intr;
        ports[pidx].blocking = 1;
        ++num_open;
        return pidx;
@@ -183,10 +179,8 @@ int ser_open(int pidx, int baud, unsigned int mode)
 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_INTR);
                outb(0, ports[fd].base + UART_MCTL);
-               /*restore_intr(prev_if);*/
        }
 
        ports[fd].base = 0;
@@ -304,18 +298,16 @@ char *ser_getline(int fd, char *buf, int bsz)
        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();
+               panic("serial receive error\n");
        }
        return stat & LST_DRDY;
 }
 
-static void __interrupt __far recv_intr()
+static void recv_intr()
 {
        int i, idreg, c;
 
@@ -327,7 +319,14 @@ static void __interrupt __far recv_intr()
                        while(have_recv(base)) {
                                c = inb(base + UART_DATA);
 
-                               p->inbuf[p->inbuf_widx] = inb(base + UART_DATA);
+#ifdef ENABLE_GDB_STUB
+                               if(c == 3 && i == GDB_SERIAL_PORT) {
+                                       asm("int $3");
+                                       continue;
+                               }
+#endif
+
+                               p->inbuf[p->inbuf_widx] = c;
                                p->inbuf_widx = BNEXT(p->inbuf_widx);
 
                                if(p->inbuf_widx == p->inbuf_ridx) {
@@ -337,7 +336,16 @@ static void __interrupt __far recv_intr()
                        }
                }
        }
+}
 
-       outb(OCW2_EOI, PIC1_CMD_PORT);
+#ifdef ENABLE_GDB_STUB
+void putDebugChar(int c)
+{
+       ser_putc(GDB_SERIAL_PORT, c);
+}
+
+int getDebugChar(void)
+{
+       return ser_getc(GDB_SERIAL_PORT);
 }
 #endif
index ef3cd38..01090cd 100644 (file)
@@ -1,5 +1,5 @@
 # pcboot - bootable PC demo/game kernel
-# Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+# Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 # 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
        .extern wait_vsync
        .extern kb_getkey
 
+       .equ STACKTOP,0x80000
+
        # move the stack to the top of the conventional memory
        cli
-       movl $0x80000, %esp
+       movl $STACKTOP, %esp
+       # push a 0 ret-addr to terminate gdb backtraces
+       pushl $0
 
        # zero the BSS section
        xor %eax, %eax
@@ -43,6 +47,34 @@ skip_bss_zero:
        hlt
        jmp 0b
 
+       # this is called once after memory init, to move the protected mode
+       # stack to the top of usable memory, to avoid interference from 16bit
+       # programs (as much as possible)
+       .global move_stack
+move_stack:
+       # calculate the currently used lowest address of the stack (rounded
+       # down to 4-byte alignment), to see where to start copying
+       mov %esp, %esi
+       and $0xfffffffc, %esi
+       # calculate the size we need to copy
+       mov $STACKTOP, %ecx
+       sub %esi, %ecx
+       # load the destination address to edi
+       mov 4(%esp), %edi
+       sub %ecx, %edi
+       # size in longwords
+       shr $2, %ecx
+
+       # change esp to the new stack
+       mov $STACKTOP, %ecx
+       sub %esp, %ecx
+       mov 4(%esp), %eax
+       mov %eax, %esp
+       sub %ecx, %esp
+
+       rep movsd
+       ret
+
        .global logohack
 logohack:
        pusha
index ee7fb68..7dd2bad 100644 (file)
@@ -41,7 +41,7 @@ extern int snd_click_size;
 
 int vbetest(void)
 {
-       int i, j, nmodes, mx, my;
+       int i, j, nmodes, mx, my, idx;
        unsigned int st, prev_st = 0;
        struct video_mode vi;
        uint16_t *fbptr;
@@ -60,7 +60,12 @@ int vbetest(void)
                }
        }
 
-       if(!(framebuf = set_video_mode(find_video_mode(640, 480, 16)))) {
+       if((idx = find_video_mode_idx(640, 480, 16)) == -1) {
+               return -1;
+       }
+       video_mode_info(idx, &vi);
+
+       if(!(framebuf = set_video_mode(vi.mode))) {
                return -1;
        }
        get_color_bits(&vi.rbits, &vi.gbits, &vi.bbits);
index 8578c94..77c4bbe 100644 (file)
@@ -1,6 +1,6 @@
 /*
-pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+256boss - bootable launcher for 256b intros
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include "intr.h"
 #include "asmops.h"
 #include "timer.h"
+#include "panic.h"
 #include "config.h"
 
 /* frequency of the oscillator driving the 8254 timer */
@@ -57,11 +58,11 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 struct timer_event {
        int dt; /* remaining ticks delta from the previous event */
+       void (*func)(void);
        struct timer_event *next;
 };
 
-/* defined in intr_asm.S */
-void intr_entry_fast_timer(void);
+static void timer_handler(int inum);
 
 static struct timer_event *evlist;
 
@@ -83,14 +84,99 @@ void init_timer(void)
        outb((reload_count >> 8) & 0xff, PORT_DATA0);
 
        /* set the timer interrupt handler */
-       /*interrupt(IRQ_TO_INTR(0), timer_handler);*/
-       /* set low level fast timer interrupt routine directly in the IDT */
-       set_intr_entry(IRQ_TO_INTR(0), intr_entry_fast_timer);
+       interrupt(IRQ_TO_INTR(0), timer_handler);
+}
+
+void set_alarm(unsigned long msec, void (*func)(void))
+{
+       int ticks, tsum, iflag;
+       struct timer_event *ev, *node;
+
+       if((ticks = MSEC_TO_TICKS(msec)) <= 0) {
+               return;
+       }
+
+       if(!(ev = malloc(sizeof *ev))) {
+               panic("failed to allocate timer event");
+               return;
+       }
+       ev->func = func;
+
+       iflag = get_intr_flag();
+       disable_intr();
+
+       if(!evlist || ticks < evlist->dt) {
+               /* insert at the begining */
+               ev->next = evlist;
+               evlist = ev;
+
+               ev->dt = ticks;
+               if(ev->next) {
+                       ev->next->dt -= ticks;
+               }
+       } else {
+               tsum = evlist->dt;
+               node = evlist;
+
+               while(node->next && ticks > tsum + node->next->dt) {
+                       tsum += node->next->dt;
+                       node = node->next;
+               }
+
+               ev->next = node->next;
+               node->next = ev;
+
+               /* fix the relative times */
+               ev->dt = ticks - tsum;
+               if(ev->next) {
+                       ev->next->dt -= ev->dt;
+               }
+       }
+
+       set_intr_flag(iflag);
+}
+
+void cancel_alarm(void (*func)(void))
+{
+       int iflag;
+       struct timer_event *ev, *node;
+       struct timer_event dummy;
+
+       iflag = get_intr_flag();
+       disable_intr();
+
+       dummy.next = evlist;
+       node = &dummy;
+       while(node->next) {
+               ev = node->next;
+               if(ev->func == func) {
+                       /* found it */
+                       if(ev->next) {
+                               ev->next->dt += ev->dt;
+                       }
+                       node->next = ev->next;
+                       free(ev);
+                       break;
+               }
+               node = node->next;
+       }
+
+       set_intr_flag(iflag);
 }
 
-/*
 static void timer_handler(int inum)
 {
        nticks++;
+
+       if(evlist) {
+               evlist->dt--;
+
+               while(evlist && evlist->dt <= 0) {
+                       struct timer_event *ev = evlist;
+                       evlist = evlist->next;
+
+                       ev->func();
+                       free(ev);
+               }
+       }
 }
-*/
index b71e62f..3da5802 100644 (file)
@@ -1,6 +1,6 @@
 /*
-pcboot - bootable PC demo/game kernel
-Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+256boss - bootable launcher for 256byte intros
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -18,6 +18,8 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #ifndef _TIMER_H_
 #define _TIMER_H_
 
+#include "config.h"
+
 #define MSEC_TO_TICKS(ms)      ((ms) * TICK_FREQ_HZ / 1000)
 #define TICKS_TO_MSEC(tk)      ((tk) * 1000 / TICK_FREQ_HZ)
 
@@ -25,7 +27,16 @@ volatile unsigned long nticks;
 
 void init_timer(void);
 
+/*
 int sys_sleep(int sec);
 void sleep(unsigned long msec);
+*/
+
+/* schedule a function to be called 'msec' milliseconds into the future
+ * warning: this function will be called directly from the timer interrupt, and
+ * must be extremely quick.
+ */
+void set_alarm(unsigned long msec, void (*func)(void));
+void cancel_alarm(void (*func)(void));
 
 #endif /* _TIMER_H_ */
index 3f0f033..cbb940d 100644 (file)
--- a/src/vbe.c
+++ b/src/vbe.c
@@ -4,13 +4,12 @@
 #include "vbe.h"
 #include "asmops.h"
 #include "int86.h"
+#include "boot.h"
 
 #define SEG_ADDR(s)    ((uint32_t)(s) << 4)
 
 #define MODE_LFB       (1 << 14)
 
-extern unsigned char low_mem_buffer[];
-
 struct vbe_info *vbe_get_info(void)
 {
        struct vbe_info *info;
@@ -83,3 +82,51 @@ void print_mode_info(struct vbe_mode_info *mi)
        printf("blue bits: %d (mask: %x)\n", (int)mi->bmask_size, maskbits[mi->bmask_size] << mi->bpos);
        printf("framebuffer address: %x\n", (unsigned int)mi->fb_addr);
 }
+
+int vbe_get_edid(struct vbe_edid *edid)
+{
+       struct int86regs regs;
+
+       memset(&regs, 0, sizeof regs);
+       regs.es = (uint32_t)low_mem_buffer >> 4;
+       regs.eax = 0x4f15;
+       regs.ebx = 1;
+       int86(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       memcpy(edid, low_mem_buffer, sizeof *edid);
+       return 0;
+}
+
+int edid_preferred_resolution(struct vbe_edid *edid, int *xres, int *yres)
+{
+       if(memcmp(edid->magic, VBE_EDID_MAGIC, 8) != 0) {
+               return -1;
+       }
+
+       *xres = (int)edid->timing[0].hactive_lsb | ((int)(edid->timing[0].hact_hblank_msb & 0xf0) << 4);
+       *yres = (int)edid->timing[0].vactive_lsb | ((int)(edid->timing[0].vact_vblank_msb & 0xf0) << 4);
+       return 0;
+}
+
+void print_edid(struct vbe_edid *edid)
+{
+       char vendor[4];
+       int xres, yres;
+
+       if(memcmp(edid->magic, VBE_EDID_MAGIC, 8) != 0) {
+               printf("invalid EDID magic\n");
+               return;
+       }
+
+       vendor[0] = (edid->vendor >> 10) & 0x1f;
+       vendor[1] = (edid->vendor >> 5) & 0x1f;
+       vendor[2] = edid->vendor & 0x1f;
+       vendor[3] = 0;
+       printf("Manufacturer: %s\n", vendor);
+
+       edid_preferred_resolution(edid, &xres, &yres);
+       printf("Preferred resolution: %dx%d\n", xres, yres);
+}
index 15fb101..ed6b176 100644 (file)
--- a/src/vbe.h
+++ b/src/vbe.h
@@ -55,6 +55,55 @@ struct vbe_mode_info {
        uint8_t reserved4[206];
 } __attribute__((packed));
 
+struct vbe_edid_chroma {
+       unsigned char redgreen_xy_lsb;
+       unsigned char bluewhite_xy_lsb;
+       unsigned char redx_msb, redy_msb;
+       unsigned char greenx_msb, greeny_msb;
+       unsigned char bluex_msb, bluey_msb;
+       unsigned char whitex_msb, whitey_msb;
+} __attribute__((packed));
+
+struct vbe_edid_timing {
+       uint16_t dotclock;
+       unsigned char hactive_lsb, hblank_lsb, hact_hblank_msb;
+       unsigned char vactive_lsb, vblank_lsb, vact_vblank_msb;
+       unsigned char hporch_lsb, hsync_lsb;
+       unsigned char vporch_vsync_lsb;
+       unsigned char hvporch_hvsync_msb;
+       unsigned char hsize_lsb, vsize_lsb;     /* mm */
+       unsigned char hsize_vsize_msb;
+       unsigned char hborder, vborder;
+       unsigned char features;
+} __attribute__((packed));
+
+
+#define VBE_EDID_MAGIC "\0\xff\xff\xff\xff\xff\xff\0"
+
+struct vbe_edid {
+       char magic[8];
+       uint16_t vendor;
+       uint16_t product;
+       uint32_t serial;
+       unsigned char week, year;
+       unsigned char ver_major, ver_minor;
+
+       unsigned char vidinp;
+       unsigned char hsize, vsize;
+       unsigned char gamma;
+       unsigned char features;
+
+       struct vbe_edid_chroma chroma;
+
+       uint16_t modes_std;
+       unsigned char modes_ext;
+       uint16_t timing_std;
+
+       struct vbe_edid_timing timing[4];
+       unsigned char num_ext, csum;
+
+} __attribute__((packed));
+
 struct vbe_info *vbe_get_info(void);
 struct vbe_mode_info *vbe_get_mode_info(int mode);
 
@@ -62,4 +111,8 @@ int vbe_set_mode(int mode);
 
 void print_mode_info(struct vbe_mode_info *modei);
 
+int vbe_get_edid(struct vbe_edid *edid);
+int edid_preferred_resolution(struct vbe_edid *edid, int *xres, int *yres);
+void print_edid(struct vbe_edid *edid);
+
 #endif /* VBE_H_ */
index d926107..ba89bad 100644 (file)
@@ -103,10 +103,9 @@ void *set_video_mode(int mode)
        return (void*)mode_info->fb_addr;
 }
 
-int find_video_mode(int xsz, int ysz, int bpp)
+int find_video_mode_idx(int xsz, int ysz, int bpp)
 {
-       int i;
-       uint16_t best = 0;
+       int i, best = -1, best_bpp = 0;
        struct vbe_mode_info *inf;
 
        if(init_once() == -1) return -1;
@@ -116,12 +115,13 @@ int find_video_mode(int xsz, int ysz, int bpp)
                if(!inf || inf->xres != xsz || inf->yres != ysz) {
                        continue;
                }
-               if(SAME_BPP(inf->bpp, bpp)) {
-                       best = modes[i];
+               if((bpp <= 0 && inf->bpp > best_bpp) || SAME_BPP(inf->bpp, bpp)) {
+                       best = i;
+                       best_bpp = inf->bpp;
                }
        }
 
-       if(!best) {
+       if(best == -1) {
                printf("Requested video mode (%dx%d %dbpp) is unavailable\n", xsz, ysz, bpp);
                return -1;
        }
@@ -197,3 +197,15 @@ unsigned int color_mask(int nbits, int pos)
        static unsigned int maskbits[] = {0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
        return maskbits[nbits] << pos;
 }
+
+const char *get_video_vendor(void)
+{
+       if(init_once() == -1) return 0;
+       return (char*)VBEPTR(vbe_info->oem_vendor_name_ptr);
+}
+
+int get_video_mem_size(void)
+{
+       if(init_once() == -1) return 0;
+       return vbe_info->total_mem << 6;
+}
index bf42f53..f8d4940 100644 (file)
@@ -30,7 +30,7 @@ struct video_mode {
 void set_vga_mode(int mode);
 
 void *set_video_mode(int mode);
-int find_video_mode(int xsz, int ysz, int bpp);
+int find_video_mode_idx(int xsz, int ysz, int bpp);
 
 int video_mode_count(void);
 int video_mode_info(int n, struct video_mode *vid);
@@ -39,7 +39,11 @@ int get_color_bits(int *rbits, int *gbits, int *bbits);
 int get_color_mask(unsigned int *rmask, unsigned int *gmask, unsigned int *bmask);
 int get_color_shift(int *rshift, int *gshift, int *bshift);
 
+const char *get_video_vendor(void);
+int get_video_mem_size(void);
+
 /* defined in video_asm.s */
 void wait_vsync(void);
+void set_pal_entry(unsigned char idx, unsigned char r, unsigned char g, unsigned char b);
 
 #endif /* VIDEO_H_ */
index 1f7995c..ac91fd0 100644 (file)
@@ -25,3 +25,20 @@ wait_vsync:
        and $8, %al
        jz 0b
        ret
+
+       .global set_pal_entry
+set_pal_entry:
+       mov 4(%esp), %al
+       mov $0x3c8, %dx
+       out %al, %dx
+       inc %dx
+       mov 8(%esp), %al
+       shr $2, %al
+       out %al, %dx
+       mov 12(%esp), %al
+       shr $2, %al
+       out %al, %dx
+       mov 16(%esp), %al
+       shr $2, %al
+       out %al, %dx
+       ret