Skip to content

Run FuzzyOS on real hardware #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bootloader/stage2.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void enable_a20() {
ax = call_int_0x15(0x2403);
if (!ax) {
print_log("BIOS A20-gate not supported");
label_exit();
return;
}

ax = call_int_0x15(0x2402);
Expand Down
5 changes: 3 additions & 2 deletions src/fs/ffs.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ int fetch_file_content(

// fetch file entry
int file_size = entry->content.filesize;
int block_count = file_size/FS_BLOCK_SIZE;
int block_count = (file_size+FS_BLOCK_SIZE-1)/FS_BLOCK_SIZE;
if(file_block_id >= block_count) {
return -1;
// zero block read
return 0;
}

int err = partition_read_block(
Expand Down
1 change: 1 addition & 0 deletions src/kernel/core.asm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ global kernel_core_entry_asm
mov fs, ax
mov gs, ax

xor ebp, ebp ; origin of stack trace
mov esp, STACKINIT_KERNEL_CORE ; init stack pointer
jmp kernel_core_entry

Expand Down
32 changes: 28 additions & 4 deletions src/kernel/interrupts/exceptions.asm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

extern interrupt_handler_0x00_0x1F_exception

global at_stack
global _interrupt_handler_0x00_exception
global _interrupt_handler_0x01_exception
global _interrupt_handler_0x02_exception
Expand Down Expand Up @@ -43,16 +44,23 @@ global _interrupt_handler_0x1F_exception
_interrupt_handler_%1_exception:
; As we are HLT at end of exception there
; is no need to save context for now.
pushad ; execution all general purpose registers

xor eax, eax
mov eax, gs ; execution gs
push eax
mov eax, fs ; execution fs
push eax
mov eax, es ; execution es
push eax
mov eax, ds ; execution ds
push eax
xor eax, eax
mov eax, ss ; execution ss (current also)
mov eax, ss ; execution ss
push eax
mov eax, %1 ; exception id
push eax
mov eax, GDT_KERNEL_DS ; kernel ds
mov ds, eax
mov eax, %1
push eax
call interrupt_handler_0x00_0x1F_exception
HLT
%endmacro
Expand All @@ -62,6 +70,22 @@ global _interrupt_handler_0x1F_exception
iret
%endmacro

at_stack:
push ebp
mov ebp, esp

push ds
mov eax, ss
mov ds, eax

mov esi, [ebp+8] ; stack pointer
mov eax, [esi]

pop ds

pop ebp
ret

create_low__interrupt_handler_xy_exception_nohup 0x00 ; divide-by-zero
create_low__interrupt_handler_xy_exception 0x01
create_low__interrupt_handler_xy_exception 0x02
Expand Down
78 changes: 49 additions & 29 deletions src/kernel/interrupts/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,41 +37,61 @@ extern void _interrupt_handler_0x1D_exception();
extern void _interrupt_handler_0x1E_exception();
extern void _interrupt_handler_0x1F_exception();

void interrupt_handler_0x00_0x1F_exception(int id, int err_code, int ds, int ss, int ip, int cs, int eflag) {
#define gdt_address_from_segment(s, gdte_size) (((s)%(gdte_size)==0)?get_gdt_baseaddress(gdt_table, GDT_TABLE_SIZE, (s)/(gdte_size)):-1)

struct exceptionContext {
int id; // exception id

int ss, ds, es, fs, gs;
int edi, esi, ebp, esp, ebx, edx, ecx, eax;

// at end
int err_code; // can be optional for some interrupts.
int ip, cs, eflag;
};

int at_stack(int esp);

void interrupt_handler_0x00_0x1F_exception(struct exceptionContext context) {
// written for handler with error code otherwise ip, cs and eflag will skew.
const int gdte_size = sizeof(struct GDTEntry);
panic_screen_init();
print_log("Hardware exception %d (0x%x) triggered", id, id);
print_log(" Error Code: %x", err_code);
print_log(" CS : %x (GDT entry)", cs);
print_log(" DS : %x (GDT entry)", ds);
print_log(" SS : %x (GDT entry)", ss);
print_log(" IP : %x", ip);
print_log(" FLAG : %x", eflag);
if(cs%sizeof(struct GDTEntry)==0) {
print_log(" PID : %d", get_idt_reverse_pid_lookup_cs(cs));
unsigned int abs_cs = get_gdt_baseaddress(gdt_table, GDT_TABLE_SIZE, cs/sizeof(struct GDTEntry));
print_log(" abs IP: %x", abs_cs+ip);
print_log(" abs CS: %x", abs_cs);
} else {
print_log(" PID : invalid");
print_log(" abs IP: invalid");
print_log(" abs CS: invalid");
}
if(ds%sizeof(struct GDTEntry)==0) {
print_log(" abs DS: %x", get_gdt_baseaddress(gdt_table, GDT_TABLE_SIZE, ds/sizeof(struct GDTEntry)));
} else {
print_log(" abs DS: invalid");

print_log("Hardware exception %d (0x%x) triggered", context.id, context.id);
print_log(" Error Code: %x", context.err_code);
if(context.cs%gdte_size==0) {
print_log(" PID : %d", get_idt_reverse_pid_lookup_cs(context.cs));
}
if(ss%sizeof(struct GDTEntry)==0) {
print_log(" abs SS: %x", get_gdt_baseaddress(gdt_table, GDT_TABLE_SIZE, ss/sizeof(struct GDTEntry)));
} else {
print_log(" abs SS: invalid");
print_log(" FLAG : %x", context.eflag);
print_log(" IP : %x", context.ip);
print_log(" CS : %x => %x", context.cs, gdt_address_from_segment(context.cs, gdte_size));
print_log(" DS : %x => %x", context.ds, gdt_address_from_segment(context.ds, gdte_size));
print_log(" SS : %x => %x", context.ss, gdt_address_from_segment(context.ss, gdte_size));
print_log(" ES : %x => %x", context.es, gdt_address_from_segment(context.es, gdte_size));
print_log(" FS : %x => %x", context.fs, gdt_address_from_segment(context.fs, gdte_size));
print_log(" GS : %x => %x", context.gs, gdt_address_from_segment(context.gs, gdte_size));
print_log(" EAX: %x EBX: %x ECX: %x EDX: %x", context.eax, context.ebx, context.ecx, context.edx);
print_log(" ESP: %x EBP: %x ESI: %x EDI: %x", context.esp, context.ebp, context.esi, context.edi);

// stack trace
{
const int stack_trace_max_depth = 5;
int ebp = context.ebp;
// stack[ebp] => previous_ebp, if previous_ebp == 0 then break;
print_log("stack trace: \n - %x", context.ip);
for(int i=0; ebp>0 && i<stack_trace_max_depth; i++) {
int return_address = at_stack(ebp+4);
print_log(" - %x (ni)", return_address);
ebp = at_stack(ebp);
}
}

switch (id) {

switch (context.id) {
case 0x0D:
PANIC(id, "[hw_exception] general_protection_fault");
PANIC(context.id, "[hw_exception] general_protection_fault");
}
PANIC(id, "[hw_exception] triggered: no handler");
PANIC(context.id, "[hw_exception] triggered: no handler");
}

void interrupt_handler_0x0D_general_protection_fault(int id, int ip, int cs) {
Expand Down
14 changes: 11 additions & 3 deletions src/kernel/interrupts/timer.asm
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,19 @@ global create_infant_process_irq0_stack
; do_not_care: next two cs, ip
; CS and IP doesn't matter, as they are controlled by _int_irq0_end

; do_not_care: next four are eax, ebx, ecx, edx
; user: pushad
mov ecx, eax
sub ecx, 8
mov [eax-12-24], ecx ; pushad esp
; do_not_care: next three are ebp, esi, edi
mov [eax-28], ecx
mov ecx, 0
mov [eax-12], ecx ; user: eax
mov [eax-16], ecx ; user: ecx
mov [eax-20], ecx ; user: edx
mov [eax-24], ecx ; user: ebx
; missing esp, pushed on top.
mov [eax-32], ecx ; user: ebp==0, origin of stack trace.
mov [eax-36], ecx ; user: esi
mov [eax-40], ecx ; user: edi

mov ecx, [ebp+0x08] ; arg0
mov [eax-44], ecx ; user: ds
Expand Down
2 changes: 1 addition & 1 deletion src/kernel/syscall/file_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ int _file_handler_read(int user_ds, int file_id, char _us_buffer[FILEIO_BUFFER_S
return 0;
}
len = min(len, FILEIO_BUFFER_SIZE); // guard for _us_buffer

len = min(len, FS_BLOCK_SIZE-byte_index_block); // skip already read content of the block
syscall_strncpy_kernel_to_user(user_ds, _us_buffer, block+byte_index_block, len);
return len;
}
Expand Down
8 changes: 7 additions & 1 deletion src/usr/include/stdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ typedef struct FILE {

// 0 => start of file
int cursor;

// store last error code
int err;
} FILE;

// TODO: Add API for reading list of files.
Expand All @@ -41,4 +44,7 @@ typedef struct FILE {
FILE *fopen(char *filename, char *mode);
int fgetc(FILE *file);
char *fgets(char *buf, size_t n, FILE *file);
int fclose(FILE *file);
int fclose(FILE *file);

int ferror(FILE *file);
void clearerror(FILE *file);
16 changes: 15 additions & 1 deletion src/usr/lib/stdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ FILE *fopen(char *filename, char *mode) {
handler->file_handler_id = fh_id;
handler->file_id = file_id;
handler->cursor = 0;
handler->err = 0;
return handler;
}

Expand All @@ -152,10 +153,15 @@ char *fgets(char *buf, size_t n, FILE *file) {
int count = SYSCALL_A4(SYSCALL_FILE_OP, SYSCALL_FILE_SUB_READBUFFER, file->file_id, _buffer, file->cursor);
if (count < 0) {
// error
file->err = count;
return NULL;
}
if (count == 0) {
// EOF
if(og_buf==buf) {
// no new characters read
return NULL;
}
break;
}

Expand All @@ -164,11 +170,11 @@ char *fgets(char *buf, size_t n, FILE *file) {
int found_newline = 0;
for (size_t i = 0; i < max_iterations; i++) {
char_read_count++;
*(buf++)=_buffer[i];
if(_buffer[i]=='\n') {
found_newline = 1;
break;
}
*(buf++)=_buffer[i];
}
file->cursor += char_read_count;
n-=char_read_count;
Expand All @@ -181,3 +187,11 @@ char *fgets(char *buf, size_t n, FILE *file) {
int fgetc(FILE *file) {

}

int ferror(FILE *file) {
return file->err;
}

void clearerror(FILE *file) {
file->err=0;
}
10 changes: 7 additions & 3 deletions src/usr/local/src/cat.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// list directory
// print content of file
#include <stdio.h>
#include <string.h>

Expand All @@ -9,12 +9,16 @@ void process(char filename[]) {
return;
}
char buffer[80];
for (size_t i = 0; i < 20; i++) {
while(1) {
if (!fgets(buffer, sizeof(buffer), handler)) {
int err = ferror(handler);
if(err) {
printf("Error: failed to read next chunk, code %d\n", err);
exit(err);
}
break;
}
puts(buffer);
putchar('\n');
}
fclose(handler);
}
Expand Down
56 changes: 56 additions & 0 deletions src/usr/local/src/more.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// buffered print content of file
#include <stdio.h>
#include <string.h>

// assumption
#define SCREEN_WIDTH 0x50
#define SCREEN_HEIGHT 0x19

void process(char filename[]) {
FILE *handler = fopen(filename, "r");
if(handler==NULL) {
printf("failed to open '%s' file.\n", filename);
return;
}
char buffer[SCREEN_WIDTH+1];
int count_before_buffer = SCREEN_HEIGHT-2;
while(1) {
if (!fgets(buffer, sizeof(buffer), handler)) {
int err = ferror(handler);
if(err) {
printf("Error: failed to read next chunk, code %d\n", err);
exit(err);
}
break;
}
puts(buffer);
if(count_before_buffer>0) {
count_before_buffer--;
} else {
// buffer
char c = getch();
if(c=='q' || c=='Q') {
exit(0);
}
// continue
}
}
fclose(handler);
}

int print_usage() {
printf("Usage: more <filename>\n");
printf(" > buffer will start when output takes over the whole screen\n");
printf(" > press 'q' to exit\n");
printf(" > press any other key to scroll down\n");
return 0;
}

int main(int argc, char *argv[]) {
if (argc != 2) {
return print_usage();
}
char *filename = argv[1];
process(filename);
return 0;
}
3 changes: 1 addition & 2 deletions tests/app/cat_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,4 @@ QEMU_SCREENSHOT_NAME="cat_test.ppm"
python3 -m tests.qemu.monitor -p ${MONITOR_PORT:?} -sc cat readme.md

test_create_screen_dump
test_screen_content $LINENO "FuzzyOS"
test_screen_content $LINENO "32-bit x86"
test_screen_content $LINENO "Execute QEMU in debug mode and setup GDB server"