jump to
@@ -0,0 +1,8 @@
+{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +}
@@ -0,0 +1,18 @@
+dd if=/dev/zero of=cedos.img count=144 +parted cedos.img mklabel msdos +parted cedos.img mkpart primary FAT32 8s 128s -s + +dd if=/dev/zero of=fat.img count=128 +mkfs.fat fat.img + +mkdir -p ./mnt +sudo mount fat.img ./mnt +sudo cp ./build/release/components/kernel.bin ./mnt +sudo cp ./build/release/components/apps.o ./mnt +sudo umount ./mnt + +dd if=fat.img of=cedos.img seek=8 conv=notrunc +dd bs=1 if=./build/release/components/boot.bin of=cedos.img count=446 conv=notrunc +dd if=./build/release/components/boot.bin of=cedos.img skip=1 seek=1 count=7 conv=notrunc + +parted cedos.img print list all
@@ -122,8 +122,9 @@ __asm__ volatile ( "mov %1, %%eax;"
"mov %2, %%ebx;" "mov %3, %%ecx;" "mov %4, %%edx;" + "mov %0, %%esi;" "int $0x30;" - "mov %%eax, %0;" : "=m" (res) : "" (eax), "" (ebx), "" (ecx), "" (edx) : "eax", "ebx", "ecx", "edx"); + : "=m" (res) : "" (eax), "" (ebx), "" (ecx), "" (edx) : "eax", "ebx", "ecx", "edx"); return res; }
@@ -7,6 +7,6 @@
/*! * Executes an elf file from memory */ -PROCESS_ID elf_exec(VIRT_ADDR elf_pointer, uint32_t size, char *name, char *args); +PROCESS_ID elf_exec(const char *fname, char *args); #endif
@@ -0,0 +1,13 @@
+#ifndef FAT_H +#define FAT_H + +#include <stdint.h> + +void *FAT_init(); +void *FAT_read_sector_offset(uint32_t lba, uint32_t *offset); +void *FAT_read_cluster(uint16_t cluster, void *buffer); +uint16_t FAT_next_cluster(uint16_t cluster); +int FAT_root_dir_next(int index, char *fname_buffer, uint16_t *first_cluster, uint32_t *file_size); +uint32_t FAT_read_file(const char *fname, void *buffer); + +#endif
@@ -61,6 +61,9 @@
//! Name of the process. const char *name; + //! Path to the ELF executable of this process + const char *exe; + //! String of arguments for the process char *args;
@@ -30,19 +30,9 @@ uint32_t eflags;
}__attribute__((packed)) SCHED_FRAME; /*! - * Creates a new process and returns its process ID. - */ -PROCESS_ID sched_create(const char *name, char *args); - -/*! - * Copies a piece of memory into the memory space of some process. - */ -int sched_copyto(PROCESS_ID pid, VIRT_ADDR src, uint32_t length, VIRT_ADDR dest); - -/*! - * Executes the (already created) task with the given process ID. + * Spawns a new process, loads it from the given ELF file, and returns its process ID. */ -int sched_exec(PROCESS_ID pid, PROCESS_MAIN *entry); +PROCESS_ID sched_spawn(const char *name, char *args); /*! * Return the ID of the current process.@@ -79,6 +69,12 @@ * \param pid Process ID of the process to be killed.
* \return 1 on success, 0 on failure. */ int sched_kill(PROCESS_ID pid); + +/*! + * Wait for a process to terminate. + * \param pid Process ID of the process to wait for. + */ +void sched_wait(PROCESS_ID pid); /*! * The scheduler.
@@ -34,5 +34,6 @@ void *memset (void *ptr, int value, size_t num);
unsigned int strlen (const char *str); char *strcpy(char *destination, const char *source); +int strcmp(const char *str1, const char *str2); #endif
@@ -5,28 +5,19 @@ PAGE_SIZE = 1 << 12;
MEMORY { - BOOT_STAGE1_VMA : ORIGIN = 0x00007C00, LENGTH = 0x00000200 - BOOT_STAGE2_VMA : ORIGIN = 0x00010000, LENGTH = 0x00090000 + BOOT_VMA : ORIGIN = 0x00007C00, LENGTH = 0x00001000 KERNEL_VMA : ORIGIN = 0xC0000000, LENGTH = 0x30000000 APPLICATION_VMA : ORIGIN = 0x10000000, LENGTH = 0xB0000000 } SECTIONS { - BOOT_STAGE1 : AT(0x0000) + BOOT : AT(0x0000) { - */stage1.o(.*) - . = 510; - BYTE(0x55) - BYTE(0xAA) - } >BOOT_STAGE1_VMA + */boot.o(.*) + } >BOOT_VMA - BOOT_STAGE2 : AT(LOADADDR(BOOT_STAGE1) + SIZEOF(BOOT_STAGE1)) - { - */stage2.o(.*) - } >BOOT_STAGE2_VMA - - KERNEL : AT(LOADADDR(BOOT_STAGE2) + SIZEOF(BOOT_STAGE2)) + KERNEL : AT(0x5E00) { */kernel.o(.*) */kernel.o(.bss)@@ -37,7 +28,7 @@ {
*/apps.o(.*) } >APPLICATION_VMA - ELF : AT(LOADADDR(APPLICATION) + SIZEOF(APPLICATION)) + ELF : AT(0xB600) { */apps_raw.o(.*) } >APPLICATION_VMA@@ -48,24 +39,20 @@
} >KERNEL_VMA } -__SS_LMA = LOADADDR(BOOT_STAGE2); -__SS_VMA = ADDR(BOOT_STAGE2); -__SS_SIZE = SIZEOF(BOOT_STAGE2); +__BOOT_LMA = LOADADDR(BOOT); +__BOOT_VMA = ADDR(BOOT); +__BOOT_SIZE = SIZEOF(BOOT); __KERNEL_LMA = LOADADDR(KERNEL); __KERNEL_VMA = ADDR(KERNEL); __KERNEL_SIZE = SIZEOF(KERNEL); -ASSERT(__KERNEL_LMA == __SS_LMA + __SS_SIZE, "LMA incorrect!"); - -__APP_LMA = LOADADDR(APPLICATION); -__APP_VMA = ADDR(APPLICATION); -__APP_SIZE = SIZEOF(APPLICATION); - __ELF_LMA = LOADADDR(ELF); __ELF_VMA = ADDR(ELF); __ELF_SIZE = SIZEOF(ELF); __KERNEL_STACK_ADDR = 0xC0400000; -ASSERT(__SS_SIZE + __KERNEL_SIZE + __APP_SIZE + __ELF_SIZE <= 0x48 * 0x200, "bootloader payload too big!"); +ASSERT(__BOOT_SIZE <= 0x1000, "bootloader too big!"); +ASSERT(__KERNEL_SIZE <= 0x5000, "bootloader too big!"); +ASSERT(__ELF_SIZE <= 0x3000, "bootloader too big!");
@@ -51,7 +51,7 @@
export CCFLAGS export GLOBAL_BUILD -MODULES := stage1 stage2 kernel apps +MODULES := boot kernel apps OBJECTS := $(patsubst %,$(LOCAL_BUILD)/%.o,$(MODULES)) $(LOCAL_BUILD)/apps_raw.o DIRS := $(LOCAL_BUILD)@@ -60,38 +60,43 @@ $(DIRS):
> $(MKDIR) $@ .PHONY: build -build: $(GLOBAL_BUILD)/base.img $(GLOBAL_BUILD)/base.o +build: $(GLOBAL_BUILD)/cedos.img -$(GLOBAL_BUILD)/base.o: $(MODULES) -> $(LD) $(OBJECTS) -r -T link.txt -Map=$(LOG_DIR)/elf_mapfile.txt --oformat elf32-i386 -o $@ +$(GLOBAL_BUILD)/fat.img: $(MODULES) +# > $(LD) $(OBJECTS) -r -T link.txt -Map=$(LOG_DIR)/elf_mapfile.txt --oformat elf32-i386 -o $@ +> dd if=/dev/zero of=$@ count=896 +> mkfs.fat -n "cedos" -S 512 -s 8 -r 32 $@ +> mkdir -p ./mnt +> sudo mount $@ ./mnt +> sudo cp $(LOCAL_BUILD)/kernel.bin ./mnt +> sudo cp $(LOCAL_BUILD)/*.o ./mnt +> sudo umount ./mnt -$(GLOBAL_BUILD)/base.img: $(MODULES) -> $(LD) $(OBJECTS) -T link.txt -Map=$(LOG_DIR)/bin_mapfile.txt --oformat binary --nostdlib -o $@ +$(GLOBAL_BUILD)/cedos.img: $(GLOBAL_BUILD)/fat.img | $(MODULES) +> dd if=/dev/zero of=$@ count=904 +> parted $@ mklabel msdos +> parted $@ mkpart primary FAT32 8s 896s -s +> parted $@ set 1 boot on +> dd if=$< of=$@ seek=8 conv=notrunc +> dd bs=1 if=$(LOCAL_BUILD)/boot.bin of=$@ count=446 conv=notrunc +> dd if=$(LOCAL_BUILD)/boot.bin of=$@ skip=1 seek=1 count=7 conv=notrunc +> parted $@ print list all +# > $(LD) $(OBJECTS) -T link.txt -Map=$(LOG_DIR)/bin_mapfile.txt --oformat binary --nostdlib -o $@ .PHONY: logs logs: $(LOG_DIR)/base.sym $(LOG_DIR)/objdump.txt -$(LOG_DIR)/base.sym: $(GLOBAL_BUILD)/base.o -> $(OBJCOPY) --only-keep-debug $< $@ - -$(LOG_DIR)/objdump.txt: $(GLOBAL_BUILD)/base.o -> $(OBJDUMP) -D $< > $@ - -.PHONY: stage1 -stage1: -> $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C src/stage1 $(LOCAL_BUILD)/stage1.o - -.PHONY: stage2 -stage2: -> $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C src/stage2 $(LOCAL_BUILD)/stage2.o +.PHONY: boot +boot: +> $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C src/boot $(LOCAL_BUILD)/boot.bin .PHONY: kernel kernel: -> $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C src/kernel $(LOCAL_BUILD)/kernel.o +> $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C src/kernel $(LOCAL_BUILD)/kernel.bin .PHONY: apps apps: -> $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C src/apps $(LOCAL_BUILD)/apps.o +> $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C src/apps build .PHONY: clean clean:
@@ -1,1 +1,1 @@
-qemu-system-i386 -drive index=0,if=floppy,format=raw,file=build/release/base.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset,exec,in_asm -vnc :0 2> log/run_err.log+qemu-system-i386 -drive index=0,if=floppy,format=raw,file=./build/release/cedos.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset,exec,in_asm 2> log/run_err.log
@@ -8,11 +8,11 @@ "mov %1, %%eax;" \
"mov %2, %%ebx;" \ "mov %3, %%ecx;" \ "mov %4, %%edx;" \ + "lea %0, %%esi;" \ "int $" #num ";" \ - "mov %%eax, %0;" \ : "=m" (res) \ : "" (arg1), "" (arg2), "" (arg3), "" (arg4) \ - : "eax", "ebx", "ecx", "edx" \ + : "eax", "ebx", "ecx", "edx", "esi", "memory" \ ) /*!
@@ -9,26 +9,36 @@ return res;
}*/ int yield() { - int res = 0; + volatile uint32_t res = 0; interrupt(0x20, res, 0, 0, 0, 0); return res; } int get_pid() { - int res = 0; + volatile uint32_t res = 0; interrupt(0x30, res, 3, 0, 0, 0); return res; } int sc_file_read(int fd, char *buffer, uint32_t size) { - int res = 0; + volatile uint32_t res = 0; interrupt(0x30, res, 0, fd, buffer, size); return res; } int sc_file_write(int fd, char *buffer, uint32_t size) { - int res = 0; + volatile uint32_t res = 0; interrupt(0x30, res, 1, fd, buffer, size); return res; } +int process_spawn(const char *fname, const char *args) { + volatile uint32_t res = 0; + interrupt(0x30, res, 4, fname, args, 0); + return res; +} + +void process_wait(int pid) { + volatile uint32_t res = 0; + interrupt(0x30, res, 5, pid, 0, 0); +}
@@ -8,6 +8,8 @@
int sysprint(const char *fmt, int arg1, int arg2); int yield(); int get_pid(); +int process_spawn(const char *fname, const char *args); +void process_wait(int pid); int sc_file_read(int fd, char *buffer, uint32_t size); int sc_file_write(int fd, char *buffer, uint32_t size);
@@ -0,0 +1,9 @@
+#include "assembly.h" + +#include <stdint.h> + +extern void main(char *args); + +int _start(char *args) { + main(args); +}
@@ -0,0 +1,8 @@
+#include "common/cedos.h" +#include "common/stdio.h" + +#include <stdint.h> + +void main(char *args) { + printf(args); +}
@@ -1,8 +1,9 @@
-#include "cedos.h" +#include "common/cedos.h" +#include "common/stdio.h" #include <stdint.h> -void fib(void) { +void main(char *args) { uint32_t a = 0, b = 1, i = 0; while (1) { uint32_t tmp = a + b;@@ -12,6 +13,7 @@ printf("fib (%i) = %i\n", i, a);
i++; char c = 0; sc_file_read(0, &c, 1); - printf("[%c]\n", (int)(uint32_t)c);//yield(); + if (c == 0x1B) { break; } + //printf("[%c]\n", (int)(uint32_t)c);//yield(); } }
@@ -1,6 +1,8 @@
OUTPUT_ARCH(i386) OUTPUT_FORMAT(elf32-i386) +ENTRY(_start) + MEMORY { HEADER : ORIGIN = 0x00000000, LENGTH = 0x10000000@@ -9,9 +11,8 @@ }
SECTIONS { - .text : AT(0x0000) + .text : AT(0x8600) { - */start.c.o(.*) *.*(.*) } >CODE }
@@ -4,29 +4,34 @@ LOCAL_BUILD = $(GLOBAL_BUILD)/apps
SRC_DIR := $(shell pwd) -C_SOURCES := $(wildcard *.c) $(wildcard **/*.c) -S_SOURCES := $(wildcard *.s) $(wildcard **/*.s) +C_SOURCES := $(wildcard common/*.c) +S_SOURCES := $(wildcard common/*.s) -C_OBJECTS := $(patsubst %.c,$(LOCAL_BUILD)/%.c.o,$(C_SOURCES)) -S_OBJECTS := $(patsubst %.s,$(LOCAL_BUILD)/%.s.o,$(S_SOURCES)) +C_OBJECTS := $(patsubst common/%.c,$(LOCAL_BUILD)/common/%.c.o,$(C_SOURCES)) +S_OBJECTS := $(patsubst common/%.s,$(LOCAL_BUILD)/common/%.s.o,$(S_SOURCES)) OBJECTS = $(S_OBJECTS) $(C_OBJECTS) -DIRS := $(sort $(dir $(OBJECTS))) +APP_SOURCES := $(wildcard *.c) +APP_OBJECTS := $(patsubst %.c,$(GLOBAL_BUILD)/%.o,$(APP_SOURCES)) + +DIRS := $(sort $(dir $(OBJECTS) $(APP_OBJECTS))) $(OBJECTS): | $(DIRS) $(DIRS): > $(MKDIR) $(DIRS) .PHONY: build -build: $(GLOBAL_BUILD)/apps.o -$(GLOBAL_BUILD)/apps.o: $(OBJECTS) -> $(LD) -T link.txt $^ -o $(GLOBAL_BUILD)/apps.o --oformat elf32-i386 -> $(OBJCOPY) -I binary -O elf32-i386 $(GLOBAL_BUILD)/apps.o $(GLOBAL_BUILD)/apps_raw.o -> $(LD) -T link.txt -r $^ -o $(GLOBAL_BUILD)/apps.o --oformat elf32-i386 - +build: $(APP_OBJECTS) +$(GLOBAL_BUILD)/%.o: $(LOCAL_BUILD)/%.o $(OBJECTS) +> $(LD) -T link.txt -Map=$(LOG_DIR)/apps_mapfile.txt -N $^ -o $@ +# > $(OBJCOPY) -I binary -O elf32-i386 $(GLOBAL_BUILD)/apps.o $(GLOBAL_BUILD)/apps_raw.o +# > $(LD) -T link.txt -r $^ -o $(GLOBAL_BUILD)/apps.o --oformat elf32-i386 $(LOCAL_BUILD)/%.s.o: %.s > $(AS) -o $@ $< +$(LOCAL_BUILD)/%.o: %.c $(wildcard *.h) +> $(CC) -c -I$(INCLUDE_DIR) -I./common $(CCFLAGS) -o $@ $< + $(LOCAL_BUILD)/%.c.o: %.c $(wildcard *.h) -> $(CC) -c -I$(INCLUDE_DIR) $(CCFLAGS) -o $@ $< +> $(CC) -c -I$(INCLUDE_DIR) -I./common $(CCFLAGS) -o $@ $<
@@ -0,0 +1,55 @@
+#include "common/cedos.h" +#include "common/stdio.h" + +#include <stdint.h> + +void read_line(char *buffer) { + int i = 0; + char c; + buffer[0] = 0; + while (1) { + sc_file_read(1, &c, 1); + + if (c == '\n') { break; } + if (c == 0) { continue; } + if (c == 0x08 && i <= 0) { continue; } + + if (c == 0x08) { + buffer[--i] = 0; + sc_file_write(0, &c, 1); + } else { + buffer[i++] = c; + sc_file_write(0, &c, 1); + } + } + + buffer[i] = 0; + sc_file_write(0, &c, 1); +} + +void main(char *args) { + uint32_t a = 0, b = 1, i = 0; + printf("\n"); + printf("CeDOS shell\n"); + + while (1) { + printf("/> "); + + char buffer[256]; + read_line(buffer); + + //printf("Executing %s...\n", buffer); + + int pid = process_spawn(buffer, "Hello, world!\n"); + + //printf("Child process %i spawned, waiting for termination...\n", pid); + + if (pid == -1) { + printf("File not found: %s\n", buffer); + } else { + process_wait(pid); + } + + //printf("Child process %i terminated.\n", pid); + } +}
@@ -1,20 +0,0 @@
-#include "assembly.h" - -#include <stdint.h> - -extern void fib(void); - -int start(char *args) { - //uint32_t eip, esp, ebp; - //__asm__ volatile ("call jump; jump: pop %0; mov %%esp, %1; mov %%ebp, %2" : "=m" (eip), "=m" (esp), "=m" (ebp)); - - int pid = get_pid(); - while (1) { - printf("Process #%i says: \"%s\".\n", pid, args); - yield(); - } - - fib(); - - while(1); -}
@@ -0,0 +1,149 @@
+.section .text +.code16 + # check if A20 gate is enabled +.global enable_a20 +enable_a20: + mov $a20_check_msg, %si + call print + call checkA20 + je enabled + + # A20 is disabled, we need to enable it + mov $disabled_msg, %si + call print + + mov $a20_enable_msg, %si + call print + + # A20 BIOS method +a20_bios: + mov $a20_enable_bios_msg, %si + call print + + movw $0x2401, %ax + int $0x15 + + mov $0x0001, %cx + call delay + + call checkA20 + je enabled + + mov $fail_msg, %si + call print + + # A20 keyboard controller method +a20_keyboard: + mov $a20_enable_kb_msg, %si + call print + + # TODO: implement + + mov $0x0001, %cx + call delay + + call checkA20 + je enabled + + mov $fail_msg, %si + call print + + # fast A20 method +a20_fasta20: + mov $a20_enable_fasta20_msg, %si + call print + + inb $0x92, %al + orb $0x02, %al + andb $0xFE, %al + outb %al, $0x92 + + mov $0x1000, %cx + call delay + + call checkA20 + je enabled + + mov $fail_msg, %si + call print + + mov $a20_fail, %si + call print + + jmp error + + +enabled: + mov $enabled_msg, %si + call print + + ret + + + # ############################################ + # checkA20 + # checks if A20 line is enabled + # equal flag: * clear, if A20 is enabled + # * set, if A20 is disabled + # ############################################ +checkA20: + push %ds + push %es + push %si + push %di + + mov $0x0000, %ax + mov %ax, %ds + mov $0xFFFF, %ax + mov %ax, %es + + mov $0x0500, %si + mov $0x0510, %di + + movw %ds:(%si), %cx + movw %es:(%di), %dx + cmp %cx, %dx + + pop %di + pop %si + pop %es + pop %ds + ret + + + # delays for at least a given number of cycles. + # CX: number of cycles to delay +delay: + nop + loop delay + ret + + +.section .data +a20_check_msg: + .ascii "Checking A20..." + .byte 0 + +a20_enable_msg: + .ascii "Enabling A20 (BIOS)..." + .byte 13 + .byte 10 + .byte 0 + +a20_fail: + .ascii "Could not enable A20 gate. HALT" + .byte 13 + .byte 10 + .byte 0 + +a20_enable_bios_msg: + .ascii " BIOS: " + .byte 0 + +a20_enable_kb_msg: + .ascii " keyboard controller: " + .byte 0 + +a20_enable_fasta20_msg: + .ascii " fast A20 method: " + .byte 0
@@ -0,0 +1,334 @@
+.section .text +.code16 +# read hard drive parameters +.global read_drive_params +read_drive_params: + mov $drive_params_msg, %si + call print + + movw $0x0000, %ax + movw %ax, %es + movw $0x0000, %di + + movb $0x08, %ah + lea bootdriv_id, %si + movb (%si), %dl + int $0x13 + + xor %ax, %ax + movb %dl, %al + lea num_drives, %si + movb %al, (%si) + + xor %ax, %ax + movb %dh, %al + inc %ax + lea num_heads, %si + movw %ax, (%si) + + xor %ax, %ax + movb %cl, %al + shl $2, %ax + movb %ch, %al + inc %ax + lea num_cylinders, %si + movw %ax, (%si) + + xor %ax, %ax + movb %cl, %al + and $0x003F, %ax + lea num_sectors, %si + movw %ax, (%si) + + mov $done_msg, %si + call print + + # print debug information + mov $num_drives_msg, %si + call print + lea num_drives, %si + xorw %ax, %ax + movb (%si), %al + call print_hex_int16 + mov $newline, %si + call print + + mov $bootdriv_id_msg, %si + call print + lea bootdriv_id, %si + xorw %ax, %ax + movb (%si), %al + call print_hex_int16 + mov $newline, %si + call print + + mov $num_heads_msg, %si + call print + lea num_heads, %si + xorw %ax, %ax + movw (%si), %ax + call print_hex_int16 + mov $newline, %si + call print + + mov $num_cylinders_msg, %si + call print + lea num_cylinders, %si + xorw %ax, %ax + movw (%si), %ax + call print_hex_int16 + mov $newline, %si + call print + + mov $num_sectors_msg, %si + call print + lea num_sectors, %si + xorw %ax, %ax + movw (%si), %ax + call print_hex_int16 + mov $newline, %si + call print + + ret + + + # reset bootdrive +.global reset_drive +reset_drive: + mov $10, %cx +reset_drive_loop: + push %cx + movw $reset_msg, %si + call print + + movb $0x00, %ah + int $0x13 + pop %cx + jnc reset_end + loop reset_drive_loop + jc error +reset_end: + + movw $done_msg, %si + call print + + ret + + + # load second stage into memory starting at adress 0x10000 + # (NOTE: this code can only be jumped to after loading the global descriptor table + # because it uses absolute adresses larger than 16 bit) + # (NOTE2: this routine only loads 0x48 sectors of the second stage into memory + # and is in general pretty whacky. should be replaced with sth more serious) + +# arguments: +# - ax: first sector (LBA) +# - cx: last sector (LBA) +# - bx: address offset +.global load_sectors +load_sectors: + movw $load_msg, %si + call print + + movw $0x1000, %bx + movw %bx, %es + +load_sectors_loop: + push %ax + push %cx + push %bx + + # call print_hex_int16 + + movw %bx, %di + + lea num_sectors, %si + movw (%si), %bx + # inc %ax + divb %bl + movb %ah, %cl + incb %cl + + xor %ah, %ah + lea num_heads, %si + movw (%si), %bx + divb %bl + movb %ah, %dh + movb %al, %ch + + lea bootdriv_id, %si + movb (%si), %dl + + movw $0x0000, %bx + + # movw $load_debug_arrow, %si + # call print + + movb $0x02, %ah # function 0x02: read a sector + movb $0x01, %al # sectors to read count + # dl (drive) keep as is + + pusha + int $0x13 + jc load_error + + movw $load_msg_dot, %si + call print + + popa + + pop %bx + pop %cx + pop %ax + inc %ax + movw %es, %bx + add $0x20, %bx + movw %bx, %es + cmp %ax, %cx + jne load_sectors_loop + +load_end: + movw $0x0000, %si # buffer address + movw $0x1000, %ax + movw %ax, %es + call print + + movw $done_msg, %si + call print + + ret + +load_error: + movw $load_debug_fail, %si + call print + + popa + movw $load_debug_reg_ax, %si + call print + call print_hex_int16 + + movw %bx, %ax + movw $load_debug_reg_bx, %si + call print + call print_hex_int16 + + movw %cx, %ax + movw $load_debug_reg_cx, %si + call print + call print_hex_int16 + + movw %dx, %ax + movw $load_debug_reg_dx, %si + call print + call print_hex_int16 + + movw %es, %ax + movw $load_debug_reg_dx, %si + call print + call print_hex_int16 + + # TODO: dump hex values of buffer + +load_error_loop: + jmp load_error_loop + + +.section .data +drive_params_msg: + .ascii "Reading drive parameters..." + .byte 0 + +reset_msg: + .ascii "Resetting bootdrive..." + .byte 0 + +load_msg: + .ascii "Loading kernel" + # .byte 13 + # .byte 10 + .byte 0 + +load_msg_dot: + .ascii "." + .byte 0 + +load_debug_msg: + .ascii " Load: (sector) 0x" + .byte 0 + +load_debug_colon: + .ascii ":" + .byte 0 + +load_debug_arrow: + .ascii " -> (address) " + .byte 0 + +load_debug_return: + .ascii " done, (ret) 0x" + .byte 0 + +load_debug_fail: + .ascii " FAILED" + .byte 13 + .byte 10 + .byte 0 + +load_debug_reg_ax: + .ascii " AX=0x" + .byte 0 + +load_debug_reg_bx: + .ascii " BX=0x" + .byte 0 + +load_debug_reg_cx: + .ascii " CX=0x" + .byte 0 + +load_debug_reg_dx: + .ascii " DX=0x" + .byte 0 + + +bootdriv_id_msg: + .ascii "- Boot drive ID: 0x" + .byte 0 + +num_drives_msg: + .ascii "- Number of drives: 0x" + .byte 0 + +num_sectors_msg: + .ascii "- Sectors per Track: 0x" + .byte 0 + +num_cylinders_msg: + .ascii "- Total cylinders: 0x" + .byte 0 + +num_heads_msg: + .ascii "- Total drive heads: 0x" + .byte 0 + +newline: + .byte 13 + .byte 10 + .byte 0 + +.section .bss +.global bootdriv_id +bootdriv_id: + .byte 0 + +num_drives: + .byte 0 + +num_sectors: + .word 0 + +num_cylinders: + .word 0 + +num_heads: + .word 0
@@ -0,0 +1,235 @@
+.section .mbr +.code16 + + # disable interrupts + cli + + # canonicalize %CS:%EIP to a known value + ljmp $0, $start + +start: + # setup segments + movw $0x0000, %ax + movw %ax, %ss + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + + # setup stack + movw $0x9000, %sp + movw %sp, %bp + + # save boot drive index + lea bootdriv_id, %si + movb %dl, (%si) + + # select display page 0 + movb $0, %al + movb $0x05, %ah + int $0x10 + + mov $load_bl_msg, %si + call print + + # load rest of bootloader + movw $0x0000, %bx # buffer address + movw $0x07e0, %ax + movw %ax, %es # buffer address (segment) + movb $0x02, %ah # function 0x02: read a sector + movb $0x07, %al # sectors to read count + movb $0x00, %ch # cylinder + movb $0x02, %cl # sector + movb $0x00, %dh # head + lea bootdriv_id, %si + movb (%si), %dl + + int $0x13 + jnc bl_loaded + + # auxiliary functions +.global error +error: + movw $fail_msg, %si + call print + +error_loop: + jmp error_loop + + # ############################################ + # print + # prints out a string on the screen + # %si: points to the message to be printed + # ############################################ +.global print +print: + pusha + movw $0x0000, %bx + movb $0x0E, %ah + +print_loop: + lodsb + or %al, %al + jz print_end + int $0x10 + jmp print_loop +print_end: + popa + ret + +print_done: + mov $done_msg, %si + jmp print + +print_fail: + mov $fail_msg, %si + jmp print + +.global print_hex_int16 +print_hex_int16: + xchg %al, %ah + call print_hex_char + + xchg %al, %ah + call print_hex_char + ret + +# arguments: +# - ax: values to print +# - cx: number of values +print_hex_char: + ror $4, %al + call print_hex_val + + ror $4, %al + call print_hex_val + ret + +print_hex_val: + pusha + movw $0x0000, %bx + lea hex_table, %di + + andw $0x000F, %ax + add %ax, %di + movb %ds:(%di), %al + movb $0x0E, %ah + int $0x10 + popa + ret + + +hex_table: + .ascii "0123456789ABCDEF" + +# this string needs to stay outside of data section +# because it is used before the data section is loaded +load_bl_msg: + .ascii "Loading bootloader..." + .byte 0 + +.section .text +bl_loaded: + mov $done_msg, %si + call print + + call read_drive_params + + call enable_a20 + + call reset_drive + + call find_bootable_part + + call load_sectors + + movw $gdt_msg, %si + call print + + # - load global descriptor table and far jump into protected mode + lgdt (GDT_DESCRIPTOR) + + movw $done_msg, %si + call print + + lidt (IDT_DESCRIPTOR) + + mov %cr0, %eax + or $0x00000001, %eax + mov %eax, %cr0 + + # perform long jump to set code segment + ljmp $0x8, $protected + + +.code32 +protected: + # setup registers with appropriate GDT values + mov $0x10, %eax + mov %eax, %ds + mov %eax, %es + mov %eax, %fs + mov %eax, %gs + mov %eax, %ss + + call load_kernel + + # create a page directory for the kernel that maps it to 0xC0000000 + # and identity maps the first 1M of memory + call create_kernel_environment + + # load kernel page directory + movl %eax, %cr3 + + # set paging enable and protection bit + movl %cr0, %eax + or $0x80000010, %eax + movl %eax, %cr0 + + # jump to kernel code + ljmp $8, $0xC0000000 + + # loop until the heat death of the universe +loop: + jmp loop + + +.section .data +gdt_msg: + .ascii "Setting GDT..." + .byte 0 + +.global done_msg +done_msg: + .ascii "done" + .byte 13 + .byte 10 + .byte 0 + +.global fail_msg +fail_msg: + .ascii "fail" + .byte 13 + .byte 10 + .byte 0 + +.global enabled_msg +enabled_msg: + .ascii "enabled" + .byte 13 + .byte 10 + .byte 0 + +.global disabled_msg +disabled_msg: + .ascii "disabled" + .byte 13 + .byte 10 + .byte 0 + +GDT_DESCRIPTOR: + .word 0x23 + .int GDT + +IDT_DESCRIPTOR: + .word 0 + .int 0
@@ -0,0 +1,186 @@
+#include "fat.h" +#include "string.h" +#include <stdint.h> + +typedef struct { + char jmp[3]; + char oemname[8]; + + uint16_t bytes_per_sect; + uint8_t sect_per_cluster; + uint16_t num_reserved_sectors; + uint8_t num_FAT; + uint16_t max_root_dir_entries; + uint16_t total_log_sectors; + uint8_t media_desc; + uint16_t log_sect_per_fat; +} __attribute__((packed)) BOOT_SECT; + +typedef struct { + char name[8]; + char ext[3]; + uint8_t file_attr; + uint8_t user_attr; + uint8_t del_char; + uint16_t create_time; + uint16_t create_date; + uint16_t last_access_date; + uint16_t access_rights; + uint16_t last_modified_time; + uint16_t last_modified_date; + uint16_t start_of_clusters; + uint32_t file_size; +} __attribute__((packed)) DIR_ENTRY; + +typedef struct { + uint8_t seq_num; + uint16_t part_1[5]; + uint8_t file_attr; + uint8_t user_attr; + uint8_t del_char; + uint16_t part_2[6]; + uint16_t start_of_clusters; + uint16_t part_3[2]; +} __attribute__((packed)) VFAT_LFN_ENTRY; + + +void *FAT_addr; +BOOT_SECT *boot_sect; + +uint32_t FAT1_lba; +uint32_t FAT2_lba; +uint32_t root_lba; +uint32_t data_lba; + +void *FAT_init() { + const int sector_size = 512; + const int sector_num = 128; + const int part_size = sector_size * sector_num; + + // open image file + FAT_addr = (void*)(0x10000); + + boot_sect = (BOOT_SECT*)(FAT_addr); + + FAT1_lba = boot_sect->num_reserved_sectors; + FAT2_lba = FAT1_lba + boot_sect->log_sect_per_fat; + root_lba = FAT1_lba + (boot_sect->log_sect_per_fat * boot_sect->num_FAT); + + long root_dir_size = boot_sect->max_root_dir_entries * sizeof(DIR_ENTRY); + data_lba = root_lba + (root_dir_size / boot_sect->bytes_per_sect); +} + +void *FAT_read_sector_offset(uint32_t lba, uint32_t *offset) { + if (offset != NULL) { + lba += (*offset) / boot_sect->bytes_per_sect; + *offset = (*offset) % boot_sect->bytes_per_sect; + } + + return (void*)((long)(FAT_addr) + (long)(lba * boot_sect->bytes_per_sect)); +} + +void *FAT_read_cluster(uint16_t cluster, void *buffer) { + // TODO: perform memcpy + void *addr = FAT_read_sector_offset(data_lba + ((cluster - 2) * boot_sect->sect_per_cluster), NULL); + + uint32_t cluster_size = boot_sect->bytes_per_sect * boot_sect->sect_per_cluster; + + memcpy(buffer, addr, cluster_size); + + return (void*)((uint8_t*)(buffer) + cluster_size); +} + +int FAT_root_dir_next(int index, char *fname_buffer, uint16_t *first_cluster, uint32_t *file_size) { + memset(fname_buffer, 0, sizeof(fname_buffer)); + + while (1) { + // index overflow + if (index >= boot_sect->max_root_dir_entries) { + return -1; + } + + uint32_t offset = index * sizeof(DIR_ENTRY); + void *sect = FAT_read_sector_offset(root_lba, &offset); + DIR_ENTRY *dir_entry = (DIR_ENTRY *)((uint32_t)(sect) + offset); + + // if first character of name is 0, then no subsequent entry is in use + if (dir_entry->name[0] == 0x00) { + return -1; + } + + // deleted file + if (dir_entry->name[0] == 0xE5) { + index++; + continue; + } + + // VFAT LFN entry + if (dir_entry->file_attr == 0x0F && dir_entry->start_of_clusters == 0 && dir_entry->file_size != 0) { + VFAT_LFN_ENTRY *lfn_entry = (VFAT_LFN_ENTRY*)(dir_entry); + + int offset = 13 * ((lfn_entry->seq_num & 0x3F) - 1); + + // read long file name + for (int i = 0; i < 5; i++) { + fname_buffer[offset++] = lfn_entry->part_1[i]; + } + + for (int i = 0; i < 6; i++) { + fname_buffer[offset++] = lfn_entry->part_2[i]; + } + + for (int i = 0; i < 2; i++) { + fname_buffer[offset++] = lfn_entry->part_3[i]; + } + + index++; + continue; + } + + if (index == 0 && (dir_entry->file_attr & 0x08) && dir_entry->file_size == 0) { + // volume label + + } else if ((dir_entry->file_attr & 0x10) && dir_entry->file_size == 0) { + // subdirectory + + } else { + // regular file + + } + + *file_size = dir_entry->file_size; + *first_cluster = dir_entry->start_of_clusters; + + // if no VFAT LFN exists, use DOS name + if (fname_buffer[0] == 0) { + for (int i = 0; i < 8; i++) { + fname_buffer[i] = dir_entry->name[i]; + } + fname_buffer[8] = '.'; + for (int i = 0; i < 3; i++) { + fname_buffer[i + 9] = dir_entry->ext[i]; + } + fname_buffer[12] = 0; + } + + return index + 1; + } +} + +uint16_t FAT_next_cluster(uint16_t cluster) { + // assuming FAT12 + int offset = (cluster >> 1) * 3; + uint8_t *sect = FAT_read_sector_offset(FAT1_lba, &offset); + sect += offset; + + if (cluster & 0x01) { + uint16_t high = (uint16_t)(sect[2]); + uint16_t low = (uint16_t)(sect[1] & 0xF0) >> 4; + return (high << 4) | low; + } else { + uint16_t low = (uint16_t)(sect[0]); + uint16_t high = (uint16_t)(sect[1] & 0x0F) << 8; + return low | high; + } +} +
@@ -0,0 +1,13 @@
+#ifndef FAT_H +#define FAT_H + +#include <stdint.h> + +void *FAT_init(); +void *FAT_read_sector_offset(uint32_t lba, uint32_t *offset); +void *FAT_read_cluster(uint16_t cluster, void *buffer); +uint16_t FAT_next_cluster(uint16_t cluster); +int FAT_root_dir_next(int index, char *fname_buffer, uint16_t *first_cluster, uint32_t *file_size); +void *FAT_find_file(const char *fname); + +#endif
@@ -0,0 +1,26 @@
+OUTPUT_ARCH(i386) +OUTPUT_FORMAT(binary) + +PAGE_SIZE = 1 << 12; + +PART_TABLE_START = 0x00007DBE; + +MEMORY +{ + BOOT_VMA : ORIGIN = 0x00007C00, LENGTH = 0x00001000 + KERNEL_VMA : ORIGIN = 0xC0000000, LENGTH = 0x30000000 +} + +SECTIONS +{ + BOOT : AT(0x0000) + { + */*.o(.mbr) + . = 510; + BYTE(0x55) + BYTE(0xAA) + */*.o(.text) + */*.o(.data) + */*.o(.rodata*) + } >BOOT_VMA +}
@@ -0,0 +1,52 @@
+#include <stdint.h> + +#include "string.h" +#include "fat.h" + +void printc(char c) { + static uint8_t *display = (uint8_t*)(0xB8000); + *(display++) = c; + *(display++) = 0x0F; +} + +void print_string(char *str) { + while (*str != 0) { + printc(*(str++)); + } +} + +int load_kernel() { + FAT_init(); + + int i = 0; + + // first cluster of kernel.bin file + uint16_t first_cluster; + + while (1) { + char buffer[832]; + uint32_t file_size; + + i = FAT_root_dir_next(i, buffer, &first_cluster, &file_size); + + print_string(buffer); + print_string(" "); + if (i <= 0) { return -1; } + + if (!(strcmp(buffer, "kernel.bin"))) { break; } + } + + // copy all clusters + uint16_t cluster = first_cluster; + void *buffer = (void *)(0x100000); + while (1) { + uint8_t *str = (uint8_t*)(0xB8000); + + buffer = FAT_read_cluster(cluster, buffer); + cluster = FAT_next_cluster(cluster); + + if (cluster == 0xFFF || cluster == 0x000) { break; } + } + + return 0; +}
@@ -0,0 +1,89 @@
+.code16 +.section .text +.global find_bootable_part +find_bootable_part: + movw $0x0000, %ax + movw %ax, %ds + + movw $0x0000, %cx + +find_part_loop: + movw $mbr_partition_msg, %si + call print + movw %cx, %ax + call print_hex_int16 + movw $newline, %si + call print + + movw $PART_TABLE_START, %si + + xor %ax, %ax + movb (%si), %al + + cmp $0x80, %al + je find_part_loop_end + + # TODO: loop over partitions + jmp find_part_loop_fail + +find_part_loop_end: + movw $mbr_bootable_msg, %si + call print + movw %cx, %ax + call print_hex_int16 + movw $newline, %si + call print + + # load partition size from MBR + movw $PART_TABLE_START, %si + add $0x0C, %si + + movw (%si), %cx + + movw $mbr_size_msg, %si + call print + movw %cx, %ax + call print_hex_int16 + movw $newline, %si + call print + + # load partition start from MBR + movw $PART_TABLE_START, %si + add $0x08, %si + + movw (%si), %ax + + movw $mbr_start_msg, %si + call print + call print_hex_int16 + movw $newline, %si + call print + + add %ax, %cx + + ret + +find_part_loop_fail: + jmp error + +.section .data +mbr_partition_msg: + .ascii " Checking partition 0x" + .byte + +mbr_bootable_msg: + .ascii " bootable partition found: 0x" + .byte 0 + +mbr_start_msg: + .ascii " Start sector: 0x" + .byte 0 + +mbr_size_msg: + .ascii " Number of sectors: 0x" + .byte 0 + +newline: + .byte 13 + .byte 10 + .byte 0
@@ -0,0 +1,35 @@
+#include "string.h" + +#include <stdint.h> + +void *memset(void *ptr, uint8_t value, uint32_t num) { + for (uint32_t i = 0; i < num; i++) { + ((uint8_t*)ptr)[i] = value; + } + return ptr; +} + +int strcmp(const char *str1, const char *str2) { + int i = 0; + + while (1) { + if (str1[i] != str2[i]) { + return str1[i] - str2[i]; + } + + if (str1[i] == 0) { + return 0; + } + + i++; + } +} + +void *memcpy(void *_dest, const void *_src, uint32_t n) { + uint8_t *src = (uint8_t*)(_src); + uint8_t *dest = (uint8_t*)(_dest); + + for (int i = 0; i < n; i++) { + dest[i] = src[i]; + } +}
@@ -0,0 +1,12 @@
+#ifndef STRING_H +#define STRING_H + +#include <stdint.h> + +#define NULL (void*)(0) + +void *memset(void *ptr, uint8_t value, uint32_t num); +int strcmp(const char *str1, const char *str2); +void *memcpy(void *dest, const void * src, uint32_t n); + +#endif
@@ -125,6 +125,9 @@ while (*fmt) {
if (state == STATE_ARGUMENT && *fmt == 'X') { printk_uint32(va_arg(args, uint32_t)); state = STATE_DEFAULT; + } else if (state == STATE_ARGUMENT && *fmt == 'x') { + printk_uint32(va_arg(args, uint32_t)); + state = STATE_DEFAULT; } else if (state == STATE_ARGUMENT && *fmt == 'i') { printk_int(va_arg(args, int)); state = STATE_DEFAULT;@@ -157,6 +160,7 @@ crit_exit();
} void kpanic(const char* string) { + cli(); printk(string); core_con->write_c('\n'); // register dump / stack dump
@@ -22,6 +22,12 @@ #define PS2_FAILURE 0xFC
#define BUFFER_LENGTH (128) +#ifdef DEBUG +#define PRINT_DBG(...) printk("[" __FILE__ "] " __VA_ARGS__) +#else +#define PRINT_DBG(...) {} +#endif + /*! * Initializes the PS/2 keyboard. * \return 1 on success, 0 on fail@@ -98,6 +104,7 @@ }
uint8_t ps2_kb_read(void) { while (buffer_empty()) { + PRINT_DBG("yield.\n"); sched_yield(); }
@@ -112,8 +112,13 @@ return 1;
} void vga_con_write_c(const char c) { - write_char(c); - set_cursor(line, column); + if (c == 0x08) { + vga_con_backspace(); + set_cursor(line, column); + } else { + write_char(c); + set_cursor(line, column); + } } void vga_con_write_n(const char *string, uint32_t num) {
@@ -2,7 +2,16 @@ #include <stdint.h>
#include "cedos/elf.h" #include "cedos/core.h" +#include "cedos/fat.h" +#include "cedos/sched/process.h" + #include "assert.h" + +#ifdef DEBUG +#define PRINT_DBG(...) printk("[" __FILE__ "] " __VA_ARGS__) +#else +#define PRINT_DBG(...) {} +#endif typedef struct { uint8_t e_ident[16];@@ -57,38 +66,38 @@
void elf_infodump(VIRT_ADDR elf_pointer, uint32_t size) { ELF_HEADER *header = (ELF_HEADER*)elf_pointer; - printk("Reading ELF file from location %p of length %i\n", elf_pointer, size); - printk("\n"); + PRINT_DBG("Reading ELF file from location %p of length %i\n", elf_pointer, size); + PRINT_DBG("\n"); - printk("ELF header size: %i\n", sizeof(ELF_HEADER)); + PRINT_DBG("ELF header size: %i\n", sizeof(ELF_HEADER)); assert(sizeof(ELF_HEADER) == 52); - printk("\n"); + PRINT_DBG("\n"); - printk("ELF header hexdump:\n"); + PRINT_DBG("ELF header hexdump:\n"); memdump(elf_pointer, 52); - printk("\n"); + PRINT_DBG("\n"); - printk("ELF header magic number:\n"); - printk("%s\n", &(header->e_ident)); - printk("\n"); + PRINT_DBG("ELF header magic number:\n"); + PRINT_DBG("%s\n", &(header->e_ident)); + PRINT_DBG("\n"); - printk("ELF header infodump:\n"); - printk("- machine: %i\n", header->machine); - printk("- version: %i\n", header->version); - printk("- entry: %p\n", header->entry); - printk("\n"); - printk("- program headers:\n"); - printk(" - offset: %i\n", header->proghead_offset); - printk(" - entries: %i\n", header->ph_num); - printk(" - entry size: %i\n", header->ph_entry_size); - printk("\n"); - printk("- section headers:\n"); - printk(" - offset: %i\n", header->secthead_offset); - printk(" - entries: %i\n", header->sh_num); - printk(" - entry size: %i\n", header->sh_entry_size); - printk("\n"); + PRINT_DBG("ELF header infodump:\n"); + PRINT_DBG("- machine: %i\n", header->machine); + PRINT_DBG("- version: %i\n", header->version); + PRINT_DBG("- entry: %p\n", header->entry); + PRINT_DBG("\n"); + PRINT_DBG("- program headers:\n"); + PRINT_DBG(" - offset: %i\n", header->proghead_offset); + PRINT_DBG(" - entries: %i\n", header->ph_num); + PRINT_DBG(" - entry size: %i\n", header->ph_entry_size); + PRINT_DBG("\n"); + PRINT_DBG("- section headers:\n"); + PRINT_DBG(" - offset: %i\n", header->secthead_offset); + PRINT_DBG(" - entries: %i\n", header->sh_num); + PRINT_DBG(" - entry size: %i\n", header->sh_entry_size); + PRINT_DBG("\n"); - printk("Enumerating sections:\n"); + PRINT_DBG("Enumerating sections:\n"); int sh_offset = header->secthead_offset; SECT_HEADER *sect_headers = (SECT_HEADER*)(elf_pointer + sh_offset);@@ -105,76 +114,79 @@ for (int i = 0; i < num_sections; i++) {
SECT_HEADER sh = sect_headers[i]; char *name = (char*)(sect_names_addr + sh.name); - printk("Section: %s\n", name); - printk("- type: %i\n", sh.type); - printk("- offset: %i\n", sh.offset); - printk("- size: %i\n", sh.size); - printk("- addr: %i\n", sh.addr); - printk("- addr_align: %i\n", sh.addr_align); - printk("\n"); + PRINT_DBG("Section: %s\n", name); + PRINT_DBG("- type: %i\n", sh.type); + PRINT_DBG("- offset: %i\n", sh.offset); + PRINT_DBG("- size: %i\n", sh.size); + PRINT_DBG("- addr: %i\n", sh.addr); + PRINT_DBG("- addr_align: %i\n", sh.addr_align); + PRINT_DBG("\n"); } } -PROCESS_ID elf_exec(VIRT_ADDR elf_pointer, uint32_t size, char *name, char *args) { - printk("Creating process %s...", name); - PROCESS_ID pid = sched_create(name, args); - printk("done, PID: %i.\n", pid); +PROCESS_ID elf_exec(const char *fname, char *args) { + PRINT_DBG("Loading ELF executable \"%s\".\n", fname); + VIRT_ADDR elf_addr = (VIRT_ADDR*)(0xA0000000); + // TODO: needs to change when we have other file systems + int fd = FAT_openat(0, fname, 0); + assert(fd != -1); + int size = FAT_read(fd, elf_addr, 0); + assert(size != 0); - ELF_HEADER *header = (ELF_HEADER*)elf_pointer; + ELF_HEADER *header = (ELF_HEADER*)(elf_addr); // magic number correct - assert(((uint32_t*)(elf_pointer))[0] == 0x464C457F); + assert(((uint32_t*)(elf_addr))[0] == 0x464C457F); // header size correct assert(sizeof(ELF_HEADER) == 52); // get section table int sh_offset = header->secthead_offset; - SECT_HEADER *sect_headers = (SECT_HEADER*)(elf_pointer + sh_offset); + SECT_HEADER *sect_headers = (SECT_HEADER*)(elf_addr + sh_offset); int num_sections = header->sh_num; int section_size = header->sh_entry_size; SECT_HEADER sect_names_sh = sect_headers[header->sh_strndx]; - VIRT_ADDR sect_names_addr = elf_pointer + sect_names_sh.offset; + VIRT_ADDR sect_names_addr = elf_addr + sect_names_sh.offset; assert(sizeof(SECT_HEADER) == section_size); // go through all sections and copy/allocate memory as necessary - printk("Enumerating %i sections:\n", num_sections); + PRINT_DBG("Enumerating %i sections:\n", num_sections); for (int i = 0; i < num_sections; i++) { SECT_HEADER sh = sect_headers[i]; char *name = (char*)(sect_names_addr + sh.name); if ((sh.flags & SHF_ALLOC) && (sh.flags & SHF_EXECINSTR)) { - VIRT_ADDR lma = elf_pointer + sh.offset; + VIRT_ADDR lma = elf_addr + sh.offset; VIRT_ADDR vma = sh.addr; uint32_t size = sh.size; - printk("%p\n", sh.flags); - printk("Copying code section %s to its destination ", name); - printk("(LMA: %p, VMA: %p)\n", lma, vma); + PRINT_DBG("%p\n", sh.flags); + PRINT_DBG("Copying code section %s to its destination ", name); + PRINT_DBG("(LMA: %p, VMA: %p)\n", lma, vma); - sched_copyto(pid, lma, size, vma); + memcpy(vma, lma, size); } else if (sh.flags & SHF_ALLOC) { - VIRT_ADDR lma = elf_pointer + sh.offset; + VIRT_ADDR lma = elf_addr + sh.offset; VIRT_ADDR vma = sh.addr; - printk("Allocating space for section %s ", name); - printk("(LMA: %p, VMA: %p)\n", lma, vma); + PRINT_DBG("Allocating space for section %s ", name); + PRINT_DBG("(LMA: %p, VMA: %p)\n", lma, vma); /* TODO: alloc */ } else { - printk("Skipping section %s\n", name); + PRINT_DBG("Skipping section %s\n", name); } } - printk("\n"); + PRINT_DBG("\n"); - printk("Entry point: %p\n", header->entry); - printk("Starting process %i...", pid); + PRINT_DBG("Entry point: %p\n", header->entry); - sched_exec(pid, header->entry); - - printk("done.\n"); + // enter the process + PROCESS_MAIN *entry = header->entry; + entry(args); return 0; }
@@ -0,0 +1,220 @@
+#include "cedos/fat.h" +#include "string.h" +#include <stdint.h> + +typedef struct { + char jmp[3]; + char oemname[8]; + + uint16_t bytes_per_sect; + uint8_t sect_per_cluster; + uint16_t num_reserved_sectors; + uint8_t num_FAT; + uint16_t max_root_dir_entries; + uint16_t total_log_sectors; + uint8_t media_desc; + uint16_t log_sect_per_fat; +} __attribute__((packed)) BOOT_SECT; + +typedef struct { + char name[8]; + char ext[3]; + uint8_t file_attr; + uint8_t user_attr; + uint8_t del_char; + uint16_t create_time; + uint16_t create_date; + uint16_t last_access_date; + uint16_t access_rights; + uint16_t last_modified_time; + uint16_t last_modified_date; + uint16_t start_of_clusters; + uint32_t file_size; +} __attribute__((packed)) DIR_ENTRY; + +typedef struct { + uint8_t seq_num; + uint16_t part_1[5]; + uint8_t file_attr; + uint8_t user_attr; + uint8_t del_char; + uint16_t part_2[6]; + uint16_t start_of_clusters; + uint16_t part_3[2]; +} __attribute__((packed)) VFAT_LFN_ENTRY; + + +void *FAT_addr; +BOOT_SECT *boot_sect; + +uint32_t FAT1_lba; +uint32_t FAT2_lba; +uint32_t root_lba; +uint32_t data_lba; + +void *FAT_init() { + const int sector_size = 512; + const int sector_num = 128; + const int part_size = sector_size * sector_num; + + // open image file + FAT_addr = (void*)(0x10000); + + boot_sect = (BOOT_SECT*)(FAT_addr); + + FAT1_lba = boot_sect->num_reserved_sectors; + FAT2_lba = FAT1_lba + boot_sect->log_sect_per_fat; + root_lba = FAT1_lba + (boot_sect->log_sect_per_fat * boot_sect->num_FAT); + + long root_dir_size = boot_sect->max_root_dir_entries * sizeof(DIR_ENTRY); + data_lba = root_lba + (root_dir_size / boot_sect->bytes_per_sect); +} + +void *FAT_read_sector_offset(uint32_t lba, uint32_t *offset) { + if (offset != NULL) { + lba += (*offset) / boot_sect->bytes_per_sect; + *offset = (*offset) % boot_sect->bytes_per_sect; + } + + return (void*)((long)(FAT_addr) + (long)(lba * boot_sect->bytes_per_sect)); +} + +void *FAT_read_cluster(uint16_t cluster, void *buffer) { + // TODO: perform memcpy + void *addr = FAT_read_sector_offset(data_lba + ((cluster - 2) * boot_sect->sect_per_cluster), NULL); + + uint32_t cluster_size = boot_sect->bytes_per_sect * boot_sect->sect_per_cluster; + + memcpy(buffer, addr, cluster_size); + + return (void*)((uint8_t*)(buffer) + cluster_size); +} + +int FAT_root_dir_next(int index, char *fname_buffer, uint16_t *first_cluster, uint32_t *file_size) { + memset(fname_buffer, 0, sizeof(fname_buffer)); + + while (1) { + // index overflow + if (index >= boot_sect->max_root_dir_entries) { + return -1; + } + + uint32_t offset = index * sizeof(DIR_ENTRY); + void *sect = FAT_read_sector_offset(root_lba, &offset); + DIR_ENTRY *dir_entry = (DIR_ENTRY *)((uint32_t)(sect) + offset); + + // if first character of name is 0, then no subsequent entry is in use + if (dir_entry->name[0] == 0x00) { + return -1; + } + + // deleted file + if (dir_entry->name[0] == 0xE5) { + index++; + continue; + } + + // VFAT LFN entry + if (dir_entry->file_attr == 0x0F && dir_entry->start_of_clusters == 0 && dir_entry->file_size != 0) { + VFAT_LFN_ENTRY *lfn_entry = (VFAT_LFN_ENTRY*)(dir_entry); + + int offset = 13 * ((lfn_entry->seq_num & 0x3F) - 1); + + // read long file name + for (int i = 0; i < 5; i++) { + fname_buffer[offset++] = lfn_entry->part_1[i]; + } + + for (int i = 0; i < 6; i++) { + fname_buffer[offset++] = lfn_entry->part_2[i]; + } + + for (int i = 0; i < 2; i++) { + fname_buffer[offset++] = lfn_entry->part_3[i]; + } + + index++; + continue; + } + + if (index == 0 && (dir_entry->file_attr & 0x08) && dir_entry->file_size == 0) { + // volume label + + } else if ((dir_entry->file_attr & 0x10) && dir_entry->file_size == 0) { + // subdirectory + + } else { + // regular file + + } + + *file_size = dir_entry->file_size; + *first_cluster = dir_entry->start_of_clusters; + + // if no VFAT LFN exists, use DOS name + if (fname_buffer[0] == 0) { + for (int i = 0; i < 8; i++) { + fname_buffer[i] = dir_entry->name[i]; + } + fname_buffer[8] = '.'; + for (int i = 0; i < 3; i++) { + fname_buffer[i + 9] = dir_entry->ext[i]; + } + fname_buffer[12] = 0; + } + + return index + 1; + } +} + +uint16_t FAT_next_cluster(uint16_t cluster) { + // assuming FAT12 + int offset = (cluster >> 1) * 3; + uint8_t *sect = FAT_read_sector_offset(FAT1_lba, &offset); + sect += offset; + + if (cluster & 0x01) { + uint16_t high = (uint16_t)(sect[2]); + uint16_t low = (uint16_t)(sect[1] & 0xF0) >> 4; + return (high << 4) | low; + } else { + uint16_t low = (uint16_t)(sect[0]); + uint16_t high = (uint16_t)(sect[1] & 0x0F) << 8; + return low | high; + } +} + +int FAT_openat(int fd, const char *fname, int flags) { + int i = 0; + + // TODO: take fd into consideration (open file in that subdirectory) + + uint16_t first_cluster; + while (1) { + char buffer[832]; + uint32_t file_size; + + i = FAT_root_dir_next(i, buffer, &first_cluster, &file_size); + if (i <= 0) { return -1; } + + if (strcmp(buffer, fname) == 0) { + // file found + return first_cluster; + } + } +} + +uint32_t FAT_read(int fd, void *buffer, int count) { + uint16_t cluster = fd; + uint32_t size = 0; + + while (1) { + buffer = FAT_read_cluster(cluster, buffer); + cluster = FAT_next_cluster(cluster); + size += boot_sect->bytes_per_sect * boot_sect->sect_per_cluster; + + if (cluster == 0xFFF || cluster == 0x000) { break; } + } + + return size; +}
@@ -4,15 +4,17 @@ #include "cedos/drivers/console.h"
#include "cedos/drivers/keyboard.h" int file_read(int fd, char *buffer, uint32_t size) { - for (int i = 0; i < size; i++) { + int i = 0; + while (i < size) { char table[] = { - 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\\', '´', 0x08, + '^', 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\\', '´', 0x08, '\t', 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü', '+', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', '#', 0, '<', 'y', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-'}; uint32_t scancode = std_kb->read(); char c = scancode >= 0 && scancode <= 60 ? table[scancode] : 0; - buffer[i] = c; + if (c == 0) { continue; } + buffer[i++] = c; } }
@@ -0,0 +1,26 @@
+OUTPUT_ARCH(i386) +OUTPUT_FORMAT(binary) + +PAGE_SIZE = 1 << 12; + +MEMORY +{ + KERNEL_VMA : ORIGIN = 0xC0000000, LENGTH = 0x30000000 +} + +SECTIONS +{ + KERNEL : AT(0x4E00) + { + */*(.text) + */*(.data) + */*(.rodata*) + + } >KERNEL_VMA +} + +__KERNEL_LMA = LOADADDR(KERNEL); +__KERNEL_VMA = ADDR(KERNEL); +__KERNEL_SIZE = SIZEOF(KERNEL); + +__KERNEL_STACK_ADDR = 0xC0400000;
@@ -14,8 +14,17 @@ #include "cedos/core.h"
#include "cedos/elf.h" +#include "cedos/fat.h" + #include "linker.h" #include "assert.h" +#include "string.h" + +#ifdef DEBUG +#define PRINT_DBG(...) printk("[" __FILE__ "] " __VA_ARGS__) +#else +#define PRINT_DBG(...) {} +#endif int os_init(void) { core_init();@@ -134,13 +143,44 @@
int os_main(void) { infodump(); + FAT_init(); + + int i = 0; + + while (1) { + char buffer[832]; + uint16_t first_cluster; + uint32_t file_size; + + i = FAT_root_dir_next(i, buffer, &first_cluster, &file_size); + if (i <= 0) { break; } + + PRINT_DBG("%s (start: %i, size: %i)\n", buffer, first_cluster, file_size); + + uint16_t cluster = first_cluster; + + if (cluster == 0xFFF || cluster == 0x000) { continue; } + + PRINT_DBG(" clusters: \n"); + while (1) { + PRINT_DBG(" %x\n", cluster); + + //char *sect = FAT_read_cluster(cluster); + //hexdump(sect, 512 * 8); + + cluster = FAT_next_cluster(cluster); + if (cluster == 0xFFF || cluster == 0x000) { break; } + } + } + // create test tasks printk("Creating tasks.\n"); - printk("Loading ELF executable.\n"); - elf_exec(SS_VMA + (ELF_LMA - SS_LMA), ELF_SIZE, "app1", "Hello World!"); - elf_exec(SS_VMA + (ELF_LMA - SS_LMA), ELF_SIZE, "app2", "Hello World!"); - elf_exec(SS_VMA + (ELF_LMA - SS_LMA), ELF_SIZE, "app3", "Hello World!"); + + int pid = sched_spawn("shell.o", "Hello World!"); + assert(pid != -1); + //sched_spawn("fibonacci.o", "Hello World!"); + //sched_spawn("fibonacci.o", "Hello World!"); printk("Starting scheduler.\n"); sched_start();
@@ -19,8 +19,8 @@ > $(MKDIR) $(DIRS)
.PHONY: build build: folder -$(GLOBAL_BUILD)/kernel.o: $(OBJECTS) | folder -> $(LD) $^ -r -o $@ --oformat elf32-i386 +$(GLOBAL_BUILD)/kernel.bin: $(OBJECTS) | folder +> $(LD) $^ -o $@ -T link.txt -Map=$(LOG_DIR)/kernel_mapfile.txt .PHONY: folder folder:
@@ -26,6 +26,12 @@ #define PAGE_DIR_ALT_MAPPED_ADDR \
((PAGE_DIR_ENTRY*)(PAGE_TABLE_ALT_MAPPED_ADDR(PAGE_ENTRY_COUNT - 1))) #define PAGE_TABLE_FLAGS 0b000000000011 + +#ifdef DEBUG +#define PRINT_DBG(...) printk("[" __FILE__ "] " __VA_ARGS__) +#else +#define PRINT_DBG(...) {} +#endif __attribute__((always_inline)) inline int is_present(uint32_t entry) { return (entry & 0b000000000001);@@ -120,7 +126,7 @@
uint32_t offset = ((uint32_t)dest % PAGE_SIZE); uint32_t part_length = (offset + length <= PAGE_SIZE) ? length : PAGE_SIZE - offset; - printk("src=%p dest=%p length=%i offset=%i plen=%i\n", src, dest, length, offset, part_length); + PRINT_DBG("src=%p dest=%p length=%i offset=%i plen=%i\n", src, dest, length, offset, part_length); for (uint32_t i = 0; i < part_length; i++) { ((uint8_t*)mount_dest)[offset + i] = ((uint8_t*)src)[i];@@ -196,7 +202,7 @@ EXCEPTION(page_fault_isr, frame, error_code) {
volatile VIRT_ADDR faulty_addr; __asm__ volatile ("mov %%cr2, %0" : "=a" (faulty_addr)); //if (PAGE_DIR_INDEX(faulty_addr) >= PAGE_ENTRY_COUNT - 2) { return; } - printk("PAGE FAULT: %X\n", faulty_addr); + PRINT_DBG("PAGE FAULT: %X\n", faulty_addr); PHYS_ADDR new_page = get_free_page(); force_map_page_to_this(new_page, PAGE_DIR_INDEX(faulty_addr), PAGE_TABLE_INDEX(faulty_addr), PAGE_TABLE_FLAGS); // dump registers to stdout
@@ -11,13 +11,21 @@ #include "cedos/core.h"
#include "cedos/interrupts.h" #include "cedos/pit.h" #include "cedos/pic.h" +#include "cedos/elf.h" #include "assembly.h" +#include "assert.h" #define KERNEL_PRIVATE_STACK (void*)(0xC0600000) #define USER_STACK (void*)(0xC0000000) #define PROCESS_STD_EFLAGS (0x00000286) + +#ifdef DEBUG +#define PRINT_DBG(...) printk("[" __FILE__ "] " __VA_ARGS__) +#else +#define PRINT_DBG(...) {} +#endif PROCESS* get_slot(void) { static PROCESS free_slots[8];@@ -34,12 +42,23 @@
int sched_dispatcher(void); +void entry_idle(char *args) { + while (1) { + + } +} + /*! - * Creates a new process and returns its process ID. + * Spawn a new process and returns its process ID. */ -PROCESS_ID sched_create(const char *name, char *args) { +PROCESS_ID sched_spawn(const char *name, char *args) { crit_enter(); + if (name != NULL) { + int fd = FAT_openat(0, name, 0); + if (fd == -1) { return -1; } + } + PHYS_ADDR page_dir = create_empty_page_dir(); // set process context@@ -50,7 +69,6 @@ p->ebp = USER_STACK;
p->esp = USER_STACK - sizeof(SCHED_FRAME); p->eflags = PROCESS_STD_EFLAGS; p->entry = 0xDEADBEEF; - p->state = PSTATE_CREATED; // TODO: implement with malloc strcpy(p->name_buf, name);@@ -60,40 +78,7 @@ p->name = &(p->name_buf);
p->args = &(p->args_buf); PROCESS_ID pid = add_process(p, current_pid); - - return pid; -} - - -/*! - * Copies a piece of memory into the memory space of some process. - */ -int sched_copyto(PROCESS_ID pid, VIRT_ADDR src, uint32_t length, VIRT_ADDR dest) { - crit_enter(); - - PROCESS* p = get_process(pid); - PHYS_ADDR page_dir = p->page_dir; - - copy_to_pdir(src, length, page_dir, dest); - - crit_exit(); - - return 0; -} - - -/*! - * Executes the (already created) task with the given process ID. - */ -int sched_exec(PROCESS_ID pid, PROCESS_MAIN *entry) { - crit_enter(); - - PROCESS* p = get_process(pid); - - if (p->state != PSTATE_CREATED) { - kpanic("Process executed multiple times after creation!"); - return -1; - } + p->id = pid; // setup stack static SCHED_FRAME frame;@@ -102,8 +87,13 @@ frame.esi = frame.edi = 0;
frame.ebp = p->ebp; frame.esp = p->esp; frame.eflags = p->eflags; - frame.eip = sched_dispatcher; frame.cs = 0x8; + + if (name == NULL) { + frame.eip = entry_idle; + } else { + frame.eip = sched_dispatcher; + } // load stack copy_to_pdir(&frame, sizeof(frame), p->page_dir, p->esp);@@ -114,10 +104,11 @@
/* TODO: check if code exists at entry point */ // start the process - p->entry = entry; p->state = PSTATE_READY; crit_exit(); + + return pid; }@@ -131,12 +122,21 @@ current->ebp = ebp;
current->eip = frame->eip; current->eflags = frame->eflags; + + // save stack checksum stack_compute_checksum(&(current->checksum), current->esp, current->ebp); } + PRINT_DBG("esp: %p\n", current->esp); + PRINT_DBG("ebp: %p\n", current->ebp); + PRINT_DBG("eip: %p\n", current->eip); + PRINT_DBG("eflags: %p\n", current->eflags); + // select next process + PRINT_DBG("exiting %i, ", current_pid); current_pid = next_schedule(current_pid); + PRINT_DBG("entering %i\n", current_pid); // unblock all blocked processes for (PROCESS *p = get_first_process(); p != NULL; p = p->next) {@@ -164,7 +164,7 @@ frame = (volatile SCHED_FRAME*)(next->esp);
ebp = next->ebp; //frame->cs = 0x08; //frame->eip = next->eip; - //frame->eflags = next->eflags; + frame->eflags = next->eflags; frame->esp = next->esp; frame->ebp = next->ebp;@@ -175,12 +175,6 @@
pic1_eoi(); } -void entry_idle(char *args) { - while (1) { - //printk("idle.\n"); - } -} - extern void* sched_interrupt; int sched_init(void) {@@ -190,15 +184,15 @@
current_pid = 0; // create idle process - PROCESS_ID idle = sched_create("idle", NULL); - sched_exec(idle, entry_idle); + PROCESS_ID idle = sched_spawn(NULL, NULL); + assert(idle != -1); return 1; } void sched_yield(void) { crit_enter(); - //printk("yield.\n"); + //PRINT_DBG("yield.\n"); PROCESS *current = get_process(current_pid); if (current != NULL && current->state != PSTATE_TERMINATED) { current->state = PSTATE_READY;@@ -206,6 +200,7 @@ //current->state = PSTATE_RUNNING;
} uint32_t csc = crit_stash(); + sti(); INT(0x20); crit_restore(csc);@@ -239,6 +234,19 @@ crit_exit();
return success; } +void sched_wait(PROCESS_ID pid) { + assert(pid != current_pid); + + if (pid < 0) { return; } + + while (1) { + PROCESS *p = get_process(pid); + if (p->state == PSTATE_TERMINATED) { break; } + + sched_yield(); + } +} + int sched_start(void) { current_pid = 0;@@ -257,18 +265,18 @@ pic_mask_interrupt(0);
} int sched_dispatcher(void) { - //printk("Dispatching process %i...\n", current_pid); + PRINT_DBG("Dispatching process %i...\n", current_pid); PROCESS* this = get_process(current_pid); - PROCESS_MAIN* entry = this->entry; + // enter the actual program - entry(this->args); + elf_exec(this->name, this->args); - //printk("Process %i terminated.\n", current_pid); + PRINT_DBG("Process %i terminated.\n", current_pid); sched_kill(current_pid); // just for absolute safety - while (1); + kpanic("Executing a terminated process!!\n"); }
@@ -5,16 +5,10 @@
PROCESS_ID next_schedule(PROCESS_ID current) { PROCESS* process = get_process(current); - if (process != NULL && process->next != NULL && process->state == PSTATE_READY) { + if (process != NULL && process->next != NULL && process->next->state != PSTATE_TERMINATED) { return process->next->id; } else { PROCESS *first = get_first_process(); - if (first != NULL && first->id != 0 && first->state == PSTATE_READY) { - return first->id; - } else if (first != NULL && first->next != NULL && first->next->state == PSTATE_READY) { - return first->next->id; - } else { - return 0; - } + return first->id; } }
@@ -34,4 +34,20 @@ unsigned int strlen (const char *str) {
int i = 0; while (str[i]) { i++; } return i; +} + +int strcmp(const char *str1, const char *str2) { + int i = 0; + + while (1) { + if (str1[i] != str2[i]) { + return str1[i] - str2[i]; + } + + if (str1[i] == 0) { + return 0; + } + + i++; + } }
@@ -15,7 +15,9 @@ void* SYSCALL_TABLE[] = {
file_read, file_write, sched_yield, - get_current_process + get_current_process, + sched_spawn, + sched_wait }; extern void syscall_interrupt(void);
@@ -13,6 +13,8 @@ mov (%ecx, %eax, 4), %eax
call *%eax + mov %eax, (%esi) + // restore stack add $12, %esp iret
@@ -1,15 +0,0 @@
-.RECIPEPREFIX = > - -LOCAL_BUILD = $(GLOBAL_BUILD)/stage1 - -OBJECTS := $(GLOBAL_BUILD)/stage1.o -DIRS := $(sort $(dir $(OBJECTS))) - -$(OBJECTS): | $(DIRS) -$(DIRS): -> $(MKDIR) $(DIRS) - -.PHONY: build -build: $(OBJECTS) -$(GLOBAL_BUILD)/stage1.o: stage1.s -> $(AS) -o $@ $<
@@ -1,224 +0,0 @@
-.section .text -.code16 - - # disable interrupts - cli - - # canonicalize %CS:%EIP to a known value - ljmp $0, $start -start: - - # setup segments - movw $0x0000, %ax - movw %ax, %ss - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - - # setup stack - movw $0x9000, %sp - movw %sp, %bp - - # select display page 0 - movb $0, %al - movb $0x05, %ah - int $0x10 - - # check if A20 gate is enabled - mov $a20_msg, %si - call print - call checkA20 - je disabled -enabled: - call print_done - jmp resume -disabled: - call print_fail - jmp disabled -resume: - - - # TODO: - # - activate A20 gate - - # reset bootdrive - mov $10, %cx -reset: - push %cx - movw $reset_msg, %si - call print - movw $bootdrive_msg, %si - call print - - movb $0x00, %ah - int $0x13 - pop %cx - jnc reset_end - loop reset - jc error -reset_end: - - movw $done_msg, %si - call print - - # load second stage into memory starting at adress 0x10000 - # (NOTE: this code can only be jumped to after loading the global descriptor table - # because it uses absolute adresses larger than 16 bit) - # (NOTE2: this routine only loads 0x48 sectors of the second stage into memory - # and is in general pretty whacky. should be replaced with sth more serious) - mov $10, %cx -load: - push %cx - movw $load_msg, %si - call print - - movw $0x0000, %bx # buffer address - movw $0x1000, %ax - movw %ax, %es # buffer address (segment) - movb $0x02, %ah # function 0x02: read a sector - movb $0x048, %al # sectors to read count - movb $0x00, %ch # cylinder - movb $0x02, %cl # sector - movb $0x00, %dh # head - # dl (drive) keep as is - int $0x13 - pop %cx - jnc load_end - loop load - jc error -load_end: - - movw $done_msg, %si - call print - - movw $gdt_msg, %si - call print - - # - load global descriptor table and far jump into protected mode - lgdt (GDT_DESCRIPTOR) - - movw $done_msg, %si - call print - - lidt (IDT_DESCRIPTOR) - - mov %cr0, %eax - or $1, %eax - mov %eax, %cr0 - - ljmp $0x8, $protected - -.code32 -protected: - # setup registers with appropriate GDT values - mov $0x10, %eax - mov %eax, %ds - mov %eax, %es - mov %eax, %fs - mov %eax, %gs - mov %eax, %ss - - # jump to second stage code - ljmp $0x08, $__SS_START - -.code16 -error: - movw $fail_msg, %si - call print -error_loop: - jmp error_loop - - # ############################################ - # print - # prints out a string on the screen - # %si: points to the message to be printed - # ############################################ -print: - movw $0x0000, %bx - movb $0x0E, %ah - -print_loop: - lodsb - or %al, %al - jz print_end - int $0x10 - jmp print_loop -print_end: - ret - -print_done: - mov $done_msg, %si - jmp print - -print_fail: - mov $fail_msg, %si - jmp print - - # ############################################ - # checkA20 - # checks if A20 line is enabled - # equal flag: * clear, if A20 is enabled - # * set, if A20 is disabled - # ############################################ -checkA20: - push %ds - push %es - push %si - push %di - - mov $0x0000, %ax - mov %ax, %ds - mov $0xFFFF, %ax - mov %ax, %es - - mov $0x7DFE, %si - mov $0x7E0E, %di - - movw %ds:(%si), %cx - movw %es:(%di), %dx - cmp %cx, %dx - - pop %di - pop %si - pop %es - pop %ds - ret - -a20_msg: - .ascii "Enabling A20..." - .byte 0 - -reset_msg: - .ascii "Resett" - .byte 0 - -load_msg: - .ascii "Load" - -bootdrive_msg: - .ascii "ing bootdrive..." - .byte 0 - -gdt_msg: - .ascii "Setting GDT..." - .byte 0 - -done_msg: - .ascii "done" - .byte 13 - .byte 10 - .byte 0 - -fail_msg: - .ascii "fail" - .byte 13 - .byte 10 - .byte 0 - -GDT_DESCRIPTOR: - .word 0x23 - .int GDT - -IDT_DESCRIPTOR: - .word 0 - .int 0
@@ -1,24 +0,0 @@
-.section .text -.global __SS_START -__SS_START: - # copy the kernel code to 0x00100000 - call copy_kernel - - # create a page directory for the kernel that maps it to 0xC0000000 - # and identity maps the first 1M of memory - call create_kernel_environment - - # load kernel page directory - movl %eax, %cr3 - - # set paging enable and protection bit - movl %cr0, %eax - or $0x80000010, %eax - movl %eax, %cr0 - - # jump to kernel code - ljmp $8, $__KERNEL_START - - # loop until the heat death of the universe -loop: - jmp loop
@@ -1,16 +0,0 @@
-OUTPUT_FORMAT(elf32-i386) -OUTPUT_ARCH(i386) -ENTRY(_ss_start) - -SECTIONS -{ - .text : - { - *.*(.text) - } - - .data : - { - *.*(.data) - } -}
@@ -6,10 +6,6 @@ #define LINKER_H
#include <stdint.h> -extern uint8_t __SS_VMA; -extern uint8_t __SS_LMA; -extern uint8_t __SS_SIZE; - extern uint8_t __KERNEL_VMA; extern uint8_t __KERNEL_LMA; extern uint8_t __KERNEL_SIZE;@@ -17,10 +13,6 @@
extern uint8_t __APP_VMA; extern uint8_t __APP_LMA; extern uint8_t __APP_SIZE; - -#define SS_VMA (&__SS_VMA) -#define SS_LMA (&__SS_LMA) -#define SS_SIZE (uint32_t)(&__SS_SIZE) #define KERNEL_VMA (&__KERNEL_VMA) #define KERNEL_LMA (&__KERNEL_LMA)
@@ -1,47 +0,0 @@
-#include "linker.h" -#include "paging.h" - -/* -#define VGA_TEXTMODE_COLUMNS 80 -#define VGA_TEXTMODE_LINES 25 -#define VGA_TEXTMODE_CELLS (VGA_TEXTMODE_COLUMNS * VGA_TEXTMODE_LINES) - -#define VGA_TEXT_COLOR 0x02 - -uint8_t const *display_start = (uint8_t*)0xB8000; -uint8_t *display = (uint8_t*)0xB8000; - -void simple_clear(void) { - display = (uint8_t*)display_start; - - for (int i = 0; i < VGA_TEXTMODE_CELLS; i++) { - display[2 * i] = 0x00; - display[2 * i + 1] = 0x00; - } -} - -void simple_print(const char *src) { - while (*src) { - *display++ = *src++; - *display++ = VGA_TEXT_COLOR; - } -} - -void simple_println(const char *src) { - simple_print(src); - - while ((display - display_start) % (2 * VGA_TEXTMODE_COLUMNS)) { - display++; - display++; - } -} -*/ - -void copy_kernel(void) { - uint8_t *kernel_dest = (uint8_t*)0x00100000; - uint8_t *kernel_src = (SS_VMA + (KERNEL_LMA - SS_LMA)); - - for (uint32_t i = 0; i < KERNEL_SIZE + APP_SIZE; i++) { - kernel_dest[i] = kernel_src[i]; - } -}
@@ -1,6 +1,6 @@
.RECIPEPREFIX = > -LOCAL_BUILD := $(GLOBAL_BUILD)/stage2 +LOCAL_BUILD := $(GLOBAL_BUILD)/boot SRC_DIR := $(shell pwd)@@ -18,9 +18,10 @@ $(DIRS):
> $(MKDIR) $(DIRS) .PHONY: build -build: $(GLOBAL_BUILD)/stage2.o -$(GLOBAL_BUILD)/stage2.o: $(OBJECTS) -> $(LD) $^ -r -T link.txt -o $@ --oformat elf32-i386 +build: $(GLOBAL_BUILD)/boot.bin +$(GLOBAL_BUILD)/boot.bin: $(OBJECTS) +> $(LD) $^ -T link.txt -Map=$(LOG_DIR)/boot_mapfile.txt -o $@ +> $(LD) $^ -T link.txt -Map=$(LOG_DIR)/boot_mapfile.txt --oformat elf32-i386 -o boot.o $(LOCAL_BUILD)/%.s.o: %.s > $(AS) -o $@ $<
@@ -1,12 +1,8 @@
#include "paging.h" #include "linker.h" +#include "string.h" +#include "fat.h" -void *ss_memset(void *ptr, uint8_t value, uint32_t num) { - for (uint32_t i = 0; i < num; i++) { - ((uint8_t*)ptr)[i] = value; - } - return ptr; -} void *create_kernel_environment() { PAGE_DIR_ENTRY (*pdir)[PAGE_ENTRY_COUNT] = (void*)(0 * PAGE_SIZE);@@ -14,13 +10,13 @@ PAGE_TABLE_ENTRY (*kernel)[PAGE_ENTRY_COUNT] = (void*)(1 * PAGE_SIZE);
PAGE_TABLE_ENTRY (*lowmem)[PAGE_ENTRY_COUNT] = (void*)(2 * PAGE_SIZE); // set everything to zero - ss_memset(pdir, 0, 3 * PAGE_SIZE); + memset(pdir, 0, 3 * PAGE_SIZE); // map page directory to itself (*pdir)[PAGE_ENTRY_COUNT - 1].entry = MAKE_PAGE_ENTRY(pdir, 0b000000000011); // map 4M of kernel to 0xC0000000 - (*pdir)[PAGE_DIR_INDEX(KERNEL_VMA)].entry = MAKE_PAGE_ENTRY(kernel, 0b000000000011); + (*pdir)[PAGE_DIR_INDEX(0xC0000000)].entry = MAKE_PAGE_ENTRY(kernel, 0b000000000011); for (uint32_t i = 0; i < 1 << 10; i++) { (*kernel)[i].entry = MAKE_PAGE_ENTRY(0x100000 + PAGE_SIZE * i, 0b000000000011);