works and returns to DOS on dosbox
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 4 Oct 2023 00:45:33 +0000 (03:45 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 4 Oct 2023 00:45:33 +0000 (03:45 +0300)
.gitignore
Makefile
src/intr.c
src/intr.h
src/loader.asm
src/main.c
src/segm.c
src/segm.h
src/startup.asm
src/timer.c
src/timer.h

index 5300cea..cec07fe 100644 (file)
@@ -8,3 +8,4 @@ disasm
 dosbox.conf
 *.log
 tofloppy
+*.s
index accedf7..68742d5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -10,8 +10,9 @@ inc = -Isrc -Isrc/libc
 AS = nasm
 
 ASFLAGS = -Isrc/
-CFLAGS = -m32 -march=i386 $(warn) $(opt) $(dbg) -fno-pic -ffreestanding -nostdinc \
-                -ffast-math $(inc) $(def)
+CFLAGS = -m32 -march=i386 $(warn) $(opt) $(dbg) -fno-pic -ffreestanding \
+                -fno-stack-protector -mpreferred-stack-boundary=2 -nostdinc -ffast-math \
+                $(inc) $(def)
 LDFLAGS = -m elf_i386 -nostdlib -T com32.ld -Map test.map
 
 $(bin): $(obj)
@@ -23,7 +24,7 @@ $(bin): $(obj)
        $(AS) -o $@ -f elf $(ASFLAGS) $<
 
 %.s: %.c
-       $(CC) $(CFLAGS) -S $< -o $@
+       $(CC) $(CFLAGS) -masm=intel -g0 -fno-asynchronous-unwind-tables -S $< -o $@
 
 .PHONY: clean
 clean:
index 29ca70e..b1fd004 100644 (file)
@@ -90,11 +90,6 @@ void init_intr(void)
                interrupt(i, 0);
        }
 
-       /* mask all IRQs by default */
-       for(i=0; i<16; i++) {
-               mask_irq(i);
-       }
-
        /* by including intrtab.h here the series of INTR_ENTRY_* macros will be
         * expanded to a series of function prototypes for all interrupt entry
         * points and the corresponding calls to set_intr_entry to set up the IDT
@@ -111,10 +106,17 @@ void init_intr(void)
        /* initialize the programmable interrupt controller
         * setting up the maping of IRQs [0, 15] to interrupts [32, 47]
         */
-       init_pic();
+       prog_pic(IRQ_OFFSET);
        eoi_pending = 0;
 }
 
+void cleanup_intr(void)
+{
+       disable_intr();
+       /* reprogram the PIC to the default BIOS offset (8) */
+       prog_pic(8);
+}
+
 /* retrieve the current interrupt frame.
  * returns 0 when called during init.
  */
@@ -151,7 +153,7 @@ void dispatch_intr(struct intr_frame frm)
                        panic("unhandled exception %u, error code: %u, at cs:eip=%x:%x\n",
                                        frm.inum, frm.err, frm.cs, frm.eip);
                }
-               printf("unhandled interrupt %d\n", frm.inum);
+               /*printf("unhandled interrupt %d\n", frm.inum);*/
        }
 
        disable_intr();
@@ -160,11 +162,6 @@ 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 */
@@ -210,7 +207,7 @@ void set_intr_entry(int num, void (*handler)(void))
         */
        int dpl = (num == SYSCALL_INT) ? 3 : 0;
 
-       gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, dpl, type);
+       gate_desc(idt + num, selector(SEGM_CODE, 0), (uint32_t)handler, dpl, type);
 }
 
 void set_pic_mask(int pic, unsigned char mask)
index f33ec23..3cfbe8b 100644 (file)
@@ -61,6 +61,7 @@ typedef void (*intr_func_t)(int);
 
 
 void init_intr(void);
+void cleanup_intr(void);
 
 struct intr_frame *get_intr_frame(void);
 
index ea0de70..d31c6a8 100644 (file)
@@ -96,14 +96,7 @@ _start:
        mov esp, _main_start
 
        call 8:startup
-
-       PMPRINT 'X'
-       PMPRINT 'Y'
-       PMPRINT 'Z'
-       PMPRINT 'Z'
-       PMPRINT 'Y'
-       PMPRINT 13
-       PMPRINT 10
+       cli
 
        ; return to real mode
        jmp 28h:.rm
