Hello I'm trying to make a simple os, and I'm currently trying to do double buffering.
I have two arrays in the size of the screen and a function that copy the array that currently is being used to the memory of the screen and then swap the being used array to the second one.
And there is a function that clear the screen and set it to a specific color.
screen.c
static u8 *BUFFER = (u8*) 0xA0000;
u8 buffers[2][SCREEN_SIZE];
u8 current_buffer = 0;
#define CURRENT (buffers[current_buffer])
#define SWAP() (current_buffer = 1 - current_buffer)
void screen_swap(){
memcpy(BUFFER, CURRENT, SCREEN_SIZE);
SWAP();
}
void clear_screen(u8 color){ // set all the memory of the screen to one color
memset(&CURRENT, color, SCREEN_SIZE);
}
memory.c
void memset(void* src, u8 val, u32 len){
u8* ptr = (u8*)src;
while(len--){
*ptr++ = val;
}
}
void* memcpy(void* dst, void* src, u32 len){
u8 *d = (u8*)dst;
const u8 *s = (const u8*)src;
while (len-- > 0){
*d++ = *s++;
}
return dst;
}
When I try to run these functions the system keeps rebooting. For example:
clear_screen(COLOR(0,0,255));
screen_swap();
A link to my github repo for more context
The TL;DR is that you are blasting your program stack.
I added some debug printf
calls using a macro: dbgprt
main
)&buffers[0][0]
is 0x5f60SCREEN_SIZE
is 0xfa00buffers
is 0x5f60-0x1f960memset
on buffers
, we write well beyond the address of the stack.The stack address in question (i.e. 0x7be8) is the stack address used during the boot process. In main.asm
, this is set with:
mov sp, 0x7C00 ; stack grows downwards from where we are loaded in memory
At jmpToKernel
, we need to set the esp
register to a value that doesn't conflict with anything (e.g.):
mov esp,0x90000
Here is the [redacted] output of make run
:
# qemu-system-i386 -serial file:serial.log -fda build/os-image.img
###qemu-system-i386 -serial stdio -fda build/os-image.img
qemu-system-i386 -serial stdio -fda build/os-image.img
WARNING: Image format was not specified for 'build/os-image.img' and probing guessed raw.
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
Specify the 'raw' format explicitly to remove the restrictions.
Unhandled IRQ 0
set_pallette: ENTER
set_pallette: EXIT
SCREEN_SIZE=fa00
STACK=7be8
screen_swap: ENTER
screen_swap: BUFFER=0xa0000 current_buffer=0/0x5f60/0x15960
screen_swap: EXIT
clear_screen: ENTER color=0x1c
clear_screen: BUFFER=0xa0000 current_buffer=1/0x15960/0x25360
clear_screen: EXIT
screen_swap: ENTER
screen_swap: BUFFER=0xa0000 current_buffer=1/0x15960/0x25360
screen_swap: EXIT
clear_screen: ENTER color=0x1c
clear_screen: BUFFER=0xa0000 current_buffer=0/0x5f60/0x15960
qemu-system-i386: Trying to execute code outside RAM or ROM at 0x1c1c1c1c
This usually means one of the following happened:
(1) You told QEMU to execute a kernel for the wrong machine type, and it crashed on startup (eg trying to run a raspberry pi kernel on a versatilepb QEMU machine)
(2) You didn't give QEMU a kernel or BIOS filename at all, and QEMU executed a ROM full of no-op instructions until it fell off the end
(3) Your guest kernel has a bug and crashed by jumping off into nowhere
This is almost always one of the first two, so check your command line and that you are using the right type of kernel for this machine.
If you think option (3) is likely then you can try debugging your guest with the -d debug options; in particular -d guest_errors will cause the log to include a dump of the guest register state at this point.
Execution cannot continue; stopping here.
make: *** [Makefile:37: run] Error 1
Here is a git diff
of what I changed:
Edit: Removed this for space. See update below.
UPDATE:
I added
mov esp, 0x90000
, and now I can only write to the second buffer ->buffers[1]
. Is there a different place in memory I can put the stack in or how can I store the buffer not in the stack? – neta cohen
Of course. I just grabbed that from my other "build your own OS" answer: How can I fix my VBE implementation for my OS?
That was a bit of a hack [and what the original author was doing].
At first, I was going to use the make
process to define the address for boot.asm
. Then, I realized a better way is to have the _start
in kernel_entry.asm
set it.
kernel_entry.asm
is the simplest way to go.While in the process of doing that, I was still having some trouble, so I changed some unrelated things to improve debugging:
printf
-like function to allow (e.g. %d
, %ld
, and %lld
) to support int/long/long long
numbers (so I could print the timer value).printf
to use stdarg.h
main
so that it only changed the background color on initial key press (e.g. rising edge).Here is the "no crash" version of the code:
diff --git a/Makefile b/Makefile
index 193cb35..e4cb5fa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,24 @@
+# tetos/Makefile -- make file for tetos
+#
+# SO: osdev double buffering rebooting system
+# SITE: stackoverflow.com
+# SO: 77524100
+include ./common.mk
ASM=nasm
-CC=/home/neta/opt/cross/bin/i386-elf-gcc
-LD=/home/neta/opt/cross/i386-elf/bin/ld
RM=rm
OBJCOPY=objcopy
-
SRC=src
-BUILD=build
+export BUILD=build
+
+IMGCOUNT = 2880
+KNLCOUNT = 2048
+all: $(BUILD)/os-image.img
$(BUILD)/os-image.img: boot kernel
- dd if=/dev/zero of=$@ bs=512 count=2880
+ dd if=/dev/zero of=$@ bs=512 count=$(IMGCOUNT)
dd if=$(BUILD)/boot.bin of=$@ conv=notrunc bs=512 count=1 seek=0
- dd if=$(BUILD)/kernel.bin of=$@ conv=notrunc bs=512 count=2048 seek=1
+ dd if=$(BUILD)/kernel.bin of=$@ conv=notrunc bs=512 count=$(KNLCOUNT) seek=1
boot: $(BUILD)/boot.bin
@@ -31,6 +38,7 @@ always:
run: $(BUILD)/os-image.img
# qemu-system-i386 -serial file:serial.log -fda $<
+ ###qemu-system-i386 -serial stdio -fda $<
qemu-system-i386 -serial stdio -fda $<
debug: $(BUILD)/os-image.img
@@ -38,6 +46,7 @@ debug: $(BUILD)/os-image.img
# for logs -- log: bochslog.txt
clean:
- @$(MAKE) -C $(SRC)/boot BUILD=$(abspath $(BUILD)) clean
- @$(MAKE) -C $(SRC)/kernel BUILD=$(abspath $(BUILD)) clean
+ rm -fr $(BUILD)
+ @###$(MAKE) -C $(SRC)/boot BUILD=$(abspath $(BUILD)) clean
+ @###$(MAKE) -C $(SRC)/kernel BUILD=$(abspath $(BUILD)) clean
diff --git a/common.mk b/common.mk
new file mode 100644
index 0000000..f0f2b8b
--- /dev/null
+++ b/common.mk
@@ -0,0 +1,18 @@
+# common.mk -- common definitions for make
+
+CC:=/home/neta/opt/cross/bin/i386-elf-gcc
+LD:=/home/neta/opt/cross/i386-elf/bin/ld
+
+ifeq ($(wildcard $(CC)*),)
+ CC:=gcc -m32
+ LD:=ld -melf_i386
+endif
+
+export CC
+export LD
+
+IMGCOUNT = 2880
+KNLCOUNT = 2048
+
+###OBJ := obj
+OBJ := o
diff --git a/src/boot/Makefile b/src/boot/Makefile
index 4c9a266..c6d6f8d 100644
--- a/src/boot/Makefile
+++ b/src/boot/Makefile
@@ -1,12 +1,15 @@
+include ../../common.mk
BUILD?=build/
ASM?=nasm
+###AFLAGS += -DKSTACK_SECTOR=$(KNLCOUNT)
+
.PHONY: all clean
all: $(BUILD)/boot.bin
$(BUILD)/boot.bin: main.asm
- $(ASM) main.asm -f bin -o $(BUILD)/boot.bin
+ $(ASM) main.asm -f bin -o $(BUILD)/boot.bin -l $(BUILD)/boot.lst $(AFLAGS)
clean:
rm -f $(BUILD)/boot.bin
diff --git a/src/boot/main.asm b/src/boot/main.asm
index 9a37335..8cc8d06 100644
--- a/src/boot/main.asm
+++ b/src/boot/main.asm
@@ -51,8 +51,7 @@ jmpToKernel:
mov ds, ax
mov ss, ax
- call KERNEL_OFFSET
- hlt
+ jmp KERNEL_OFFSET
bits 16
EnableA20:
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
index 7bf9326..1e1f7a4 100644
--- a/src/kernel/Makefile
+++ b/src/kernel/Makefile
@@ -1,38 +1,43 @@
+include ../../common.mk
BUILD?=build/
ASM?=nasm
ASMFLAGS?=-f elf
-CC?=/home/neta/opt/cross/bin/i386-elf-gcc
-LD=/home/neta/opt/cross/bin/i386-elf-ld
-LGCC=/home/neta/opt/cross/lib/gcc/i386-elf/13.1.0
+###CC?=/home/neta/opt/cross/bin/i386-elf-gcc
+###LD=/home/neta/opt/cross/bin/i386-elf-ld
+###LGCC=-L /home/neta/opt/cross/lib/gcc/i386-elf/13.1.0
# CCFLAGS= -ffreestanding -nostdlib -c
-CCFLAGS=-m32 -std=c11 -O2 -g -Wall -Wextra -Wpedantic -Wstrict-aliasing
+CCFLAGS+=-m32 -std=c11 -O2 -g -Wall -Wextra
+CCFLAGS+=-Werror
+###CCFLAGS+=-Wpedantic -Wstrict-aliasing
CCFLAGS+=-Wno-pointer-arith -Wno-unused-parameter
-CCFLAGS+=-nostdlib -nostdinc -ffreestanding -fno-pie -fno-stack-protector
+CCFLAGS+=-nostdlib -ffreestanding -fno-pie -fno-stack-protector
+###CCFLAGS+=-nostdinc
CCFLAGS+=-fno-builtin-function -fno-builtin -c -mgeneral-regs-only
-LDFLAGS=-ffreestanding -O2 -nostdlib -m32 -L $(LGCC) -lgcc
+LDFLAGS=-ffreestanding -O2 -nostdlib -m32 $(LGCC) -lgcc
SOURCES_C=$(wildcard *.c)
SOURCES_ASM=$(wildcard *.asm)
-OBJECTS_C=$(patsubst %.c,$(BUILD)/kernel/c/%.obj,$(SOURCES_C))
-OBJECTS_ASM=$(patsubst %.asm,$(BUILD)/kernel/asm/%.obj,$(SOURCES_ASM))
+OBJECTS_C=$(patsubst %.c,$(BUILD)/kernel/c/%.$(OBJ),$(SOURCES_C))
+OBJECTS_ASM=$(patsubst %.asm,$(BUILD)/kernel/asm/%.$(OBJ),$(SOURCES_ASM))
.PHONY: all clean always
-all: kernel.bin
+all: always kernel.bin
kernel.bin: $(OBJECTS_ASM) $(OBJECTS_C)
- $(CC) -T link.ld -o $(BUILD)/kernel.bin $^ $(LDFLAGS)
- # $(LD) -o $(BUILD)/kernel.bin $(LDFLAGS) -Tlink.ld $^
+ @###$(CC) -T link.ld -o $(BUILD)/kernel.bin $^ $(LDFLAGS)
+ $(CC) -Wl,-Map=$(BUILD)/kernel.map -T link.ld -o $(BUILD)/kernel.bin $^ $(LDFLAGS)
+ @# $(LD) -o $(BUILD)/kernel.bin $(LDFLAGS) -Tlink.ld $^
-$(BUILD)/kernel/c/%.obj: %.c always
+$(BUILD)/kernel/c/%.$(OBJ): %.c ###always
$(CC) $(CCFLAGS) -o $@ $<
-$(BUILD)/kernel/asm/%.obj: %.asm always
- $(ASM) $(ASMFLAGS) -o $@ $<
+$(BUILD)/kernel/asm/%.$(OBJ): %.asm ###always
+ $(ASM) $(ASMFLAGS) -o $@ $< -l $(basename $@).lst
always:
mkdir -p $(BUILD)/kernel/c
mkdir -p $(BUILD)/kernel/asm
clean:
- rm -f $(BUILD)/kernel.bin
+ rm -f $(BUILD)/kernel.bin $(BUILD)/kernel.map
diff --git a/src/kernel/hal.c b/src/kernel/hal.c
index 1b5a7b1..433447c 100644
--- a/src/kernel/hal.c
+++ b/src/kernel/hal.c
@@ -7,13 +7,15 @@
#include "keyboard.h"
void HAL_init(){
+ init_serial(); // init the COM1 port (for qemu and bochs)
+
IDT_init(); // init the IDT
ISR_init(); // init the ISR's
IRQ_init(); // init the IRQ's and pic
timer_install(); // register timer in irq
+#if 1
keybrd_install(); // register keyboard in irq
-
- init_serial(); // init the COM1 port (for qemu and bochs)
+#endif
write_serial('\n'); // print a new line to seperate the qemu things
diff --git a/src/kernel/irq.c b/src/kernel/irq.c
index d3ac3fa..6140a4d 100644
--- a/src/kernel/irq.c
+++ b/src/kernel/irq.c
@@ -10,7 +10,9 @@ void IRQ_handler(Registers_t *regs){
u8 irq = regs->interrupt - PIC_OFFSET;
if (g_IRQHandlers[irq] != 0){
+ //dbgprt("IRQ_handler: ENTER irq=%u\n",irq);
g_IRQHandlers[irq](regs);
+ //dbgprt("IRQ_handler: EXIT\n");
} else {
QemuPrintf("Unhandled IRQ %d\n", irq);
}
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c
index 7136655..4dbf35a 100644
--- a/src/kernel/kernel.c
+++ b/src/kernel/kernel.c
@@ -9,19 +9,62 @@
void main(){
HAL_init();
set_palette();
+ dbgprt("SCREEN_SIZE=0x%x\n",SCREEN_SIZE);
+ dbgprt("STACK=0x%x\n",__builtin_frame_address(0));
screen_swap();
+#if 0
clear_screen(COLOR(0,0,0));
+#else
+ clear_screen(COLOR(0,255,0));
+#endif
screen_swap();
+ clear_screen(COLOR(0,255,0));
+ screen_swap();
+
+ u64 otimer = get_timer();
+ dbgprt("main: OTIMER otimer=%llu\n",otimer);
+
+ u32 kcount = 0;
+ u8 color = 0;
+ bool kpress_old = 0;
+ bool kpress_cur = 0;
+
+ while (true) {
+ //dbgprt("main: ENTER/GTIMER\n");
+ u64 ctimer = get_timer();
+ //dbgprt("main: EXIT/GTIMER\n");
- while (true){
- if (is_key_pressed('a')){
- clear_screen(COLOR(255,0,0));
+ if (ctimer != otimer) {
+ //dbgprt("\rmain: CTIMER %llu\n",ctimer);
+ otimer = ctimer;
+ }
+
+ kpress_cur = is_key_pressed('a');
+
+ if ((kpress_cur != kpress_old) && kpress_cur) {
+ dbgprt("\n");
+ dbgprt("main: KTIMER kcount=%u ctimer=%llu\n",ctimer);
+ switch (kcount % 3) {
+ case 0:
+ color = COLOR(255,0,0);
+ break;
+ case 1:
+ color = COLOR(0,255,0);
+ break;
+ default:
+ color = COLOR(0,0,255);
+ break;
+ }
+ ++kcount;
+ clear_screen(color);
screen_swap();
}
+
+ kpress_old = kpress_cur;
}
- while(1){
+ while (1) {
__asm__ volatile("hlt");
}
}
diff --git a/src/kernel/kernel_entry.asm b/src/kernel/kernel_entry.asm
index d9a22bf..8e3e9c7 100644
--- a/src/kernel/kernel_entry.asm
+++ b/src/kernel/kernel_entry.asm
@@ -1,8 +1,31 @@
[bits 32]
[extern main]
+KSTACK_SIZE equ 64 * 1024 ; stack size 64 KB
+
+extern __end
+
section .entry
global _start
_start:
+ ;;;mov esp,__end ; this didn't work too well
+ mov esp,__stack ; point to start of stack
+
+ add esp,KSTACK_SIZE ; point past the end
+
+ ; get mask to align to 16 byte boundary
+ mov eax,0x0f
+ not eax
+
+ ; align stack
+ and esp,eax
+
+ ; point stack pointer to last valid part of stack
+ sub esp,16
+
call main
hlt
+
+section .bss
+__stack:
+ times KSTACK_SIZE db 0
diff --git a/src/kernel/keyboard.h b/src/kernel/keyboard.h
index 8091212..8476a61 100644
--- a/src/kernel/keyboard.h
+++ b/src/kernel/keyboard.h
@@ -88,6 +88,7 @@ enum KEYBOARD_SPECIAL_KEYS {
DOWN = 0x80
};
+void keybrd_install();
bool is_special_key(u8 key); // check in mode if key is pressed
bool is_key_pressed(u8 key); // check if key is pressed
diff --git a/src/kernel/printf.c b/src/kernel/printf.c
index 435d799..af5f85e 100644
--- a/src/kernel/printf.c
+++ b/src/kernel/printf.c
@@ -1,4 +1,5 @@
#include "util.h"
+#include <stdarg.h>
// define qemu logs
void QemuPrintStr(i8* s){
@@ -9,12 +10,12 @@ void QemuPrintStr(i8* s){
// convert binary number to ascii
const i8 g_chars[] = "0123456789abcdef";
-void printf_unsigned(u32 num, u32 base){
+void printf_unsigned(u64 num, u32 base){
i8 string[32];
i32 pos = 0;
do {
- u32 rem = num % base;
+ u64 rem = num % base;
num /= base;
string[pos++] = g_chars[rem];
} while (num > 0);
@@ -24,7 +25,7 @@ void printf_unsigned(u32 num, u32 base){
}
}
-void printf_signed(i32 num, u32 base){
+void printf_signed(s64 num, u32 base){
if (num < 0){
write_serial('-'); // changed
printf_unsigned(-num, base);
@@ -36,11 +37,22 @@ void printf_signed(i32 num, u32 base){
#define STATE_NORMAL 0
#define STATE_FORMAT 1
void QemuPrintf(const i8* str, ...){
+#if 0
u32* argp = (u32*)&str;
+#endif
u8 state = STATE_NORMAL;
+ int llflg;
+#if 0
argp += sizeof(str)/sizeof(u32);
+#else
+ va_list ap;
+ va_start(ap,str);
+ u64 uval;
+ s64 sval;
+#endif
+
while (*str){
switch (state){
case STATE_NORMAL: // wait for % or print
@@ -55,35 +67,59 @@ void QemuPrintf(const i8* str, ...){
}
// fall through
case STATE_FORMAT: // check what char is after %
+ llflg = 0;
+ if (*str == 'l') {
+ ++llflg;
+ ++str;
+ }
+ if (*str == 'l') {
+ ++llflg;
+ ++str;
+ }
+
switch (*str){
case '%':
write_serial('%'); // changed
break;
case 'c': // print char
- write_serial((char)*argp); // changed
- argp++;
+ write_serial(va_arg(ap,int)); // changed
break;
case 's': // print string
- QemuPrintStr((char*)*argp);
- argp++;
+ QemuPrintStr(va_arg(ap,char *));
break;
case 'd': // print signed base 10
- printf_signed((i32)*argp, 10);
- argp++;
+ switch (llflg) {
+ case 0:
+ sval = va_arg(ap,i32);
+ break;
+ case 1:
+ sval = va_arg(ap,long);
+ break;
+ default:
+ sval = va_arg(ap,long long);
+ break;
+ }
+ printf_signed(sval, 10);
break;
case 'u': // print unsigned base 10
- printf_unsigned((u32)*argp, 10);
- argp++;
- break;
-
case 'x':
case 'p': // print unsigned base 16
- printf_unsigned((u32)*argp, 16);
- argp++;
+ switch (llflg) {
+ case 0:
+ uval = va_arg(ap,u32);
+ break;
+ case 1:
+ uval = va_arg(ap,unsigned long);
+ break;
+ default:
+ uval = va_arg(ap,unsigned long long);
+ break;
+ }
+ printf_unsigned(uval, (*str == 'u') ? 10 : 16);
break;
default: break; // ignore invalid char
@@ -93,5 +129,10 @@ void QemuPrintf(const i8* str, ...){
}
str++;
}
+
+#if 1
+ va_end(ap);
+#endif
+
return;
}
diff --git a/src/kernel/screen.c b/src/kernel/screen.c
index 45f1de1..3713ad3 100644
--- a/src/kernel/screen.c
+++ b/src/kernel/screen.c
@@ -7,21 +7,39 @@ static u8 *BUFFER = (u8*) 0xA0000;
u8 buffers[2][SCREEN_SIZE];
u8 current_buffer = 0;
+#if 0
#define CURRENT (buffers[current_buffer])
+#else
+#define CURRENT (&buffers[current_buffer][0])
+#endif
+#if 0
#define SWAP() (current_buffer = 1 - current_buffer)
+#else
+#define SWAP() current_buffer = current_buffer ? 0 : 1
+#endif
#define VGA_MASK 0x3c6
#define VGA_READ_ADD 0x3c7
#define VGA_WRITE_ADD 0x3c8
#define VGA_DATA 0x3c9
+#define CURRENT_SHOW \
+ dbgprt("%s: BUFFER=0x%x current_buffer=%d/0x%x/0x%x\n", \
+ __FUNCTION__,BUFFER,current_buffer,CURRENT,CURRENT + SCREEN_SIZE)
+
void screen_swap(){
+ dbgprt("screen_swap: ENTER\n");
+ //CURRENT_SHOW;
memcpy(BUFFER, CURRENT, SCREEN_SIZE);
SWAP();
+ dbgprt("screen_swap: EXIT\n");
}
void clear_screen(u8 color){
- memset(&CURRENT, color, SCREEN_SIZE);
+ dbgprt("clear_screen: ENTER color=0x%x\n",color);
+ CURRENT_SHOW;
+ memset(CURRENT, color, SCREEN_SIZE);
+ dbgprt("clear_screen: EXIT\n");
}
void plot_pixel(i32 x, i32 y, u8 color){
@@ -30,6 +48,7 @@ void plot_pixel(i32 x, i32 y, u8 color){
}
void set_palette(){
+ dbgprt("set_pallette: ENTER\n");
outb(VGA_WRITE_ADD, 0);
for(u8 i=0; i < 255; i++){
// we shift it by 2 because each color is 6 bits
@@ -43,6 +62,7 @@ void set_palette(){
outb(VGA_DATA, 0xff >> 2);
outb(VGA_DATA, 0xff >> 2);
outb(VGA_DATA, 0xff >> 2);
+ dbgprt("set_pallette: EXIT\n");
}
u8 COLOR(u8 r, u8 g, u8 b){
diff --git a/src/kernel/timer.c b/src/kernel/timer.c
index 748de08..7e283c0 100644
--- a/src/kernel/timer.c
+++ b/src/kernel/timer.c
@@ -2,36 +2,38 @@
#include "util.h"
#include "irq.h"
-static struct {
- u32 divisor;
- u32 frequency;
- u64 ticks;
-} state;
-
/* u64 timer = 0; */
void timerFunction(Registers_t *regs){
- state.ticks++;
+ timer_state.ticks++;
+ //dbgprt("timerFunction: ticks=%llu\n",timer_state.ticks);
}
void PIT_setCount(){
// set the frequency of the pit to 1/TIMER_FREQ
- state.divisor = TIMER_FREQ;
- state.frequency = PIT_INTERNAL_FREQUENCY / state.divisor; // get the desired freq
+ timer_state.divisor = TIMER_FREQ;
+ timer_state.frequency = PIT_INTERNAL_FREQUENCY / timer_state.divisor; // get the desired freq
CLI();
outb(PIT_COMMAND, PIT_SET);
- outb(PIT_CHANNEL0, state.frequency & 0xff); // low byte
- outb(PIT_CHANNEL0, ((state.frequency & 0xff00) >> 8)); // high byte
+ outb(PIT_CHANNEL0, timer_state.frequency & 0xff); // low byte
+ outb(PIT_CHANNEL0, ((timer_state.frequency & 0xff00) >> 8)); // high byte
STI();
return;
}
u64 get_timer(){
- return state.ticks;
+ return timer_state.ticks;
}
void timer_install(){
+ dbgprt("timer_install: ENTER\n");
+#if 0
PIT_setCount();
IRQ_RegisterHandler(0, timerFunction);
+#else
+ IRQ_RegisterHandler(0, timerFunction);
+ PIT_setCount();
+#endif
+ dbgprt("timer_install: EXIT\n");
}
diff --git a/src/kernel/timer.h b/src/kernel/timer.h
index 9d6de1e..daecf36 100644
--- a/src/kernel/timer.h
+++ b/src/kernel/timer.h
@@ -13,6 +13,14 @@
#define PIT_SET 0x36
+struct timer {
+ u32 divisor;
+ u32 frequency;
+ u64 ticks;
+};
+
+struct timer timer_state;
+
void timer_install();
u64 get_timer();
diff --git a/src/kernel/util.h b/src/kernel/util.h
index df2e92b..4935576 100644
--- a/src/kernel/util.h
+++ b/src/kernel/util.h
@@ -10,6 +10,8 @@ typedef char i8;
typedef short i16;
typedef int i32;
typedef long long i64;
+typedef int s32;
+typedef long long s64;
typedef u32 size_t;
typedef u32 uintptr_t;
typedef float f32;
@@ -41,6 +43,9 @@ typedef u8 bool;
void QemuPrintStr(i8* s);
void QemuPrintf(const i8* str, ...);
+#define dbgprt(_fmt...) \
+ QemuPrintf(_fmt)
+
// communiation via ports --> io.c
int init_serial();
void write_serial(char a);
UPDATE #2:
Thank you so much, now it works!! There is something I didn't quite understand... why use two buffers, why buffers is two arrays in the size of screen. Why can't we just write to the same array each time and then copy it to the screen memory? – neta cohen
Yes, you are quite correct. You don't need two buffers
. But, it's your code, so why did you do this? ;-)
Just one is needed because filling buffers
and then "blitting" to the frame buffer (i.e. the memcpy
) is [already] "double buffering"
It would actually be faster with just one buffers
. After sending the first frame to the frame buffer, generating the second frame could be just a small incremental change to buffers
This is similar to using a graphics library like SDL2
.
buffers
), draw into that surface. Or, just draw into the offscreen buffer with (e.g.) SDL_RenderDrawRect
SDL_RenderPresent
(like your memcpy
).I've seen this in some other similar SO questions for this like the linked answer. The github repo linked to on that page is [AFAICT] no longer available. But, it had a buffer that was just text chars, it would change those, then use those to index into a font to produce the raster lines in the frame buffer.
Really, I don't know why, so the following is just speculation ...
Although not really true on modern systems, IIRC [and I could easily be wrong about this] access to the frame buffer could be slower than regular RAM on older systems. So, with two offscreen buffers
, we could do memcpy
only for the pixels that change frame-to-frame.
Or, with multiple buffers, it could help with animation (loosely):
.gif
file into buffers[0]
buffers[1]
memcpy
of buffers[0]
to H/W frame bufferSo, reading data from a file for frame N
could be overlapped with the memcpy
for frame N-1
. This could be more efficient.