Have getc, halting, timer, graphics, mode switching
This commit is contained in:
parent
f601c99d39
commit
4a446c2d51
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,3 +15,4 @@ cmake-build-debug
|
|||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
__pycache__
|
__pycache__
|
||||||
res.txt
|
res.txt
|
||||||
|
vibing.txt
|
||||||
2
Makefile
2
Makefile
@ -106,7 +106,7 @@ debug-nox: image.bin
|
|||||||
-ex "break _start" \
|
-ex "break _start" \
|
||||||
-ex "continue"
|
-ex "continue"
|
||||||
|
|
||||||
USERPROGS=./user/false ./user/greet ./user/div0 ./user/shout ./user/badputs ./user/bss
|
USERPROGS=./user/false ./user/greet ./user/div0 ./user/shout ./user/badputs ./user/bss ./user/snake
|
||||||
|
|
||||||
fs.img: ./kernel.bin ./tools/mkfs $(USERPROGS)
|
fs.img: ./kernel.bin ./tools/mkfs $(USERPROGS)
|
||||||
./tools/mkfs $@ $< $(USERPROGS)
|
./tools/mkfs $@ $< $(USERPROGS)
|
||||||
|
|||||||
134
cpu/idt.c
134
cpu/idt.c
@ -3,7 +3,10 @@
|
|||||||
#include "memlayout.h"
|
#include "memlayout.h"
|
||||||
#include "../syscall.h"
|
#include "../syscall.h"
|
||||||
#include "../proc.h"
|
#include "../proc.h"
|
||||||
|
#include "../drivers/keyboard.h"
|
||||||
#include "../drivers/port.h"
|
#include "../drivers/port.h"
|
||||||
|
#include "../drivers/pit.h"
|
||||||
|
#include "../drivers/vga.h"
|
||||||
#include "../console.h"
|
#include "../console.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -147,7 +150,31 @@ bool is_userspace_ptr_mapped(uint32_t ptr) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* get_userspace_cstr(uint32_t ptr) {
|
static bool is_userspace_range_mapped(uint32_t ptr, uint32_t size) {
|
||||||
|
if (size == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (ptr >= KERNBASE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t end = ptr + size - 1;
|
||||||
|
if (end < ptr || end >= KERNBASE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t last_page = PGROUNDDOWN(end);
|
||||||
|
for (uint32_t addr = ptr;; addr = PGROUNDDOWN(addr) + PGSIZE) {
|
||||||
|
if (!is_userspace_ptr_mapped(addr)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (PGROUNDDOWN(addr) == last_page) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_userspace_cstr(uint32_t ptr) {
|
||||||
for (uint32_t addr = ptr;; addr++) {
|
for (uint32_t addr = ptr;; addr++) {
|
||||||
if (addr == 0 || !is_userspace_ptr_mapped(addr)) {
|
if (addr == 0 || !is_userspace_ptr_mapped(addr)) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -158,16 +185,75 @@ static void* get_userspace_cstr(uint32_t ptr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_puts(const char* s) {
|
static _Noreturn void userspace_panic(const char* msg) {
|
||||||
if (!s) {
|
if (!vga_is_text_mode()) {
|
||||||
|
switch_to_text_mode();
|
||||||
|
vga_clear_screen();
|
||||||
|
}
|
||||||
|
printk(msg);
|
||||||
|
killproc();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_puts(uintptr_t s) {
|
||||||
|
if (!is_userspace_cstr(s)) {
|
||||||
|
userspace_panic("SYS_puts panic: page fault\n");
|
||||||
|
}
|
||||||
|
printk((const char*)s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void require_text_mode_for_userspace_text_syscall() {
|
||||||
|
if (!vga_is_text_mode()) {
|
||||||
|
userspace_panic("Userspace panic: text syscall in graphics mode\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_swap_frame(uintptr_t frame) {
|
||||||
|
enum {
|
||||||
|
VGA_GRAPHICS_FRAME_SIZE = VGA_GRAPHICS_WIDTH * VGA_GRAPHICS_HEIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (vga_is_text_mode()) {
|
||||||
|
userspace_panic("Userspace panic: frame swap in text mode\n");
|
||||||
|
}
|
||||||
|
if (!is_userspace_range_mapped(frame, VGA_GRAPHICS_FRAME_SIZE)) {
|
||||||
|
userspace_panic("SYS_swap_frame panic: page fault\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *video = (uint8_t*)(KERNBASE + 0xA0000);
|
||||||
|
uint8_t *user = (uint8_t*)frame;
|
||||||
|
for (uint32_t i = 0; i < VGA_GRAPHICS_FRAME_SIZE; i++) {
|
||||||
|
video[i] = user[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refill_keyboard_copy_buffer(void) {
|
||||||
|
size_t count = kbd_state_shrd.len;
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli();
|
||||||
|
size_t rem = KEYBOARD_INTERRUPT_BUF_CAP - kbd_state_shrd.copy_len;
|
||||||
|
size_t copying = rem < count ? rem : count;
|
||||||
|
memcpy(kbd_state_shrd.copy_buf, kbd_state_shrd.buf, copying);
|
||||||
|
kbd_state_shrd.len -= copying;
|
||||||
|
kbd_state_shrd.copy_len += copying;
|
||||||
|
sti();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_getc(void) {
|
||||||
|
if (kbd_can_take_from_copy_buffer()) {
|
||||||
|
return kbd_take_from_copy_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
refill_keyboard_copy_buffer();
|
||||||
|
if (!kbd_can_take_from_copy_buffer()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
printk(s);
|
return kbd_take_from_copy_buffer();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_syscall(registers_t* r) {
|
static void handle_syscall(registers_t* r) {
|
||||||
int ret;
|
|
||||||
switch (r->eax) {
|
switch (r->eax) {
|
||||||
case SYS_exit:
|
case SYS_exit:
|
||||||
if (r->ebx == 0) {
|
if (r->ebx == 0) {
|
||||||
@ -177,24 +263,44 @@ static void handle_syscall(registers_t* r) {
|
|||||||
}
|
}
|
||||||
killproc();
|
killproc();
|
||||||
case SYS_greet:
|
case SYS_greet:
|
||||||
|
require_text_mode_for_userspace_text_syscall();
|
||||||
printk("Hello world!\n");
|
printk("Hello world!\n");
|
||||||
r->eax = 0;
|
r->eax = 0;
|
||||||
break;
|
break;
|
||||||
case SYS_putc:
|
case SYS_putc:
|
||||||
printk((const char[]){r->ebx, '\0'});
|
require_text_mode_for_userspace_text_syscall();
|
||||||
|
printk((const char[]){(char)r->ebx, '\0'});
|
||||||
r->eax = 0;
|
r->eax = 0;
|
||||||
break;
|
break;
|
||||||
case SYS_puts:
|
case SYS_puts:
|
||||||
ret = handle_puts(get_userspace_cstr(r->ebx));
|
require_text_mode_for_userspace_text_syscall();
|
||||||
if (ret < 0) {
|
handle_puts(r->ebx);
|
||||||
printk("SYS_puts panic: page fault\n");
|
|
||||||
killproc();
|
|
||||||
}
|
|
||||||
r->eax = 0;
|
r->eax = 0;
|
||||||
break;
|
break;
|
||||||
|
case SYS_switch_to_text:
|
||||||
|
switch_to_text_mode();
|
||||||
|
r->eax = 0;
|
||||||
|
break;
|
||||||
|
case SYS_switch_to_graphics:
|
||||||
|
switch_to_graphics_mode();
|
||||||
|
r->eax = 0;
|
||||||
|
break;
|
||||||
|
case SYS_swap_frame:
|
||||||
|
handle_swap_frame(r->ebx);
|
||||||
|
r->eax = 0;
|
||||||
|
break;
|
||||||
|
case SYS_time_ms:
|
||||||
|
r->eax = get_uptime_ms();
|
||||||
|
break;
|
||||||
|
case SYS_halt:
|
||||||
|
asm volatile("hlt");
|
||||||
|
r->eax = 0;
|
||||||
|
break;
|
||||||
|
case SYS_getc:
|
||||||
|
r->eax = handle_getc();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printk("Userspace panic: Unknown syscall\n");
|
userspace_panic("Userspace panic: Unknown syscall\n");
|
||||||
killproc();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,13 @@
|
|||||||
borrowed bits from http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c
|
borrowed bits from http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
#include "vga.h"
|
||||||
#include "cpu/x86.h"
|
#include "cpu/x86.h"
|
||||||
#include "cpu/memlayout.h"
|
#include "cpu/memlayout.h"
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
|
|
||||||
|
static vga_display_mode_t current_display_mode = VGA_DISPLAY_MODE_TEXT;
|
||||||
|
|
||||||
static inline char inb(int port) {
|
static inline char inb(int port) {
|
||||||
return port_byte_in(port);
|
return port_byte_in(port);
|
||||||
}
|
}
|
||||||
@ -410,6 +413,7 @@ void vgaMode13() {
|
|||||||
outb(0x3C0, 0x20);
|
outb(0x3C0, 0x20);
|
||||||
|
|
||||||
setdefaultVGApalette();
|
setdefaultVGApalette();
|
||||||
|
current_display_mode = VGA_DISPLAY_MODE_GRAPHICS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vgaMode3() {
|
void vgaMode3() {
|
||||||
@ -518,4 +522,21 @@ void vgaMode3() {
|
|||||||
|
|
||||||
inb(VGA+0x1A);
|
inb(VGA+0x1A);
|
||||||
outb(0x3C0, 0x20);
|
outb(0x3C0, 0x20);
|
||||||
|
current_display_mode = VGA_DISPLAY_MODE_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void switch_to_graphics_mode() {
|
||||||
|
vgaMode13();
|
||||||
|
}
|
||||||
|
|
||||||
|
void switch_to_text_mode() {
|
||||||
|
vgaMode3();
|
||||||
|
}
|
||||||
|
|
||||||
|
vga_display_mode_t vga_get_display_mode() {
|
||||||
|
return current_display_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vga_is_text_mode() {
|
||||||
|
return current_display_mode == VGA_DISPLAY_MODE_TEXT;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,8 +25,11 @@ enum {
|
|||||||
PIT_MODES_HW_TRIGGERRED_STROBE = 0x5,
|
PIT_MODES_HW_TRIGGERRED_STROBE = 0x5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Wtf is that O_o
|
||||||
static timer_callback callbacks[100];
|
static timer_callback callbacks[100];
|
||||||
static int registered_callbacks = 0;
|
static int registered_callbacks = 0;
|
||||||
|
static volatile uint32_t uptime_ms = 0;
|
||||||
|
|
||||||
void add_timer_callback(timer_callback tc) {
|
void add_timer_callback(timer_callback tc) {
|
||||||
callbacks[registered_callbacks++] = tc;
|
callbacks[registered_callbacks++] = tc;
|
||||||
@ -45,7 +48,7 @@ struct pit_command_t {
|
|||||||
unsigned char select_channel : 2;
|
unsigned char select_channel : 2;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
static void dec_sleep_counter(void);
|
static void timer_int_callback(void);
|
||||||
|
|
||||||
void init_pit() {
|
void init_pit() {
|
||||||
struct pit_command_t cmd = {
|
struct pit_command_t cmd = {
|
||||||
@ -59,15 +62,20 @@ void init_pit() {
|
|||||||
port_byte_out(0x40, (PIT_PROGRAM_REG & 0xff00) >> 8);
|
port_byte_out(0x40, (PIT_PROGRAM_REG & 0xff00) >> 8);
|
||||||
|
|
||||||
register_interrupt_handler(IRQ0, timer_interrupt_handler);
|
register_interrupt_handler(IRQ0, timer_interrupt_handler);
|
||||||
add_timer_callback(dec_sleep_counter);
|
add_timer_callback(timer_int_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
static volatile int sleep_counter = 0;
|
static volatile int sleep_counter = 0;
|
||||||
|
|
||||||
static void dec_sleep_counter(void) {
|
static void timer_int_callback(void) {
|
||||||
|
uptime_ms += 1000 / CLOCK_PRECISION_HZ;
|
||||||
sleep_counter--;
|
sleep_counter--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t get_uptime_ms(void) {
|
||||||
|
return uptime_ms;
|
||||||
|
}
|
||||||
|
|
||||||
void msleep(int ms) {
|
void msleep(int ms) {
|
||||||
sleep_counter = ms / 10;
|
sleep_counter = ms / 10;
|
||||||
while (sleep_counter > 0) {
|
while (sleep_counter > 0) {
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef void (*timer_callback)(void);
|
typedef void (*timer_callback)(void);
|
||||||
|
|
||||||
void init_pit(void);
|
void init_pit(void);
|
||||||
void add_timer_callback(timer_callback tc);
|
void add_timer_callback(timer_callback tc);
|
||||||
|
|
||||||
|
uint32_t get_uptime_ms(void);
|
||||||
void msleep(int ms);
|
void msleep(int ms);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -23,5 +24,17 @@ void vga_clear_screen();
|
|||||||
void vga_set_char(unsigned offset, char c);
|
void vga_set_char(unsigned offset, char c);
|
||||||
void vga_print_string(const char* s);
|
void vga_print_string(const char* s);
|
||||||
|
|
||||||
|
#define VGA_GRAPHICS_WIDTH 320
|
||||||
|
#define VGA_GRAPHICS_HEIGHT 200
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VGA_DISPLAY_MODE_TEXT = 0,
|
||||||
|
VGA_DISPLAY_MODE_GRAPHICS = 1,
|
||||||
|
} vga_display_mode_t;
|
||||||
|
|
||||||
void vgaMode13();
|
void vgaMode13();
|
||||||
void vgaMode3();
|
void vgaMode3();
|
||||||
|
void switch_to_graphics_mode();
|
||||||
|
void switch_to_text_mode();
|
||||||
|
vga_display_mode_t vga_get_display_mode();
|
||||||
|
bool vga_is_text_mode();
|
||||||
|
|||||||
4
kernel.c
4
kernel.c
@ -19,14 +19,14 @@ void vga_set_pixel(int x, int y, int color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void graphtest() {
|
void graphtest() {
|
||||||
vgaMode13();
|
switch_to_graphics_mode();
|
||||||
for (int i = 0; i < 320; ++i) {
|
for (int i = 0; i < 320; ++i) {
|
||||||
for (int j = 0; j < 200; ++j) {
|
for (int j = 0; j < 200; ++j) {
|
||||||
vga_set_pixel(i, j, (i+j)/2);
|
vga_set_pixel(i, j, (i+j)/2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msleep(5000);
|
msleep(5000);
|
||||||
vgaMode3();
|
switch_to_text_mode();
|
||||||
vga_clear_screen();
|
vga_clear_screen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
proc.c
11
proc.c
@ -1,4 +1,5 @@
|
|||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
|
#include "drivers/vga.h"
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
// matches the behavior of swtch()
|
// matches the behavior of swtch()
|
||||||
@ -28,9 +29,9 @@ void trapret();
|
|||||||
void swtch(void** oldstack, void* newstack);
|
void swtch(void** oldstack, void* newstack);
|
||||||
|
|
||||||
pde_t *get_user_proc_page_directory() {
|
pde_t *get_user_proc_page_directory() {
|
||||||
// if (!vm.user_task) {
|
if (!vm.user_task) {
|
||||||
// return 0;
|
return 0;
|
||||||
// }
|
}
|
||||||
return vm.user_task->pgdir;
|
return vm.user_task->pgdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +88,10 @@ void run_elf(const char* name) {
|
|||||||
|
|
||||||
_Noreturn void killproc() {
|
_Noreturn void killproc() {
|
||||||
void* task_stack;
|
void* task_stack;
|
||||||
|
if (!vga_is_text_mode()) {
|
||||||
|
switch_to_text_mode();
|
||||||
|
vga_clear_screen();
|
||||||
|
}
|
||||||
switchkvm();
|
switchkvm();
|
||||||
freevm(vm.user_task->pgdir);
|
freevm(vm.user_task->pgdir);
|
||||||
sti();
|
sti();
|
||||||
|
|||||||
@ -8,6 +8,12 @@ enum {
|
|||||||
SYS_greet = 1,
|
SYS_greet = 1,
|
||||||
SYS_putc = 2,
|
SYS_putc = 2,
|
||||||
SYS_puts = 3,
|
SYS_puts = 3,
|
||||||
|
SYS_switch_to_text = 4,
|
||||||
|
SYS_switch_to_graphics = 5,
|
||||||
|
SYS_swap_frame = 6,
|
||||||
|
SYS_time_ms = 7,
|
||||||
|
SYS_halt = 8,
|
||||||
|
SYS_getc = 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
int syscall(int call, uintptr_t arg);
|
int syscall(int call, uintptr_t arg);
|
||||||
|
|||||||
59
user/snake.c
59
user/snake.c
@ -1,8 +1,61 @@
|
|||||||
#include "../syscall.h"
|
#include "../syscall.h"
|
||||||
|
#include "../drivers/vga.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
int main() {
|
enum {
|
||||||
return 0;
|
FRAME_SIZE = VGA_GRAPHICS_WIDTH * VGA_GRAPHICS_HEIGHT,
|
||||||
|
BLOCK_WIDTH = 270,
|
||||||
|
BLOCK_HEIGHT = 100,
|
||||||
|
BLOCK_X = 10,
|
||||||
|
BLOCK_Y = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Non-zero initializer keeps the framebuffer in the program image, which this
|
||||||
|
// loader maps more reliably than a large BSS object.
|
||||||
|
static uint8_t frame[FRAME_SIZE] = { 1 };
|
||||||
|
|
||||||
|
static uint32_t time_ms(void) {
|
||||||
|
return (uint32_t)syscall(SYS_time_ms, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_frame(uint8_t color) {
|
||||||
|
for (uint32_t i = 0; i < FRAME_SIZE; i++) {
|
||||||
|
frame[i] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_pixel(int x, int y, uint8_t color) {
|
||||||
|
if (x < 0 || x >= VGA_GRAPHICS_WIDTH || y < 0 || y >= VGA_GRAPHICS_HEIGHT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frame[y * VGA_GRAPHICS_WIDTH + x] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_demo(void) {
|
||||||
|
clear_frame(0x01);
|
||||||
|
|
||||||
|
for (int y = 0; y < BLOCK_HEIGHT; y++) {
|
||||||
|
for (int x = 0; x < BLOCK_WIDTH; x++) {
|
||||||
|
int screen_x = BLOCK_X + x;
|
||||||
|
int screen_y = BLOCK_Y + y;
|
||||||
|
uint8_t color = (uint8_t)((x + 2 * y) & 0x3f);
|
||||||
|
|
||||||
|
if (x < 3 || y < 3 || x >= BLOCK_WIDTH - 3 || y >= BLOCK_HEIGHT - 3) {
|
||||||
|
color = 0x3f;
|
||||||
|
}
|
||||||
|
put_pixel(screen_x, screen_y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
syscall(SYS_switch_to_graphics, 0);
|
||||||
|
draw_demo();
|
||||||
|
syscall(SYS_swap_frame, (uintptr_t)frame);
|
||||||
|
|
||||||
|
uint32_t start = time_ms();
|
||||||
|
while ((uint32_t)(time_ms() - start) < 2000) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user