@@ -120,12 +113,15 @@ _start:
        mov es, ax
        mov ss, ax
 
+       ; restore real-mode IVT
+       lidt [rmidt]
+       sti
+
+       mov ax, 3
+       int 10h
 exit:  mov ax, 4c00h
        int 21h
 
-dbg_inpm db 'DBG: in pmode',10,0
-dbg_retrm db 'DBG: returning to real mode...',10,0
-
 str_errvm86 db 'Error: memory manager detected! Stop it and try again (e.g. emm386 off)',10,0
 str_enterpm db 'Entering 32bit protected mode ...',10,0
 
@@ -532,5 +528,10 @@ gdt:       ; 0: null segment
        dd 0000ffffh
        dd 00009a00h
 
+       ; pseudo IDTR descriptor for real-mode IVT at address 0
+       align 4
+       dw 0
+rmidt: dw 3ffh         ; IVT limit (1kb / 256 entries)
+       dd 0            ; IVT base 0
 
 ; vi:set ts=8 sts=8 sw=8 ft=nasm:
index 08f9510..c19dd5f 100644 (file)
@@ -7,13 +7,16 @@
 #include "psaux.h"
 #include "timer.h"
 
+extern uint16_t orig_seg;
+
 int main(void)
 {
+       init_segm();
        init_intr();
 
        con_init();
        kb_init();
-       init_psaux();
+       /*init_psaux();*/
 
        init_mem();
 
@@ -21,6 +24,9 @@ int main(void)
 
        enable_intr();
 
-       printf("hello from C\n");
+       printf("\nhello from C\n");
+
+       cleanup_intr(); /* also disables interrupts */
+       cleanup_timer();
        return 0;
 }
index c6baffd..0d8f4b4 100644 (file)
@@ -15,6 +15,7 @@ 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 <string.h>
 #include "segm.h"
 #include "desc.h"
@@ -44,30 +45,38 @@ enum {TYPE_DATA, TYPE_CODE};
 
 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
 static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
-static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl);
+/*static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl);*/
 
 /* these functions are implemented in segm-asm.S */
 void setup_selectors(uint16_t code, uint16_t data);
 void set_gdt(uint32_t addr, uint16_t limit);
 void set_task_reg(uint16_t tss_selector);
 
+static void dbg_print_gdt(void);
+static void print_desc(desc_t *desc);
 
 /* our global descriptor table */
 static desc_t gdt[NUM_SEGMENTS] __attribute__((aligned(8)));
-
+uint16_t orig_seg;
 
 void init_segm(void)
 {
+       asm volatile (
+               "mov %%fs, %0\n\t"
+               : "=a"(orig_seg));
+
        memset(gdt, 0, sizeof gdt);
-       segm_desc(gdt + SEGM_KCODE, 0, 0xffffffff, 0, TYPE_CODE);
-       segm_desc(gdt + SEGM_KDATA, 0, 0xffffffff, 0, TYPE_DATA);
-       segm_desc(gdt + SEGM_UCODE, 0, 0xffffffff, 3, TYPE_CODE);
-       segm_desc(gdt + SEGM_UDATA, 0, 0xffffffff, 3, TYPE_DATA);
-       segm_desc16(gdt + SEGM_CODE16, 0, 0xffff, 0, TYPE_CODE);
+       segm_desc(gdt + SEGM_CODE, 0, 0xffffffff, 0, TYPE_CODE);
+       segm_desc(gdt + SEGM_DATA, 0, 0xffffffff, 0, TYPE_DATA);
+       segm_desc(gdt + SEGM_XCODE, orig_seg << 4, 0xffffffff, 0, TYPE_CODE);
+       segm_desc(gdt + SEGM_XDATA, orig_seg << 4, 0xffffffff, 0, TYPE_DATA);
+       segm_desc16(gdt + SEGM_CODE16, orig_seg << 4, 0xffff, 0, TYPE_CODE);
 
        set_gdt((uint32_t)gdt, sizeof gdt - 1);
 
-       setup_selectors(selector(SEGM_KCODE, 0), selector(SEGM_KDATA, 0));
+       setup_selectors(selector(SEGM_CODE, 0), selector(SEGM_DATA, 0));
+
+       dbg_print_gdt();
 }
 
 /* constructs a GDT selector based on index and priviledge level */
