jump to
@@ -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
@@ -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.
@@ -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,34 +60,39 @@ $(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)/apps.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:
@@ -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 -vnc :0 2> log/run_err.log
@@ -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 }
@@ -20,9 +20,9 @@
.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 +> $(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
@@ -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;
@@ -2,6 +2,9 @@ #include <stdint.h>
#include "cedos/elf.h" #include "cedos/core.h" +#include "cedos/fat.h" +#include "cedos/sched/process.h" + #include "assert.h" typedef struct {@@ -115,28 +118,30 @@ printk("\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) { + printk("Loading ELF executable \"%s\".\n", fname); + VIRT_ADDR elf_addr = (VIRT_ADDR*)(0xA0000000); + // TODO: needs to change when we have other file systems + int size = FAT_read_file(fname, elf_addr); + 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);@@ -147,16 +152,16 @@ 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); - 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);@@ -170,11 +175,10 @@
printk("\n"); printk("Entry point: %p\n", header->entry); - printk("Starting process %i...", pid); - sched_exec(pid, header->entry); - - printk("done.\n"); + // enter the process + PROCESS_MAIN *entry = header->entry; + entry(args); return 0; }
@@ -0,0 +1,236 @@
+#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; + } +} + +void *FAT_find_file(const char *fname) { + int i = 0; + + void *addr = (void *)(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; } + + if (strcmp(buffer, fname) == 0) { + // file found + addr = FAT_read_sector_offset(data_lba + ((first_cluster - 2) * boot_sect->sect_per_cluster), NULL); + break; + } + } + + return addr; +} + +uint32_t FAT_read_file(const char *fname, void *buffer) { + int i = 0; + + uint16_t first_cluster; + uint32_t file_size; + while (1) { + char buffer[832]; + + i = FAT_root_dir_next(i, buffer, &first_cluster, &file_size); + if (i <= 0) { return 0; } + + if (strcmp(buffer, fname) == 0) { break; } + } + + // copy all clusters + uint16_t cluster = first_cluster; + 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; +}
@@ -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,11 @@ #include "cedos/core.h"
#include "cedos/elf.h" +#include "cedos/fat.h" + #include "linker.h" #include "assert.h" +#include "string.h" int os_init(void) { core_init();@@ -134,13 +137,45 @@
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; } + + printk("%s (start: %i, size: %i)\n", buffer, first_cluster, file_size); + + uint16_t cluster = first_cluster; + + if (cluster == 0xFFF || cluster == 0x000) { continue; } + + printk(" clusters: "); + while (1) { + printk("%x", cluster); + + //char *sect = FAT_read_cluster(cluster); + //hexdump(sect, 512 * 8); + + cluster = FAT_next_cluster(cluster); + if (cluster == 0xFFF || cluster == 0x000) { break; } + printk(", "); + } + printk("\n"); + } + // 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!"); + + sched_spawn("apps.o", "Hello World!"); + sched_spawn("apps.o", "Hello World!"); + sched_spawn("apps.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:
@@ -11,6 +11,7 @@ #include "cedos/core.h"
#include "cedos/interrupts.h" #include "cedos/pit.h" #include "cedos/pic.h" +#include "cedos/elf.h" #include "assembly.h"@@ -34,10 +35,16 @@
int sched_dispatcher(void); +void entry_idle(char *args) { + while (1) { + //printk("idle.\n"); + } +} + /*! - * 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(); PHYS_ADDR page_dir = create_empty_page_dir();@@ -50,7 +57,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);@@ -61,40 +67,6 @@ 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; - } - // setup stack static SCHED_FRAME frame; frame.eax = frame.ebx = frame.ecx = frame.edx = 0;@@ -102,9 +74,14 @@ 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,7 +91,6 @@
/* TODO: check if code exists at entry point */ // start the process - p->entry = entry; p->state = PSTATE_READY; crit_exit();@@ -175,12 +151,6 @@
pic1_eoi(); } -void entry_idle(char *args) { - while (1) { - //printk("idle.\n"); - } -} - extern void* sched_interrupt; int sched_init(void) {@@ -190,8 +160,7 @@
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); return 1; }@@ -260,10 +229,10 @@ int sched_dispatcher(void) {
//printk("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);
@@ -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++; + } }
@@ -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);