Compare commits
8 Commits
19c8608c76
...
53b4cff56a
| Author | SHA1 | Date | |
|---|---|---|---|
|
53b4cff56a
|
|||
|
278a524bbb
|
|||
|
efcc54ed4b
|
|||
|
0d49827035
|
|||
|
fcb533ff24
|
|||
|
23451c8e85
|
|||
|
fcbc810db8
|
|||
|
dbf4eb5d0e
|
@@ -1,19 +1,23 @@
|
|||||||
CC = gcc
|
CC = clang
|
||||||
CFLAGS = -Wall -Wextra -g -std=c11 -D_POSIX_C_SOURCE=200809L
|
CFLAGS = -Wall -Wextra -g -std=c11
|
||||||
LDFLAGS =
|
COMMON_SRCS = forth_core.c forth_dict.c forth_words.c forth_interp.c main.c
|
||||||
SRCS = forth_core.c forth_dict.c forth_words.c forth_interp.c main.c
|
|
||||||
OBJS = $(SRCS:.c=.o)
|
LINUX_SRCS = $(COMMON_SRCS) platform_linux.c
|
||||||
|
KERNEL_SRCS = $(COMMON_SRCS) platform_kernel.c kernel_entry.S
|
||||||
|
KERNEL_LD = kernel.ld
|
||||||
|
|
||||||
TARGET = forth
|
TARGET = forth
|
||||||
|
KERNEL_TARGET = forth.kernel
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
$(TARGET): $(OBJS)
|
$(TARGET): $(LINUX_SRCS) forth.h
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -static -nostdlib -ffreestanding -fno-stack-protector -o $@ $(LINUX_SRCS)
|
||||||
|
|
||||||
%.o: %.c forth.h
|
$(KERNEL_TARGET): $(KERNEL_SRCS) forth.h $(KERNEL_LD)
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -ffreestanding -nostdlib -fno-stack-protector -mno-red-zone -fno-pie -no-pie -o $@ $(KERNEL_SRCS) -T$(KERNEL_LD) -Wl,--build-id=none
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJS) $(TARGET)
|
rm -f $(TARGET) $(KERNEL_TARGET)
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|||||||
@@ -1,29 +1,46 @@
|
|||||||
#ifndef FORTH_H
|
#ifndef FORTH_H
|
||||||
#define FORTH_H
|
#define FORTH_H
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
// Configuration (all hard limits removed)
|
// Configuration (all hard limits removed)
|
||||||
#define MAX_NAME_LEN 31
|
#define MAX_NAME_LEN 31
|
||||||
|
#define FORTH_EOF (-1)
|
||||||
|
|
||||||
/* Portable panic hook. Override for bare-metal reset/handling. */
|
/* Platform interface -- must be provided by the target platform layer. */
|
||||||
#ifndef forth_panic
|
void forth_putchar(char c);
|
||||||
#define forth_panic() do { for (;;) ; } while (0)
|
int forth_getchar(void);
|
||||||
#endif
|
void forth_printf(const char* fmt, ...);
|
||||||
|
void forth_fflush(void);
|
||||||
|
void forth_panic(void);
|
||||||
|
|
||||||
/* Portable I/O hooks. Define FORTH_CUSTOM_IO before including this header
|
/* Platform string-to-number (base 10 is required). */
|
||||||
* to provide bare-metal UART (or other) implementations. */
|
int64_t forth_strtoll(const char* str, char** endptr, int base);
|
||||||
#ifndef FORTH_CUSTOM_IO
|
|
||||||
#define forth_putchar(c) putchar(c)
|
/* Portable character classification. */
|
||||||
#define forth_getchar() getchar()
|
static inline int forth_isspace(int c) {
|
||||||
#define forth_printf(...) printf(__VA_ARGS__)
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
|
||||||
#define forth_fflush() fflush(stdout)
|
}
|
||||||
#endif
|
|
||||||
|
/* Portable string operations. */
|
||||||
|
static inline size_t forth_strlen(const char* s) {
|
||||||
|
size_t n = 0;
|
||||||
|
while (s[n]) n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void forth_memcpy(void* dst, const void* src, size_t n) {
|
||||||
|
char* d = dst;
|
||||||
|
const char* s = src;
|
||||||
|
while (n--) *d++ = *s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int forth_strcmp(const char* a, const char* b) {
|
||||||
|
while (*a && *a == *b) { a++; b++; }
|
||||||
|
return (unsigned char)*a - (unsigned char)*b;
|
||||||
|
}
|
||||||
|
|
||||||
/* Static memory sizes (override before including forth.h) */
|
/* Static memory sizes (override before including forth.h) */
|
||||||
#ifndef FORTH_DATA_STACK_SIZE
|
#ifndef FORTH_DATA_STACK_SIZE
|
||||||
@@ -105,6 +122,9 @@ extern Word* w_branch;
|
|||||||
extern Word* w_zbranch;
|
extern Word* w_zbranch;
|
||||||
extern Word* w_dot_quote_inner;
|
extern Word* w_dot_quote_inner;
|
||||||
|
|
||||||
|
// Entry point
|
||||||
|
void forth_run(void);
|
||||||
|
|
||||||
// Core function prototypes
|
// Core function prototypes
|
||||||
void data_push(int64_t val);
|
void data_push(int64_t val);
|
||||||
int64_t data_pop(void);
|
int64_t data_pop(void);
|
||||||
|
|||||||
+4
-4
@@ -5,10 +5,10 @@ Word* add_primitive(const char* name, void (*code)(Word*), uint8_t flags) {
|
|||||||
w->prev = dict_head;
|
w->prev = dict_head;
|
||||||
dict_head = w;
|
dict_head = w;
|
||||||
|
|
||||||
size_t len = strlen(name);
|
size_t len = forth_strlen(name);
|
||||||
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
w->flags = flags | (uint8_t)len;
|
w->flags = flags | (uint8_t)len;
|
||||||
memcpy(w->name, name, len);
|
forth_memcpy(w->name, name, len);
|
||||||
w->name[len] = '\0';
|
w->name[len] = '\0';
|
||||||
w->code = code;
|
w->code = code;
|
||||||
w->body = NULL;
|
w->body = NULL;
|
||||||
@@ -18,14 +18,14 @@ Word* add_primitive(const char* name, void (*code)(Word*), uint8_t flags) {
|
|||||||
Word* lookup_word(const char* name) {
|
Word* lookup_word(const char* name) {
|
||||||
for (Word* w = dict_head; w != NULL; w = w->prev) {
|
for (Word* w = dict_head; w != NULL; w = w->prev) {
|
||||||
if (w->flags & (1 << 6)) continue;
|
if (w->flags & (1 << 6)) continue;
|
||||||
if (strcmp(w->name, name) == 0) return w;
|
if (forth_strcmp(w->name, name) == 0) return w;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Word* lookup_word_internal(const char* name) {
|
Word* lookup_word_internal(const char* name) {
|
||||||
for (Word* w = dict_head; w != NULL; w = w->prev) {
|
for (Word* w = dict_head; w != NULL; w = w->prev) {
|
||||||
if (strcmp(w->name, name) == 0) return w;
|
if (forth_strcmp(w->name, name) == 0) return w;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -3,12 +3,12 @@
|
|||||||
// Input tokenizer (unchanged)
|
// Input tokenizer (unchanged)
|
||||||
char* next_token(void) {
|
char* next_token(void) {
|
||||||
if (input_ptr == NULL) return NULL;
|
if (input_ptr == NULL) return NULL;
|
||||||
while (*input_ptr != '\0' && isspace((unsigned char)*input_ptr)) {
|
while (*input_ptr != '\0' && forth_isspace((unsigned char)*input_ptr)) {
|
||||||
input_ptr++;
|
input_ptr++;
|
||||||
}
|
}
|
||||||
if (*input_ptr == '\0') return NULL;
|
if (*input_ptr == '\0') return NULL;
|
||||||
char* start = input_ptr;
|
char* start = input_ptr;
|
||||||
while (*input_ptr != '\0' && !isspace((unsigned char)*input_ptr)) {
|
while (*input_ptr != '\0' && !forth_isspace((unsigned char)*input_ptr)) {
|
||||||
input_ptr++;
|
input_ptr++;
|
||||||
}
|
}
|
||||||
if (*input_ptr != '\0') {
|
if (*input_ptr != '\0') {
|
||||||
@@ -63,10 +63,10 @@ void process_token(const char* token) {
|
|||||||
}
|
}
|
||||||
} else { // Try to parse as number
|
} else { // Try to parse as number
|
||||||
char* end;
|
char* end;
|
||||||
long long v = strtoll(token, &end, 10);
|
int64_t v = forth_strtoll(token, &end, 10);
|
||||||
if (end != token && *end == '\0') {
|
if (end != token && *end == '\0') {
|
||||||
if (state == 0) {
|
if (state == 0) {
|
||||||
data_push((int64_t)v);
|
data_push(v);
|
||||||
} else { // Compile lit + number
|
} else { // Compile lit + number
|
||||||
if (!w_lit) {
|
if (!w_lit) {
|
||||||
forth_printf("Fatal: lit word not found\n");
|
forth_printf("Fatal: lit word not found\n");
|
||||||
@@ -91,13 +91,13 @@ void outer_interpreter(void) {
|
|||||||
int c;
|
int c;
|
||||||
while (i < sizeof(line_buf) - 1) {
|
while (i < sizeof(line_buf) - 1) {
|
||||||
c = forth_getchar();
|
c = forth_getchar();
|
||||||
if (c == EOF || c == '\n' || c == '\r') {
|
if (c == FORTH_EOF || c == '\n' || c == '\r') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
line_buf[i++] = (char)c;
|
line_buf[i++] = (char)c;
|
||||||
}
|
}
|
||||||
line_buf[i] = '\0';
|
line_buf[i] = '\0';
|
||||||
if (i == 0 && c == EOF) {
|
if (i == 0 && c == FORTH_EOF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
input_buf = line_buf;
|
input_buf = line_buf;
|
||||||
|
|||||||
+17
-15
@@ -309,7 +309,7 @@ void do_zero_gt(Word* w) {
|
|||||||
void do_dot(Word* w) {
|
void do_dot(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (data_sp < 0) return;
|
if (data_sp < 0) return;
|
||||||
forth_printf("%" PRId64 " ", data_pop());
|
forth_printf("%lld ", (long long)data_pop());
|
||||||
forth_fflush();
|
forth_fflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ void do_emit(Word* w) {
|
|||||||
void do_key(Word* w) {
|
void do_key(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
int c = forth_getchar();
|
int c = forth_getchar();
|
||||||
data_push(c == EOF ? -1 : c);
|
data_push(c == FORTH_EOF ? -1 : c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_dot_quote(Word* w) {
|
void do_dot_quote(Word* w) {
|
||||||
@@ -337,7 +337,7 @@ void do_dot_quote(Word* w) {
|
|||||||
if (state == 0) {
|
if (state == 0) {
|
||||||
// Interpret mode: print immediately
|
// Interpret mode: print immediately
|
||||||
if (input_ptr == NULL) { forth_printf("Missing string\n"); return; }
|
if (input_ptr == NULL) { forth_printf("Missing string\n"); return; }
|
||||||
while (*input_ptr && isspace((unsigned char)*input_ptr)) input_ptr++;
|
while (*input_ptr && forth_isspace((unsigned char)*input_ptr)) input_ptr++;
|
||||||
if (*input_ptr != '"') { forth_printf("Expected \" to start string\n"); return; }
|
if (*input_ptr != '"') { forth_printf("Expected \" to start string\n"); return; }
|
||||||
input_ptr++;
|
input_ptr++;
|
||||||
char* start = input_ptr;
|
char* start = input_ptr;
|
||||||
@@ -349,7 +349,7 @@ void do_dot_quote(Word* w) {
|
|||||||
} else {
|
} else {
|
||||||
// Compile mode: compile string for runtime
|
// Compile mode: compile string for runtime
|
||||||
if (input_ptr == NULL) { forth_printf("Missing string\n"); return; }
|
if (input_ptr == NULL) { forth_printf("Missing string\n"); return; }
|
||||||
while (*input_ptr && isspace((unsigned char)*input_ptr)) input_ptr++;
|
while (*input_ptr && forth_isspace((unsigned char)*input_ptr)) input_ptr++;
|
||||||
if (*input_ptr != '"') { forth_printf("Expected \" to start string\n"); return; }
|
if (*input_ptr != '"') { forth_printf("Expected \" to start string\n"); return; }
|
||||||
input_ptr++;
|
input_ptr++;
|
||||||
char* start = input_ptr;
|
char* start = input_ptr;
|
||||||
@@ -495,10 +495,10 @@ void do_variable(Word* w) {
|
|||||||
new_w->prev = dict_head;
|
new_w->prev = dict_head;
|
||||||
dict_head = new_w;
|
dict_head = new_w;
|
||||||
|
|
||||||
size_t len = strlen(name);
|
size_t len = forth_strlen(name);
|
||||||
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
new_w->flags = (uint8_t)len;
|
new_w->flags = (uint8_t)len;
|
||||||
memcpy(new_w->name, name, len);
|
forth_memcpy(new_w->name, name, len);
|
||||||
new_w->name[len] = '\0';
|
new_w->name[len] = '\0';
|
||||||
new_w->code = do_do_var;
|
new_w->code = do_do_var;
|
||||||
new_w->body = var_cell; // body points directly to the data cell in user_mem
|
new_w->body = var_cell; // body points directly to the data cell in user_mem
|
||||||
@@ -524,10 +524,10 @@ void do_constant(Word* w) {
|
|||||||
new_w->prev = dict_head;
|
new_w->prev = dict_head;
|
||||||
dict_head = new_w;
|
dict_head = new_w;
|
||||||
|
|
||||||
size_t len = strlen(name);
|
size_t len = forth_strlen(name);
|
||||||
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
new_w->flags = (uint8_t)len;
|
new_w->flags = (uint8_t)len;
|
||||||
memcpy(new_w->name, name, len);
|
forth_memcpy(new_w->name, name, len);
|
||||||
new_w->name[len] = '\0';
|
new_w->name[len] = '\0';
|
||||||
new_w->code = do_do_const;
|
new_w->code = do_do_const;
|
||||||
new_w->body = val_cell; // body points to the cell that holds the value
|
new_w->body = val_cell; // body points to the cell that holds the value
|
||||||
@@ -583,9 +583,9 @@ void do_colon(Word* w) {
|
|||||||
(void)w;
|
(void)w;
|
||||||
char* name = next_token();
|
char* name = next_token();
|
||||||
if (!name) { forth_printf("':' expects a name\n"); return; }
|
if (!name) { forth_printf("':' expects a name\n"); return; }
|
||||||
size_t len = strlen(name);
|
size_t len = forth_strlen(name);
|
||||||
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
memcpy(compiling_name, name, len);
|
forth_memcpy(compiling_name, name, len);
|
||||||
compiling_name[len] = '\0';
|
compiling_name[len] = '\0';
|
||||||
state = 1;
|
state = 1;
|
||||||
compile_idx = 0;
|
compile_idx = 0;
|
||||||
@@ -603,7 +603,7 @@ void do_semicolon(Word* w) {
|
|||||||
// Create body copy of compiled cells
|
// Create body copy of compiled cells
|
||||||
Cell* body_copy = forth_alloc_body(compile_idx);
|
Cell* body_copy = forth_alloc_body(compile_idx);
|
||||||
if (!body_copy) { forth_printf("Out of memory\n"); return; }
|
if (!body_copy) { forth_printf("Out of memory\n"); return; }
|
||||||
memcpy(body_copy, compile_buf, compile_idx * sizeof(Cell));
|
forth_memcpy(body_copy, compile_buf, compile_idx * sizeof(Cell));
|
||||||
|
|
||||||
// Create new word entry
|
// Create new word entry
|
||||||
Word* new_w = forth_alloc_word();
|
Word* new_w = forth_alloc_word();
|
||||||
@@ -611,10 +611,10 @@ void do_semicolon(Word* w) {
|
|||||||
new_w->prev = dict_head;
|
new_w->prev = dict_head;
|
||||||
dict_head = new_w;
|
dict_head = new_w;
|
||||||
|
|
||||||
size_t len = strlen(compiling_name);
|
size_t len = forth_strlen(compiling_name);
|
||||||
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
new_w->flags = (uint8_t)len; // no hidden, no immediate
|
new_w->flags = (uint8_t)len; // no hidden, no immediate
|
||||||
memcpy(new_w->name, compiling_name, len);
|
forth_memcpy(new_w->name, compiling_name, len);
|
||||||
new_w->name[len] = '\0';
|
new_w->name[len] = '\0';
|
||||||
new_w->code = do_docolon;
|
new_w->code = do_docolon;
|
||||||
new_w->body = body_copy;
|
new_w->body = body_copy;
|
||||||
@@ -692,7 +692,8 @@ void do_until(Word* w) {
|
|||||||
if (!w_zbranch) { forth_printf("Fatal: 0branch not found\n"); return; }
|
if (!w_zbranch) { forth_printf("Fatal: 0branch not found\n"); return; }
|
||||||
if (!ensure_compile_cap(2)) return;
|
if (!ensure_compile_cap(2)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
||||||
compile_buf[compile_idx++] = (Cell){.num = begin_idx - compile_idx};
|
compile_buf[compile_idx] = (Cell){.num = begin_idx - compile_idx};
|
||||||
|
compile_idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_while(Word* w) {
|
void do_while(Word* w) {
|
||||||
@@ -722,7 +723,8 @@ void do_repeat(Word* w) {
|
|||||||
if (!w_branch) { forth_printf("Fatal: branch not found\n"); return; }
|
if (!w_branch) { forth_printf("Fatal: branch not found\n"); return; }
|
||||||
if (!ensure_compile_cap(2)) return;
|
if (!ensure_compile_cap(2)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_branch};
|
compile_buf[compile_idx++] = (Cell){.word = w_branch};
|
||||||
compile_buf[compile_idx++] = (Cell){.num = begin_idx - compile_idx};
|
compile_buf[compile_idx] = (Cell){.num = begin_idx - compile_idx};
|
||||||
|
compile_idx++;
|
||||||
|
|
||||||
compile_buf[while_offset_idx].num = compile_idx - while_offset_idx;
|
compile_buf[while_offset_idx].num = compile_idx - while_offset_idx;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x100000;
|
||||||
|
|
||||||
|
.text : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.multiboot2)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : ALIGN(4K)
|
||||||
|
{
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss)
|
||||||
|
*(COMMON)
|
||||||
|
__bss_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note : ALIGN(4)
|
||||||
|
{
|
||||||
|
*(.note.Xen)
|
||||||
|
}
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
# Multiboot2 header and x86_64 long-mode bootstrap
|
||||||
|
|
||||||
|
.section .multiboot2, "a"
|
||||||
|
.align 8
|
||||||
|
multiboot_header:
|
||||||
|
.long 0xe85250d6
|
||||||
|
.long 0
|
||||||
|
.long multiboot_header_end - multiboot_header
|
||||||
|
.long -(0xe85250d6 + 0 + (multiboot_header_end - multiboot_header))
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
.word 0
|
||||||
|
.word 0
|
||||||
|
.long 8
|
||||||
|
multiboot_header_end:
|
||||||
|
|
||||||
|
.section .bss, "aw", @nobits
|
||||||
|
.align 4096
|
||||||
|
pml4:
|
||||||
|
.space 4096
|
||||||
|
pdpt:
|
||||||
|
.space 4096
|
||||||
|
pd:
|
||||||
|
.space 4096
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
stack_bottom:
|
||||||
|
.space 16384
|
||||||
|
stack_top:
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.code32
|
||||||
|
.global _start
|
||||||
|
.type _start, @function
|
||||||
|
_start:
|
||||||
|
movl $stack_top, %esp
|
||||||
|
|
||||||
|
cld
|
||||||
|
movl $__bss_start, %edi
|
||||||
|
movl $__bss_end, %ecx
|
||||||
|
subl %edi, %ecx
|
||||||
|
xorl %eax, %eax
|
||||||
|
rep stosb
|
||||||
|
|
||||||
|
movl $pdpt, %eax
|
||||||
|
orl $0x03, %eax
|
||||||
|
movl %eax, pml4
|
||||||
|
|
||||||
|
movl $pd, %eax
|
||||||
|
orl $0x03, %eax
|
||||||
|
movl %eax, pdpt
|
||||||
|
|
||||||
|
movl $0x00000083, %eax
|
||||||
|
movl $pd, %edi
|
||||||
|
movl $512, %ecx
|
||||||
|
1:
|
||||||
|
movl %eax, (%edi)
|
||||||
|
addl $0x200000, %eax
|
||||||
|
addl $8, %edi
|
||||||
|
loop 1b
|
||||||
|
|
||||||
|
movl $pml4, %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
movl %cr4, %eax
|
||||||
|
orl $0x20, %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
|
||||||
|
movl $0xC0000080, %ecx
|
||||||
|
rdmsr
|
||||||
|
orl $0x100, %eax
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $0x80000000, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
lgdt gdt64_pointer
|
||||||
|
ljmp $0x08, $long_mode_start
|
||||||
|
|
||||||
|
.code64
|
||||||
|
long_mode_start:
|
||||||
|
movabsq $stack_top, %rax
|
||||||
|
movq %rax, %rsp
|
||||||
|
|
||||||
|
call kernel_main
|
||||||
|
cli
|
||||||
|
1:
|
||||||
|
hlt
|
||||||
|
jmp 1b
|
||||||
|
|
||||||
|
.section .note.Xen, "a", @note
|
||||||
|
.align 4
|
||||||
|
.long 4
|
||||||
|
.long 4
|
||||||
|
.long 18
|
||||||
|
.asciz "Xen"
|
||||||
|
.align 4
|
||||||
|
.long _start
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
.align 8
|
||||||
|
gdt64:
|
||||||
|
.quad 0x0000000000000000
|
||||||
|
.quad 0x00209A0000000000
|
||||||
|
gdt64_pointer:
|
||||||
|
.word gdt64_pointer - gdt64 - 1
|
||||||
|
.quad gdt64
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "forth.h"
|
#include "forth.h"
|
||||||
|
|
||||||
int main(void) {
|
void forth_run(void) {
|
||||||
here = user_mem;
|
here = user_mem;
|
||||||
|
|
||||||
// Hidden words first
|
// Hidden words first
|
||||||
@@ -104,5 +104,4 @@ int main(void) {
|
|||||||
|
|
||||||
// Start outer interpreter
|
// Start outer interpreter
|
||||||
outer_interpreter();
|
outer_interpreter();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
#include "forth.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
// VGA text-mode buffer
|
||||||
|
static uint16_t* vga_buffer = (uint16_t*)0xB8000;
|
||||||
|
static int vga_row = 0;
|
||||||
|
static int vga_col = 0;
|
||||||
|
|
||||||
|
static void vga_putchar(char c) {
|
||||||
|
if (c == '\n') {
|
||||||
|
vga_col = 0;
|
||||||
|
vga_row++;
|
||||||
|
} else {
|
||||||
|
int idx = vga_row * 80 + vga_col;
|
||||||
|
vga_buffer[idx] = (uint16_t)((0x0F << 8) | (unsigned char)c);
|
||||||
|
vga_col++;
|
||||||
|
if (vga_col >= 80) {
|
||||||
|
vga_col = 0;
|
||||||
|
vga_row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vga_row >= 25) {
|
||||||
|
vga_row = 0;
|
||||||
|
vga_col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void outb(uint16_t port, uint8_t val) {
|
||||||
|
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t inb(uint16_t port) {
|
||||||
|
uint8_t ret;
|
||||||
|
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_init(void) {
|
||||||
|
outb(0x3F8 + 1, 0x00);
|
||||||
|
outb(0x3F8 + 3, 0x80);
|
||||||
|
outb(0x3F8 + 0, 0x01);
|
||||||
|
outb(0x3F8 + 1, 0x00);
|
||||||
|
outb(0x3F8 + 3, 0x03);
|
||||||
|
outb(0x3F8 + 2, 0xC7);
|
||||||
|
outb(0x3F8 + 4, 0x0B);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_putchar(char c) {
|
||||||
|
vga_putchar(c);
|
||||||
|
while ((inb(0x3F8 + 5) & 0x20) == 0) { }
|
||||||
|
outb(0x3F8, (uint8_t)c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int forth_getchar(void) {
|
||||||
|
if ((inb(0x3F8 + 5) & 1) == 0) {
|
||||||
|
return FORTH_EOF;
|
||||||
|
}
|
||||||
|
return inb(0x3F8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_fflush(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_panic(void) {
|
||||||
|
__asm__ volatile ("cli; hlt");
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t forth_strtoll(const char* str, char** endptr, int base) {
|
||||||
|
const char* s = str;
|
||||||
|
int neg = 0;
|
||||||
|
int64_t val = 0;
|
||||||
|
while (forth_isspace(*s)) s++;
|
||||||
|
if (*s == '-') { neg = 1; s++; }
|
||||||
|
else if (*s == '+') { s++; }
|
||||||
|
while (*s >= '0' && *s <= '9') {
|
||||||
|
val = val * base + (*s - '0');
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (endptr) *endptr = (char*)s;
|
||||||
|
return neg ? -val : val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_str(const char* s) {
|
||||||
|
while (*s) forth_putchar(*s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_int(long long v) {
|
||||||
|
char buf[32];
|
||||||
|
int i = 30;
|
||||||
|
int neg = 0;
|
||||||
|
if (v < 0) { neg = 1; v = -v; }
|
||||||
|
buf[31] = '\0';
|
||||||
|
if (v == 0) {
|
||||||
|
buf[i--] = '0';
|
||||||
|
} else {
|
||||||
|
while (v > 0 && i >= 0) {
|
||||||
|
buf[i--] = '0' + (v % 10);
|
||||||
|
v /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (neg) buf[i--] = '-';
|
||||||
|
print_str(&buf[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_printf(const char* fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
while (*fmt) {
|
||||||
|
if (*fmt == '%' && *(fmt + 1)) {
|
||||||
|
fmt++;
|
||||||
|
if (*fmt == 's') {
|
||||||
|
print_str(va_arg(ap, const char*));
|
||||||
|
} else if (*fmt == 'c') {
|
||||||
|
forth_putchar((char)va_arg(ap, int));
|
||||||
|
} else if (*fmt == '%') {
|
||||||
|
forth_putchar('%');
|
||||||
|
} else if (*fmt == 'l') {
|
||||||
|
if (*(fmt + 1) == 'l' && (*(fmt + 2) == 'd' || *(fmt + 2) == 'i' || *(fmt + 2) == 'u')) {
|
||||||
|
fmt += 2;
|
||||||
|
print_int(va_arg(ap, long long));
|
||||||
|
}
|
||||||
|
} else if (*fmt == 'd' || *fmt == 'i' || *fmt == 'u') {
|
||||||
|
print_int(va_arg(ap, int));
|
||||||
|
} else {
|
||||||
|
forth_putchar('%');
|
||||||
|
forth_putchar(*fmt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forth_putchar(*fmt);
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel_main(void) {
|
||||||
|
serial_init();
|
||||||
|
forth_printf("Kernel started\n");
|
||||||
|
forth_run();
|
||||||
|
forth_panic();
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#include "forth.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
static inline long syscall3(long n, long a1, long a2, long a3) {
|
||||||
|
long ret;
|
||||||
|
__asm__ volatile ("syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(n), "D"(a1), "S"(a2), "d"(a3)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long syscall1(long n, long a1) {
|
||||||
|
long ret;
|
||||||
|
__asm__ volatile ("syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(n), "D"(a1)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_putchar(char c) {
|
||||||
|
char ch = c;
|
||||||
|
syscall3(1, 1, (long)&ch, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_fflush(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int forth_getchar(void) {
|
||||||
|
unsigned char c;
|
||||||
|
long n = syscall3(0, 0, (long)&c, 1);
|
||||||
|
if (n <= 0) return FORTH_EOF;
|
||||||
|
return (int)c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_panic(void) {
|
||||||
|
syscall1(60, 1);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t forth_strtoll(const char* str, char** endptr, int base) {
|
||||||
|
const char* s = str;
|
||||||
|
int neg = 0;
|
||||||
|
int64_t val = 0;
|
||||||
|
while (forth_isspace(*s)) s++;
|
||||||
|
if (*s == '-') { neg = 1; s++; }
|
||||||
|
else if (*s == '+') { s++; }
|
||||||
|
while (*s >= '0' && *s <= '9') {
|
||||||
|
val = val * base + (*s - '0');
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (endptr) *endptr = (char*)s;
|
||||||
|
return neg ? -val : val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_str(const char* s) {
|
||||||
|
while (*s) forth_putchar(*s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_int(long long v) {
|
||||||
|
char buf[32];
|
||||||
|
int i = 30;
|
||||||
|
int neg = 0;
|
||||||
|
if (v < 0) { neg = 1; v = -v; }
|
||||||
|
buf[31] = '\0';
|
||||||
|
if (v == 0) {
|
||||||
|
buf[i--] = '0';
|
||||||
|
} else {
|
||||||
|
while (v > 0 && i >= 0) {
|
||||||
|
buf[i--] = '0' + (v % 10);
|
||||||
|
v /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (neg) buf[i--] = '-';
|
||||||
|
print_str(&buf[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forth_printf(const char* fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
while (*fmt) {
|
||||||
|
if (*fmt == '%' && *(fmt + 1)) {
|
||||||
|
fmt++;
|
||||||
|
if (*fmt == 's') {
|
||||||
|
print_str(va_arg(ap, const char*));
|
||||||
|
} else if (*fmt == 'c') {
|
||||||
|
forth_putchar((char)va_arg(ap, int));
|
||||||
|
} else if (*fmt == '%') {
|
||||||
|
forth_putchar('%');
|
||||||
|
} else if (*fmt == 'l') {
|
||||||
|
if (*(fmt + 1) == 'l' && (*(fmt + 2) == 'd' || *(fmt + 2) == 'i' || *(fmt + 2) == 'u')) {
|
||||||
|
fmt += 2;
|
||||||
|
print_int(va_arg(ap, long long));
|
||||||
|
}
|
||||||
|
} else if (*fmt == 'd' || *fmt == 'i' || *fmt == 'u') {
|
||||||
|
print_int(va_arg(ap, int));
|
||||||
|
} else {
|
||||||
|
forth_putchar('%');
|
||||||
|
forth_putchar(*fmt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forth_putchar(*fmt);
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _start(void) {
|
||||||
|
forth_run();
|
||||||
|
syscall1(60, 0);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user