@@ -76,11 +85,13 @@ uint16_t selector(int idx, int rpl)
        return (idx << 3) | (rpl & 3);
 }
 
+/*
 void set_tss(uint32_t addr)
 {
        task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
        set_task_reg(selector(SEGM_TASK, 0));
 }
+*/
 
 static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type)
 {
@@ -116,6 +127,7 @@ static void segm_desc16(desc_t *desc, uint32_t base, uint32_t limit, int dpl, in
        desc->d[3] = 0;
 }
 
+#if 0
 static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
 {
        desc->d[0] = limit & 0xffff;
@@ -125,7 +137,8 @@ static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
                TSS_TYPE_BITS; /* XXX busy ? */
        desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN;
 }
-/*
+#endif
+
 static void dbg_print_gdt(void)
 {
        int i;
@@ -133,7 +146,8 @@ static void dbg_print_gdt(void)
        printf("Global Descriptor Table\n");
        printf("-----------------------\n");
 
-       for(i=0; i<6; i++) {
+       for(i=0; i<NUM_SEGMENTS; i++) {
+               printf("%d: ", i);
                print_desc(gdt + i);
        }
 }
@@ -141,19 +155,19 @@ static void dbg_print_gdt(void)
 static void print_desc(desc_t *desc)
 {
        uint32_t base, limit;
-       int dpl, g, db, l, avl, p, s, type;
-       char *type_str;
+       int dpl, g;
+
+       if((desc->d[0] | desc->d[1] | desc->d[2] | desc->d[3]) == 0) {
+               printf("null\n");
+       }
 
        base = (uint32_t)desc->d[1] | ((uint32_t)(desc->d[2] & 0xff) << 16) | ((uint32_t)(desc->d[3] >> 8) << 24);
        limit = (uint32_t)desc->d[0] | ((uint32_t)(desc->d[3] & 0xf) << 16);
        dpl = (desc->d[2] >> 13) & 3;
-       type = (desc->d[2] >> 8) & 0xf;
-       g = (desc->d[3] >> 23) & 1;
-       db = (desc->d[3] >> 22) & 1;
-       l = (desc->d[3] >> 21) & 1;
-       avl = (desc->d[3] >> 20) & 1;
-
-       p = (desc->d[2] >> 15) & 1;
-       s = (desc->d[2] >> 12) & 1;
+       g = (desc->d[3] >> 7) & 1;
+
+       if(g) limit = ((limit + 1) << 12) - 1;
+
+       printf("base:%x lim:%x dpl:%d type:%s %dbit\n", base, limit, dpl,
+                       desc->d[2] & BIT_CODE ? "code" : "data", desc->d[3] & BIT_BIG ? 32 : 16);
 }
-*/
index bf76c72..f3b083c 100644 (file)
@@ -21,11 +21,11 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <inttypes.h>
 
 enum {
-       SEGM_KCODE = 1,
-       SEGM_KDATA = 2,
-       SEGM_UCODE,
-       SEGM_UDATA,
-       SEGM_TASK,
+       SEGM_NULL,
+       SEGM_CODE,
+       SEGM_DATA,
+       SEGM_XCODE,             /* transition 32bit code with base matching the RM segment */
+       SEGM_XDATA,             /* same for data */
        SEGM_CODE16,
 
        NUM_SEGMENTS
index 8c7dfbb..bc033e2 100644 (file)
@@ -21,6 +21,7 @@ startup:
        rep stosd
 .nobss:
 
+       mov ebp, 12345678h
        call main
        cli     ; XXX
 
@@ -29,7 +30,7 @@ startup:
        test al, 1
        jz .waitkey
        in al, 60h
-       ret
+       retf
 
 ;      global putchar
 ;putchar:
index f4a812b..c050b84 100644 (file)
@@ -89,6 +89,14 @@ void init_timer(void)
        unmask_irq(0);
 }
 
+void cleanup_timer(void)
+{
+       /* return the timer to the original rate */
+       outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE);
+       outp(PORT_DATA0, 0);
+       outp(PORT_DATA0, 0);
+}
+
 void set_alarm(unsigned long msec, void (*func)(void))
 {
        int ticks, tsum, iflag;
index c41c0f5..c057801 100644 (file)
@@ -26,6 +26,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 extern volatile unsigned long nticks;
 
 void init_timer(void);
+void cleanup_timer(void);
 
 /*
 int sys_sleep(int sec);