Compare commits
8 Commits
53b4cff56a
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
b50883b3ed
|
|||
|
1d16c23fc5
|
|||
|
29ad4c2835
|
|||
|
d8fad1765e
|
|||
|
d73ace71fb
|
|||
|
9c242187ea
|
|||
|
75ddd75ab9
|
|||
|
47b6a1eb82
|
@@ -3,7 +3,7 @@ CFLAGS = -Wall -Wextra -g -std=c11
|
|||||||
COMMON_SRCS = forth_core.c forth_dict.c forth_words.c forth_interp.c main.c
|
COMMON_SRCS = forth_core.c forth_dict.c forth_words.c forth_interp.c main.c
|
||||||
|
|
||||||
LINUX_SRCS = $(COMMON_SRCS) platform_linux.c
|
LINUX_SRCS = $(COMMON_SRCS) platform_linux.c
|
||||||
KERNEL_SRCS = $(COMMON_SRCS) platform_kernel.c kernel_entry.S
|
KERNEL_SRCS = $(COMMON_SRCS) platform_kernel.c kernel_entry.S font8x8.c
|
||||||
KERNEL_LD = kernel.ld
|
KERNEL_LD = kernel.ld
|
||||||
|
|
||||||
TARGET = forth
|
TARGET = forth
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const uint8_t font8x8[96][8] = {
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* 32 ' ' */
|
||||||
|
{0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x00}, /* 33 '!' */
|
||||||
|
{0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00}, /* 34 '"' */
|
||||||
|
{0x66,0x66,0xFF,0x66,0xFF,0x66,0x66,0x00}, /* 35 '#' */
|
||||||
|
{0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, /* 36 '$' */
|
||||||
|
{0x62,0x66,0x0C,0x18,0x30,0x66,0x46,0x00}, /* 37 '%' */
|
||||||
|
{0x3C,0x66,0x3C,0x38,0x67,0x66,0x3F,0x00}, /* 38 '&' */
|
||||||
|
{0x06,0x0C,0x18,0x00,0x00,0x00,0x00,0x00}, /* 39 ''' */
|
||||||
|
{0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, /* 40 '(' */
|
||||||
|
{0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, /* 41 ')' */
|
||||||
|
{0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, /* 42 '*' */
|
||||||
|
{0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00}, /* 43 '+' */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, /* 44 ',' */
|
||||||
|
{0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, /* 45 '-' */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, /* 46 '.' */
|
||||||
|
{0x00,0x03,0x06,0x0C,0x18,0x30,0x60,0x00}, /* 47 '/' */
|
||||||
|
{0x3C,0x66,0x6E,0x76,0x66,0x66,0x3C,0x00}, /* 48 '0' */
|
||||||
|
{0x18,0x18,0x38,0x18,0x18,0x18,0x7E,0x00}, /* 49 '1' */
|
||||||
|
{0x3C,0x66,0x06,0x0C,0x30,0x60,0x7E,0x00}, /* 50 '2' */
|
||||||
|
{0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, /* 51 '3' */
|
||||||
|
{0x06,0x0E,0x1E,0x66,0x7F,0x06,0x06,0x00}, /* 52 '4' */
|
||||||
|
{0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, /* 53 '5' */
|
||||||
|
{0x3C,0x60,0x60,0x7C,0x66,0x66,0x3C,0x00}, /* 54 '6' */
|
||||||
|
{0x7E,0x06,0x0C,0x18,0x30,0x30,0x30,0x00}, /* 55 '7' */
|
||||||
|
{0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, /* 56 '8' */
|
||||||
|
{0x3C,0x66,0x66,0x3E,0x06,0x06,0x3C,0x00}, /* 57 '9' */
|
||||||
|
{0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00}, /* 58 ':' */
|
||||||
|
{0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30}, /* 59 ';' */
|
||||||
|
{0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, /* 60 '<' */
|
||||||
|
{0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00}, /* 61 '=' */
|
||||||
|
{0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, /* 62 '>' */
|
||||||
|
{0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, /* 63 '?' */
|
||||||
|
{0x3C,0x66,0x6E,0x6E,0x60,0x62,0x3C,0x00}, /* 64 '@' */
|
||||||
|
{0x18,0x3C,0x66,0x7E,0x66,0x66,0x66,0x00}, /* 65 'A' */
|
||||||
|
{0x7C,0x66,0x66,0x7C,0x66,0x66,0x7C,0x00}, /* 66 'B' */
|
||||||
|
{0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x00}, /* 67 'C' */
|
||||||
|
{0x78,0x6C,0x66,0x66,0x66,0x6C,0x78,0x00}, /* 68 'D' */
|
||||||
|
{0x7E,0x60,0x60,0x78,0x60,0x60,0x7E,0x00}, /* 69 'E' */
|
||||||
|
{0x7E,0x60,0x60,0x78,0x60,0x60,0x60,0x00}, /* 70 'F' */
|
||||||
|
{0x3C,0x66,0x60,0x6E,0x66,0x66,0x3C,0x00}, /* 71 'G' */
|
||||||
|
{0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, /* 72 'H' */
|
||||||
|
{0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, /* 73 'I' */
|
||||||
|
{0x1E,0x0C,0x0C,0x0C,0x0C,0x6C,0x38,0x00}, /* 74 'J' */
|
||||||
|
{0x66,0x6C,0x78,0x70,0x78,0x6C,0x66,0x00}, /* 75 'K' */
|
||||||
|
{0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00}, /* 76 'L' */
|
||||||
|
{0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x00}, /* 77 'M' */
|
||||||
|
{0x66,0x76,0x7E,0x7E,0x6E,0x66,0x66,0x00}, /* 78 'N' */
|
||||||
|
{0x3C,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* 79 'O' */
|
||||||
|
{0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00}, /* 80 'P' */
|
||||||
|
{0x3C,0x66,0x66,0x66,0x66,0x3C,0x0E,0x00}, /* 81 'Q' */
|
||||||
|
{0x7C,0x66,0x66,0x7C,0x78,0x6C,0x66,0x00}, /* 82 'R' */
|
||||||
|
{0x3C,0x66,0x60,0x3C,0x06,0x66,0x3C,0x00}, /* 83 'S' */
|
||||||
|
{0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* 84 'T' */
|
||||||
|
{0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00}, /* 85 'U' */
|
||||||
|
{0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, /* 86 'V' */
|
||||||
|
{0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, /* 87 'W' */
|
||||||
|
{0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00}, /* 88 'X' */
|
||||||
|
{0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00}, /* 89 'Y' */
|
||||||
|
{0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00}, /* 90 'Z' */
|
||||||
|
{0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, /* 91 '[' */
|
||||||
|
{0x00,0x60,0x30,0x18,0x0C,0x06,0x03,0x00}, /* 92 '\' */
|
||||||
|
{0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, /* 93 ']' */
|
||||||
|
{0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00}, /* 94 '^' */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00}, /* 95 '_' */
|
||||||
|
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, /* 96 '`' */
|
||||||
|
{0x00,0x00,0x3C,0x06,0x3E,0x66,0x3E,0x00}, /* 97 'a' */
|
||||||
|
{0x00,0x60,0x60,0x7C,0x66,0x66,0x7C,0x00}, /* 98 'b' */
|
||||||
|
{0x00,0x00,0x3C,0x60,0x60,0x60,0x3C,0x00}, /* 99 'c' */
|
||||||
|
{0x00,0x06,0x06,0x3E,0x66,0x66,0x3E,0x00}, /* 100 'd' */
|
||||||
|
{0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, /* 101 'e' */
|
||||||
|
{0x00,0x0E,0x18,0x3E,0x18,0x18,0x18,0x00}, /* 102 'f' */
|
||||||
|
{0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x7C}, /* 103 'g' */
|
||||||
|
{0x00,0x60,0x60,0x7C,0x66,0x66,0x66,0x00}, /* 104 'h' */
|
||||||
|
{0x00,0x18,0x00,0x38,0x18,0x18,0x3C,0x00}, /* 105 'i' */
|
||||||
|
{0x00,0x06,0x00,0x06,0x06,0x06,0x06,0x3C}, /* 106 'j' */
|
||||||
|
{0x00,0x60,0x60,0x6C,0x78,0x6C,0x66,0x00}, /* 107 'k' */
|
||||||
|
{0x00,0x38,0x18,0x18,0x18,0x18,0x3C,0x00}, /* 108 'l' */
|
||||||
|
{0x00,0x00,0x66,0x7F,0x6B,0x63,0x63,0x00}, /* 109 'm' */
|
||||||
|
{0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, /* 110 'n' */
|
||||||
|
{0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, /* 111 'o' */
|
||||||
|
{0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60}, /* 112 'p' */
|
||||||
|
{0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x06}, /* 113 'q' */
|
||||||
|
{0x00,0x00,0x7C,0x66,0x60,0x60,0x60,0x00}, /* 114 'r' */
|
||||||
|
{0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, /* 115 's' */
|
||||||
|
{0x00,0x18,0x18,0x7E,0x18,0x18,0x0C,0x00}, /* 116 't' */
|
||||||
|
{0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x00}, /* 117 'u' */
|
||||||
|
{0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, /* 118 'v' */
|
||||||
|
{0x00,0x00,0x63,0x6B,0x7F,0x3E,0x36,0x00}, /* 119 'w' */
|
||||||
|
{0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x00}, /* 120 'x' */
|
||||||
|
{0x00,0x00,0x66,0x66,0x66,0x3E,0x0C,0x78}, /* 121 'y' */
|
||||||
|
{0x00,0x00,0x7E,0x0C,0x18,0x30,0x7E,0x00}, /* 122 'z' */
|
||||||
|
{0x0C,0x18,0x18,0x30,0x18,0x18,0x0C,0x00}, /* 123 '{' */
|
||||||
|
{0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, /* 124 '|' */
|
||||||
|
{0x30,0x18,0x18,0x0C,0x18,0x18,0x30,0x00}, /* 125 '}' */
|
||||||
|
{0x00,0x00,0x66,0x3C,0x00,0x00,0x00,0x00}, /* 126 '~' */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* 127 DEL */
|
||||||
|
};
|
||||||
@@ -204,6 +204,14 @@ void do_dot_quote(Word* w);
|
|||||||
void do_dot_quote_inner(Word* w);
|
void do_dot_quote_inner(Word* w);
|
||||||
void do_words(Word* w);
|
void do_words(Word* w);
|
||||||
|
|
||||||
|
// Framebuffer
|
||||||
|
void do_fb_addr(Word* w);
|
||||||
|
void do_fb_width(Word* w);
|
||||||
|
void do_fb_height(Word* w);
|
||||||
|
void do_fb_pitch(Word* w);
|
||||||
|
void do_fb_bpp(Word* w);
|
||||||
|
void do_fb_plot(Word* w);
|
||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
void do_fetch(Word* w);
|
void do_fetch(Word* w);
|
||||||
void do_store(Word* w);
|
void do_store(Word* w);
|
||||||
|
|||||||
+82
-6
@@ -8,6 +8,19 @@ multiboot_header:
|
|||||||
.long multiboot_header_end - multiboot_header
|
.long multiboot_header_end - multiboot_header
|
||||||
.long -(0xe85250d6 + 0 + (multiboot_header_end - multiboot_header))
|
.long -(0xe85250d6 + 0 + (multiboot_header_end - multiboot_header))
|
||||||
|
|
||||||
|
/* Framebuffer tag: type=5, size=20, width=height=0 (any), depth=32.
|
||||||
|
* Layout per multiboot2 spec:
|
||||||
|
* u16 type, u16 flags, u32 size, u32 width, u32 height, u32 depth
|
||||||
|
* Padded to 8-byte alignment. */
|
||||||
|
.align 8
|
||||||
|
.word 5
|
||||||
|
.word 0
|
||||||
|
.long 20
|
||||||
|
.long 0
|
||||||
|
.long 0
|
||||||
|
.long 32
|
||||||
|
.long 0 /* padding to 8-byte alignment */
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.word 0
|
.word 0
|
||||||
.word 0
|
.word 0
|
||||||
@@ -21,19 +34,24 @@ pml4:
|
|||||||
pdpt:
|
pdpt:
|
||||||
.space 4096
|
.space 4096
|
||||||
pd:
|
pd:
|
||||||
.space 4096
|
.space 4096 * 4
|
||||||
|
|
||||||
.align 16
|
.align 16
|
||||||
stack_bottom:
|
stack_bottom:
|
||||||
.space 16384
|
.space 16384
|
||||||
stack_top:
|
stack_top:
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
mboot_info_ptr:
|
||||||
|
.space 8
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
.code32
|
.code32
|
||||||
.global _start
|
.global _start
|
||||||
.type _start, @function
|
.type _start, @function
|
||||||
_start:
|
_start:
|
||||||
movl $stack_top, %esp
|
movl $stack_top, %esp
|
||||||
|
movl %ebx, mboot_info_ptr
|
||||||
|
|
||||||
cld
|
cld
|
||||||
movl $__bss_start, %edi
|
movl $__bss_start, %edi
|
||||||
@@ -46,13 +64,22 @@ _start:
|
|||||||
orl $0x03, %eax
|
orl $0x03, %eax
|
||||||
movl %eax, pml4
|
movl %eax, pml4
|
||||||
|
|
||||||
|
/* Populate 4 PDPT entries, each pointing to one of 4 PDs.
|
||||||
|
* This identity-maps the first 4 GiB using 2 MiB pages,
|
||||||
|
* which covers typical framebuffer/MMIO regions. */
|
||||||
movl $pd, %eax
|
movl $pd, %eax
|
||||||
orl $0x03, %eax
|
orl $0x03, %eax
|
||||||
movl %eax, pdpt
|
movl %eax, pdpt + 0
|
||||||
|
addl $4096, %eax
|
||||||
|
movl %eax, pdpt + 8
|
||||||
|
addl $4096, %eax
|
||||||
|
movl %eax, pdpt + 16
|
||||||
|
addl $4096, %eax
|
||||||
|
movl %eax, pdpt + 24
|
||||||
|
|
||||||
movl $0x00000083, %eax
|
movl $0x00000083, %eax
|
||||||
movl $pd, %edi
|
movl $pd, %edi
|
||||||
movl $512, %ecx
|
movl $2048, %ecx
|
||||||
1:
|
1:
|
||||||
movl %eax, (%edi)
|
movl %eax, (%edi)
|
||||||
addl $0x200000, %eax
|
addl $0x200000, %eax
|
||||||
@@ -80,15 +107,62 @@ _start:
|
|||||||
|
|
||||||
.code64
|
.code64
|
||||||
long_mode_start:
|
long_mode_start:
|
||||||
|
/* Load data segment registers with the data descriptor (0x10).
|
||||||
|
* In long mode most of these are ignored for access checks, but
|
||||||
|
* %ss must be a valid (or null) selector so that iretq from an
|
||||||
|
* interrupt can safely reload it. */
|
||||||
|
movw $0x10, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
movw %ax, %ss
|
||||||
|
|
||||||
movabsq $stack_top, %rax
|
movabsq $stack_top, %rax
|
||||||
movq %rax, %rsp
|
movq %rax, %rsp
|
||||||
|
/* Ensure 16-byte alignment for the System V AMD64 ABI. */
|
||||||
|
andq $-16, %rsp
|
||||||
|
|
||||||
|
movq mboot_info_ptr, %rdi
|
||||||
call kernel_main
|
call kernel_main
|
||||||
cli
|
cli
|
||||||
1:
|
1:
|
||||||
hlt
|
hlt
|
||||||
jmp 1b
|
jmp 1b
|
||||||
|
|
||||||
|
.code64
|
||||||
|
.global isr_keyboard
|
||||||
|
.align 16
|
||||||
|
isr_keyboard:
|
||||||
|
/* Save all caller-saved registers used by the SysV AMD64 ABI. */
|
||||||
|
pushq %rax
|
||||||
|
pushq %rcx
|
||||||
|
pushq %rdx
|
||||||
|
pushq %rsi
|
||||||
|
pushq %rdi
|
||||||
|
pushq %r8
|
||||||
|
pushq %r9
|
||||||
|
pushq %r10
|
||||||
|
pushq %r11
|
||||||
|
/* On interrupt entry the CPU pushed 5 qwords (40 bytes), and we
|
||||||
|
* pushed 9 more (72 bytes) = 112 bytes total. That leaves %rsp
|
||||||
|
* misaligned by 8 relative to a 16-byte boundary after the
|
||||||
|
* upcoming `call`. Push one dummy qword to realign. */
|
||||||
|
subq $8, %rsp
|
||||||
|
cld
|
||||||
|
call keyboard_handler
|
||||||
|
addq $8, %rsp
|
||||||
|
popq %r11
|
||||||
|
popq %r10
|
||||||
|
popq %r9
|
||||||
|
popq %r8
|
||||||
|
popq %rdi
|
||||||
|
popq %rsi
|
||||||
|
popq %rdx
|
||||||
|
popq %rcx
|
||||||
|
popq %rax
|
||||||
|
iretq
|
||||||
|
|
||||||
.section .note.Xen, "a", @note
|
.section .note.Xen, "a", @note
|
||||||
.align 4
|
.align 4
|
||||||
.long 4
|
.long 4
|
||||||
@@ -101,8 +175,10 @@ long_mode_start:
|
|||||||
.section .rodata
|
.section .rodata
|
||||||
.align 8
|
.align 8
|
||||||
gdt64:
|
gdt64:
|
||||||
.quad 0x0000000000000000
|
.quad 0x0000000000000000 /* 0x00: null descriptor */
|
||||||
.quad 0x00209A0000000000
|
.quad 0x00209A0000000000 /* 0x08: 64-bit code, DPL=0 */
|
||||||
|
.quad 0x0000920000000000 /* 0x10: data, writable, present */
|
||||||
|
gdt64_end:
|
||||||
gdt64_pointer:
|
gdt64_pointer:
|
||||||
.word gdt64_pointer - gdt64 - 1
|
.word gdt64_end - gdt64 - 1
|
||||||
.quad gdt64
|
.quad gdt64
|
||||||
|
|||||||
@@ -65,6 +65,14 @@ void forth_run(void) {
|
|||||||
add_primitive(".\"", do_dot_quote, F_IMMEDIATE); // immediate
|
add_primitive(".\"", do_dot_quote, F_IMMEDIATE); // immediate
|
||||||
add_primitive("words", do_words, 0);
|
add_primitive("words", do_words, 0);
|
||||||
|
|
||||||
|
// Framebuffer
|
||||||
|
add_primitive("fb-addr", do_fb_addr, 0);
|
||||||
|
add_primitive("fb-width", do_fb_width, 0);
|
||||||
|
add_primitive("fb-height", do_fb_height, 0);
|
||||||
|
add_primitive("fb-pitch", do_fb_pitch, 0);
|
||||||
|
add_primitive("fb-bpp", do_fb_bpp, 0);
|
||||||
|
add_primitive("fb-plot", do_fb_plot, 0);
|
||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
add_primitive("@", do_fetch, 0);
|
add_primitive("@", do_fetch, 0);
|
||||||
add_primitive("!", do_store, 0);
|
add_primitive("!", do_store, 0);
|
||||||
|
|||||||
+275
-21
@@ -2,27 +2,102 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
// VGA text-mode buffer
|
extern const uint8_t font8x8[96][8];
|
||||||
static uint16_t* vga_buffer = (uint16_t*)0xB8000;
|
|
||||||
static int vga_row = 0;
|
|
||||||
static int vga_col = 0;
|
|
||||||
|
|
||||||
static void vga_putchar(char c) {
|
struct mboot_tag {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mboot_tag_framebuffer {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t size;
|
||||||
|
uint64_t framebuffer_addr;
|
||||||
|
uint32_t framebuffer_pitch;
|
||||||
|
uint32_t framebuffer_width;
|
||||||
|
uint32_t framebuffer_height;
|
||||||
|
uint8_t framebuffer_bpp;
|
||||||
|
uint8_t framebuffer_type;
|
||||||
|
uint16_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint64_t fb_addr = 0;
|
||||||
|
static uint32_t fb_pitch = 0;
|
||||||
|
static uint32_t fb_width = 0;
|
||||||
|
static uint32_t fb_height = 0;
|
||||||
|
static uint8_t fb_bpp = 0;
|
||||||
|
static int fb_cols = 0;
|
||||||
|
static int fb_rows = 0;
|
||||||
|
static int fb_col = 0;
|
||||||
|
static int fb_row = 0;
|
||||||
|
|
||||||
|
static void fb_draw_pixel(int x, int y, uint32_t color) {
|
||||||
|
if (x < 0 || y < 0 || (uint32_t)x >= fb_width || (uint32_t)y >= fb_height) return;
|
||||||
|
if (!fb_addr) return;
|
||||||
|
if (fb_bpp == 32) {
|
||||||
|
uint32_t* p = (uint32_t*)(fb_addr + y * fb_pitch + x * 4);
|
||||||
|
*p = color;
|
||||||
|
} else if (fb_bpp == 24) {
|
||||||
|
uint8_t* p = (uint8_t*)(fb_addr + y * fb_pitch + x * 3);
|
||||||
|
p[0] = color & 0xFF;
|
||||||
|
p[1] = (color >> 8) & 0xFF;
|
||||||
|
p[2] = (color >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fb_scroll(void) {
|
||||||
|
int line_height = 8;
|
||||||
|
uint32_t bytes_per_pixel = (fb_bpp + 7) / 8;
|
||||||
|
uint32_t copy_bytes = fb_width * bytes_per_pixel;
|
||||||
|
for (uint32_t y = 0; y < fb_height - line_height; y++) {
|
||||||
|
uint8_t* dst = (uint8_t*)(fb_addr + y * fb_pitch);
|
||||||
|
uint8_t* src = (uint8_t*)(fb_addr + (y + line_height) * fb_pitch);
|
||||||
|
for (uint32_t i = 0; i < copy_bytes; i++) {
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (uint32_t y = fb_height - line_height; y < fb_height; y++) {
|
||||||
|
uint8_t* row = (uint8_t*)(fb_addr + y * fb_pitch);
|
||||||
|
for (uint32_t i = 0; i < copy_bytes; i++) {
|
||||||
|
row[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fb_draw_char(char c) {
|
||||||
|
if (!fb_addr || fb_cols == 0) return;
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
vga_col = 0;
|
fb_col = 0;
|
||||||
vga_row++;
|
fb_row++;
|
||||||
|
} else if (c == '\r') {
|
||||||
|
fb_col = 0;
|
||||||
|
} else if (c == '\b') {
|
||||||
|
if (fb_col > 0) fb_col--;
|
||||||
} else {
|
} else {
|
||||||
int idx = vga_row * 80 + vga_col;
|
unsigned char ch = (unsigned char)c;
|
||||||
vga_buffer[idx] = (uint16_t)((0x0F << 8) | (unsigned char)c);
|
if (ch < 32 || ch > 126) ch = '?';
|
||||||
vga_col++;
|
const uint8_t* glyph = font8x8[ch - 32];
|
||||||
if (vga_col >= 80) {
|
int start_x = fb_col * 8;
|
||||||
vga_col = 0;
|
int start_y = fb_row * 8;
|
||||||
vga_row++;
|
for (int dy = 0; dy < 8; dy++) {
|
||||||
|
uint8_t row = glyph[dy];
|
||||||
|
for (int dx = 0; dx < 8; dx++) {
|
||||||
|
if (row & (0x80 >> dx)) {
|
||||||
|
fb_draw_pixel(start_x + dx, start_y + dy, 0xFFFFFF);
|
||||||
|
} else {
|
||||||
|
fb_draw_pixel(start_x + dx, start_y + dy, 0x000000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vga_row >= 25) {
|
}
|
||||||
vga_row = 0;
|
fb_col++;
|
||||||
vga_col = 0;
|
}
|
||||||
|
if (fb_col >= fb_cols) {
|
||||||
|
fb_col = 0;
|
||||||
|
fb_row++;
|
||||||
|
}
|
||||||
|
if (fb_row >= fb_rows) {
|
||||||
|
fb_scroll();
|
||||||
|
fb_row = fb_rows - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +111,10 @@ static inline uint8_t inb(uint16_t port) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void io_wait(void) {
|
||||||
|
__asm__ volatile ("outb %0, %1" : : "a"((uint8_t)0), "Nd"((uint16_t)0x80));
|
||||||
|
}
|
||||||
|
|
||||||
static void serial_init(void) {
|
static void serial_init(void) {
|
||||||
outb(0x3F8 + 1, 0x00);
|
outb(0x3F8 + 1, 0x00);
|
||||||
outb(0x3F8 + 3, 0x80);
|
outb(0x3F8 + 3, 0x80);
|
||||||
@@ -46,17 +125,117 @@ static void serial_init(void) {
|
|||||||
outb(0x3F8 + 4, 0x0B);
|
outb(0x3F8 + 4, 0x0B);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Each 64-bit IDT entry is 16 bytes = two uint64_t words.
|
||||||
|
*
|
||||||
|
* Word 0 layout:
|
||||||
|
* [15: 0] offset[15:0]
|
||||||
|
* [31:16] segment selector
|
||||||
|
* [34:32] IST (0 = no IST)
|
||||||
|
* [39:35] reserved (0)
|
||||||
|
* [47:40] type+attr (0x8E = present, DPL=0, 64-bit interrupt gate)
|
||||||
|
* [63:48] offset[31:16]
|
||||||
|
*
|
||||||
|
* Word 1 layout:
|
||||||
|
* [31: 0] offset[63:32]
|
||||||
|
* [63:32] reserved (0)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t low;
|
||||||
|
uint64_t high;
|
||||||
|
} __attribute__((packed)) IdtEntry;
|
||||||
|
|
||||||
|
static IdtEntry idt_entries[256];
|
||||||
|
|
||||||
|
static void idt_set_gate(int vector, uint64_t offset, uint16_t selector, uint8_t type_attr) {
|
||||||
|
uint64_t low =
|
||||||
|
(offset & 0x000000000000FFFFULL) | /* offset[15:0] */
|
||||||
|
((uint64_t)selector << 16) | /* selector */
|
||||||
|
/* bits 34:32 = IST=0, bits 39:35 = 0 */
|
||||||
|
((uint64_t)type_attr << 40) | /* type+attr */
|
||||||
|
((offset & 0x00000000FFFF0000ULL) << 32); /* offset[31:16] */
|
||||||
|
uint64_t high = offset >> 32; /* offset[63:32] */
|
||||||
|
idt_entries[vector].low = low;
|
||||||
|
idt_entries[vector].high = high;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
uint16_t limit;
|
||||||
|
uint64_t base;
|
||||||
|
} __attribute__((packed)) idt_ptr;
|
||||||
|
|
||||||
|
static void pic_remap(void) {
|
||||||
|
uint8_t a1 = inb(0x21);
|
||||||
|
uint8_t a2 = inb(0xA1);
|
||||||
|
|
||||||
|
outb(0x20, 0x11);
|
||||||
|
io_wait();
|
||||||
|
outb(0xA0, 0x11);
|
||||||
|
io_wait();
|
||||||
|
outb(0x21, 0x20);
|
||||||
|
io_wait();
|
||||||
|
outb(0xA1, 0x28);
|
||||||
|
io_wait();
|
||||||
|
outb(0x21, 0x04);
|
||||||
|
io_wait();
|
||||||
|
outb(0xA1, 0x02);
|
||||||
|
io_wait();
|
||||||
|
outb(0x21, 0x01);
|
||||||
|
io_wait();
|
||||||
|
outb(0xA1, 0x01);
|
||||||
|
io_wait();
|
||||||
|
|
||||||
|
outb(0x21, a1);
|
||||||
|
outb(0xA1, a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pic_unmask_keyboard(void) {
|
||||||
|
uint8_t mask = inb(0x21);
|
||||||
|
mask &= ~(1 << 1);
|
||||||
|
outb(0x21, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KEYBUF_SIZE 256
|
||||||
|
static volatile char keybuf[KEYBUF_SIZE];
|
||||||
|
static volatile int keybuf_head = 0;
|
||||||
|
static volatile int keybuf_tail = 0;
|
||||||
|
|
||||||
|
static const char scancode_map[] = {
|
||||||
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||||
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||||
|
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
|
||||||
|
0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,
|
||||||
|
'*', 0, ' ', 0
|
||||||
|
};
|
||||||
|
|
||||||
|
void keyboard_handler(void) {
|
||||||
|
uint8_t scancode = inb(0x60);
|
||||||
|
if (scancode < sizeof(scancode_map)) {
|
||||||
|
char c = scancode_map[scancode];
|
||||||
|
if (c) {
|
||||||
|
int next = (keybuf_tail + 1) % KEYBUF_SIZE;
|
||||||
|
if (next != keybuf_head) {
|
||||||
|
keybuf[keybuf_tail] = c;
|
||||||
|
keybuf_tail = next;
|
||||||
|
forth_putchar(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
void forth_putchar(char c) {
|
void forth_putchar(char c) {
|
||||||
vga_putchar(c);
|
fb_draw_char(c);
|
||||||
while ((inb(0x3F8 + 5) & 0x20) == 0) { }
|
while ((inb(0x3F8 + 5) & 0x20) == 0) { }
|
||||||
outb(0x3F8, (uint8_t)c);
|
outb(0x3F8, (uint8_t)c);
|
||||||
}
|
}
|
||||||
|
|
||||||
int forth_getchar(void) {
|
int forth_getchar(void) {
|
||||||
if ((inb(0x3F8 + 5) & 1) == 0) {
|
while (keybuf_head == keybuf_tail) {
|
||||||
return FORTH_EOF;
|
__asm__ volatile ("pause");
|
||||||
}
|
}
|
||||||
return inb(0x3F8);
|
char c = keybuf[keybuf_head];
|
||||||
|
keybuf_head = (keybuf_head + 1) % KEYBUF_SIZE;
|
||||||
|
return (int)c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void forth_fflush(void) {
|
void forth_fflush(void) {
|
||||||
@@ -135,9 +314,84 @@ void forth_printf(const char* fmt, ...) {
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kernel_main(void) {
|
void kernel_main(uint64_t mboot_ptr) {
|
||||||
|
extern void isr_keyboard(void);
|
||||||
|
|
||||||
|
/* Multiboot2 info tag types:
|
||||||
|
* 5 = BIOS boot device, 6 = memory map, 8 = framebuffer info, ...
|
||||||
|
* Note: in the *header* (request side), type 5 means "framebuffer
|
||||||
|
* request", but the bootloader's *response* tag uses type 8. */
|
||||||
|
struct mboot_tag* tag = (struct mboot_tag*)(mboot_ptr + 8);
|
||||||
|
while (tag->type != 0) {
|
||||||
|
if (tag->type == 8) {
|
||||||
|
struct mboot_tag_framebuffer* fb = (struct mboot_tag_framebuffer*)tag;
|
||||||
|
fb_addr = fb->framebuffer_addr;
|
||||||
|
fb_pitch = fb->framebuffer_pitch;
|
||||||
|
fb_width = fb->framebuffer_width;
|
||||||
|
fb_height = fb->framebuffer_height;
|
||||||
|
fb_bpp = fb->framebuffer_bpp;
|
||||||
|
}
|
||||||
|
tag = (struct mboot_tag*)((uint8_t*)tag + ((tag->size + 7) & ~7));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fb_addr && fb_bpp >= 24) {
|
||||||
|
fb_cols = fb_width / 8;
|
||||||
|
fb_rows = fb_height / 8;
|
||||||
|
for (uint32_t y = 0; y < fb_height; y++) {
|
||||||
|
for (uint32_t x = 0; x < fb_width; x++) {
|
||||||
|
fb_draw_pixel(x, y, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serial_init();
|
serial_init();
|
||||||
|
|
||||||
|
idt_set_gate(0x21, (uint64_t)isr_keyboard, 0x08, 0x8E);
|
||||||
|
idt_ptr.limit = (uint16_t)(sizeof(idt_entries) - 1);
|
||||||
|
idt_ptr.base = (uint64_t)(uintptr_t)idt_entries;
|
||||||
|
__asm__ volatile ("lidt %0" : : "m"(idt_ptr));
|
||||||
|
|
||||||
|
pic_remap();
|
||||||
|
outb(0x21, 0xFF); // mask all IRQs on master
|
||||||
|
outb(0xA1, 0xFF); // mask all IRQs on slave
|
||||||
|
pic_unmask_keyboard();
|
||||||
|
|
||||||
|
__asm__ volatile ("sti");
|
||||||
|
|
||||||
forth_printf("Kernel started\n");
|
forth_printf("Kernel started\n");
|
||||||
forth_run();
|
forth_run();
|
||||||
forth_panic();
|
forth_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_fb_addr(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
data_push((int64_t)fb_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_fb_width(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
data_push((int64_t)fb_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_fb_height(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
data_push((int64_t)fb_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_fb_pitch(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
data_push((int64_t)fb_pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_fb_bpp(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
data_push((int64_t)fb_bpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_fb_plot(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
int64_t color = data_pop();
|
||||||
|
int64_t y = data_pop();
|
||||||
|
int64_t x = data_pop();
|
||||||
|
fb_draw_pixel((int)x, (int)y, (uint32_t)color);
|
||||||
|
}
|
||||||
|
|||||||
@@ -107,6 +107,13 @@ void forth_printf(const char* fmt, ...) {
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_fb_addr(Word* w) { (void)w; data_push(0); }
|
||||||
|
void do_fb_width(Word* w) { (void)w; data_push(0); }
|
||||||
|
void do_fb_height(Word* w) { (void)w; data_push(0); }
|
||||||
|
void do_fb_pitch(Word* w) { (void)w; data_push(0); }
|
||||||
|
void do_fb_bpp(Word* w) { (void)w; data_push(0); }
|
||||||
|
void do_fb_plot(Word* w) { (void)w; data_pop(); data_pop(); data_pop(); }
|
||||||
|
|
||||||
void _start(void) {
|
void _start(void) {
|
||||||
forth_run();
|
forth_run();
|
||||||
syscall1(60, 0);
|
syscall1(60, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user