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
|
||||
__pycache__
|
||||
res.txt
|
||||
vibing.txt
|
||||
2
Makefile
2
Makefile
@ -106,7 +106,7 @@ debug-nox: image.bin
|
||||
-ex "break _start" \
|
||||
-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)
|
||||
./tools/mkfs $@ $< $(USERPROGS)
|
||||
|
||||
134
cpu/idt.c
134
cpu/idt.c
@ -3,7 +3,10 @@
|
||||
#include "memlayout.h"
|
||||
#include "../syscall.h"
|
||||
#include "../proc.h"
|
||||
#include "../drivers/keyboard.h"
|
||||
#include "../drivers/port.h"
|
||||
#include "../drivers/pit.h"
|
||||
#include "../drivers/vga.h"
|
||||
#include "../console.h"
|
||||
|
||||
enum {
|
||||
@ -147,7 +150,31 @@ bool is_userspace_ptr_mapped(uint32_t ptr) {
|
||||
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++) {
|
||||
if (addr == 0 || !is_userspace_ptr_mapped(addr)) {
|
||||
return 0;
|
||||
@ -158,16 +185,75 @@ static void* get_userspace_cstr(uint32_t ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_puts(const char* s) {
|
||||
if (!s) {
|
||||
static _Noreturn void userspace_panic(const char* msg) {
|
||||
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;
|
||||
}
|
||||
printk(s);
|
||||
return 0;
|
||||
return kbd_take_from_copy_buffer();
|
||||
}
|
||||
|
||||
static void handle_syscall(registers_t* r) {
|
||||
int ret;
|
||||
switch (r->eax) {
|
||||
case SYS_exit:
|
||||
if (r->ebx == 0) {
|
||||
@ -177,24 +263,44 @@ static void handle_syscall(registers_t* r) {
|
||||
}
|
||||
killproc();
|
||||
case SYS_greet:
|
||||
require_text_mode_for_userspace_text_syscall();
|
||||
printk("Hello world!\n");
|
||||
r->eax = 0;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case SYS_puts:
|
||||
ret = handle_puts(get_userspace_cstr(r->ebx));
|
||||
if (ret < 0) {
|
||||
printk("SYS_puts panic: page fault\n");
|
||||
killproc();
|
||||
}
|
||||
require_text_mode_for_userspace_text_syscall();
|
||||
handle_puts(r->ebx);
|
||||
r->eax = 0;
|
||||
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:
|
||||
printk("Userspace panic: Unknown syscall\n");
|
||||
killproc();
|
||||
userspace_panic("Userspace panic: Unknown syscall\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,10 +4,13 @@
|
||||
borrowed bits from http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c
|
||||
|
||||
*/
|
||||
#include "vga.h"
|
||||
#include "cpu/x86.h"
|
||||
#include "cpu/memlayout.h"
|
||||
#include "port.h"
|
||||
|
||||
static vga_display_mode_t current_display_mode = VGA_DISPLAY_MODE_TEXT;
|
||||
|
||||
static inline char inb(int port) {
|
||||
return port_byte_in(port);
|
||||
}
|
||||
@ -410,6 +413,7 @@ void vgaMode13() {
|
||||
outb(0x3C0, 0x20);
|
||||
|
||||
setdefaultVGApalette();
|
||||
current_display_mode = VGA_DISPLAY_MODE_GRAPHICS;
|
||||
}
|
||||
|
||||
void vgaMode3() {
|
||||
@ -518,4 +522,21 @@ void vgaMode3() {
|
||||
|
||||
inb(VGA+0x1A);
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
// Wtf is that O_o
|
||||
static timer_callback callbacks[100];
|
||||
static int registered_callbacks = 0;
|
||||
static volatile uint32_t uptime_ms = 0;
|
||||
|
||||
void add_timer_callback(timer_callback tc) {
|
||||
callbacks[registered_callbacks++] = tc;
|
||||
@ -45,7 +48,7 @@ struct pit_command_t {
|
||||
unsigned char select_channel : 2;
|
||||
} __attribute__((packed));
|
||||
|
||||
static void dec_sleep_counter(void);
|
||||
static void timer_int_callback(void);
|
||||
|
||||
void init_pit() {
|
||||
struct pit_command_t cmd = {
|
||||
@ -59,15 +62,20 @@ void init_pit() {
|
||||
port_byte_out(0x40, (PIT_PROGRAM_REG & 0xff00) >> 8);
|
||||
|
||||
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 void dec_sleep_counter(void) {
|
||||
static void timer_int_callback(void) {
|
||||
uptime_ms += 1000 / CLOCK_PRECISION_HZ;
|
||||
sleep_counter--;
|
||||
}
|
||||
|
||||
uint32_t get_uptime_ms(void) {
|
||||
return uptime_ms;
|
||||
}
|
||||
|
||||
void msleep(int ms) {
|
||||
sleep_counter = ms / 10;
|
||||
while (sleep_counter > 0) {
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*timer_callback)(void);
|
||||
|
||||
void init_pit(void);
|
||||
void add_timer_callback(timer_callback tc);
|
||||
|
||||
uint32_t get_uptime_ms(void);
|
||||
void msleep(int ms);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
@ -23,5 +24,17 @@ void vga_clear_screen();
|
||||
void vga_set_char(unsigned offset, char c);
|
||||
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 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() {
|
||||
vgaMode13();
|
||||
switch_to_graphics_mode();
|
||||
for (int i = 0; i < 320; ++i) {
|
||||
for (int j = 0; j < 200; ++j) {
|
||||
vga_set_pixel(i, j, (i+j)/2);
|
||||
}
|
||||
}
|
||||
msleep(5000);
|
||||
vgaMode3();
|
||||
switch_to_text_mode();
|
||||
vga_clear_screen();
|
||||
}
|
||||
|
||||
|
||||
11
proc.c
11
proc.c
@ -1,4 +1,5 @@
|
||||
#include "proc.h"
|
||||
#include "drivers/vga.h"
|
||||
|
||||
struct context {
|
||||
// matches the behavior of swtch()
|
||||
@ -28,9 +29,9 @@ void trapret();
|
||||
void swtch(void** oldstack, void* newstack);
|
||||
|
||||
pde_t *get_user_proc_page_directory() {
|
||||
// if (!vm.user_task) {
|
||||
// return 0;
|
||||
// }
|
||||
if (!vm.user_task) {
|
||||
return 0;
|
||||
}
|
||||
return vm.user_task->pgdir;
|
||||
}
|
||||
|
||||
@ -87,6 +88,10 @@ void run_elf(const char* name) {
|
||||
|
||||
_Noreturn void killproc() {
|
||||
void* task_stack;
|
||||
if (!vga_is_text_mode()) {
|
||||
switch_to_text_mode();
|
||||
vga_clear_screen();
|
||||
}
|
||||
switchkvm();
|
||||
freevm(vm.user_task->pgdir);
|
||||
sti();
|
||||
|
||||
@ -8,6 +8,12 @@ enum {
|
||||
SYS_greet = 1,
|
||||
SYS_putc = 2,
|
||||
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);
|
||||
|
||||
59
user/snake.c
59
user/snake.c
@ -1,8 +1,61 @@
|
||||
#include "../syscall.h"
|
||||
#include "../drivers/vga.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
enum {
|
||||
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