diff --git a/Makefile b/Makefile index fcc22bd..f080df4 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -FILES = ./build/kernel.asm.o ./build/kernel.o ./build/idt/idt.asm.o ./build/idt/idt.o ./build/memory/memory.o ./build/io/io.asm.o ./build/memory/heap/heap.o ./build/memory/heap/kheap.o ./build/memory/paging/paging.o ./build/memory/paging/paging.asm.o ./build/disk/disk.o ./build/string/string.o ./build/fs/pparser.o ./build/disk/streamer.o ./build/fs/file.o ./build/fs/fat/fat16.o ./build/gdt/gdt.o ./build/gdt/gdt.asm.o ./build/task/tss.asm.o ./build/task/task.o +FILES = ./build/kernel.asm.o ./build/kernel.o ./build/idt/idt.asm.o ./build/idt/idt.o ./build/memory/memory.o ./build/io/io.asm.o ./build/memory/heap/heap.o ./build/memory/heap/kheap.o ./build/memory/paging/paging.o ./build/memory/paging/paging.asm.o ./build/disk/disk.o ./build/string/string.o ./build/fs/pparser.o ./build/disk/streamer.o ./build/fs/file.o ./build/fs/fat/fat16.o ./build/gdt/gdt.o ./build/gdt/gdt.asm.o ./build/task/tss.asm.o ./build/task/task.o ./build/task/process.o ./build/task/task.asm.o ./build/isr80h/isr80h.o ./build/isr80h/misc.o ./build/isr80h/io.o INCLUDES = -I./src FLAGS = -g -ffreestanding -falign-jumps -falign-functions -falign-lables -falign-loops -fstrength-reduce -fomit-frame-pointer -finline-functions -Wno-unused-function -fno-builtin -Werror -Wno-cpp -Wno-unused-parameter -nostdlib -nostartfiles -nodefaultlibs -Wall -O0 -Iinc -all: ./bin/boot.bin ./bin/kernel.bin +all: ./bin/boot.bin ./bin/kernel.bin user_programs rm -rf ./bin/os.bin dd if=./bin/boot.bin >> ./bin/os.bin dd if=./bin/kernel.bin >> ./bin/os.bin @@ -15,6 +15,7 @@ all: ./bin/boot.bin ./bin/kernel.bin # copy a file over sudo cp ./hello.txt /mnt/d + sudo cp ./programs/blank/blank.bin /mnt/d sudo unmount /mnt/d ./bin/kernel.bin: $(FILES) @@ -84,7 +85,28 @@ all: ./bin/boot.bin ./bin/kernel.bin ./build/task/task.o: ./src/task/task.c i686-elf-gcc $(INCLUDES) -I./src/task $(FLAGS) -std=gnu99 -c ./src/task/task.c -o ./build/task/task.o -clean: +./build/task/process.o: ./src/task/process.c + i686-elf-gcc $(INCLUDES) -I./src/task $(FLAGS) -std=gnu99 -c ./src/task/process.c -o ./build/task/process.o + +./build/task/task.asm.o: ./src/task/task.asm + nasm -f elf -g ./src/task/task.asm -o ./build/task/task.asm.o + +./build/isr80h/isr80h.o: ./src/isr80h/isr80h.c + i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/isr80h.c -o ./build/isr80h/isr80h.o + +./build/isr80h/misc.o: ./src/isr80h/misc.c + i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/misc.c -o ./build/isr80h/misc.o + +./build/isr80h/io.o: ./src/isr80h/io.c + i686-elf-gcc $(INCLUDES) -I./src/isr80h $(FLAGS) -std=gnu99 -c ./src/isr80h/io.c -o ./build/isr80h/io.o + +user_programs: + cd ./programs/blank && $(MAKE) all + +user_programs_clean: + cd ./programs/blank && $(MAKE) clean + +clean: user_programs_clean rm -rf ./bin/boot.bin rm -rf ./bin/kernel.bin rm -rf ./bin/os.bin diff --git a/OS_n_Booting.docx b/OS_n_Booting.docx index 4e45a46..83dd068 100644 Binary files a/OS_n_Booting.docx and b/OS_n_Booting.docx differ diff --git a/build/isr80h/to_keep b/build/isr80h/to_keep new file mode 100644 index 0000000..d57d09f --- /dev/null +++ b/build/isr80h/to_keep @@ -0,0 +1 @@ +as \ No newline at end of file diff --git a/programs/blank/blank.asm b/programs/blank/blank.asm new file mode 100644 index 0000000..1648e7b --- /dev/null +++ b/programs/blank/blank.asm @@ -0,0 +1,19 @@ +%%if 0 + creating the first program where it will jump in to itself +%%endif +[BITS 32] + +section .asm + +global _start + +_start: + push message + mov eax, 1 ; command print + int 0x80 + add esp, 4 + + jmp $ + +section .data +message: db 'This is from user space', 0 \ No newline at end of file diff --git a/programs/blank/build/Makefile b/programs/blank/build/Makefile new file mode 100644 index 0000000..a7e5ec7 --- /dev/null +++ b/programs/blank/build/Makefile @@ -0,0 +1,6 @@ +all: + nasm -f elf ./blank.asm -o ./build/blank.o + i686-elf-gcc -g -T ./linker.ld -o ./blank.bin -ffreestanding -O0 -nostdlib -fpic -g ./build/blank.o + +clean: + rm -rf ./build/blank.o \ No newline at end of file diff --git a/programs/blank/linker.ld b/programs/blank/linker.ld new file mode 100644 index 0000000..800df6e --- /dev/null +++ b/programs/blank/linker.ld @@ -0,0 +1,46 @@ +/* + Here we are specifing the sections that which section is doing which part + and so on. + + Here in SECTIONS '. = 1M' means (1024x1024=100000 (in hex)) + So we are telling that after the boot go to this location where the + kernel.bin is saved and start running from that part. + + Here we are aligning everything properly as we are now coding in C. + During assmebly we need not wrry for the alignment but for both + asm and C we need to align otherwise code not work properly. + + So we added times 512 at the end of kernel.asm and here. +*/ + +ENTRY(_start) +OUTPUT_FORMAT(binary) +SECTIONS +{ + . = 0x400000; + .text : ALIGN(4096) + { + *(.text) + } + + .asm : ALIGN(4096) + { + *(.asm) + } + + .rodata : ALIGN(4096) + { + *(.rodata) + } + + .data : ALIGN(4096) + { + *(.data) + } + + .bss : ALIGN(4096) + { + *(COMMON) + *(.bss) + } +} \ No newline at end of file diff --git a/src/boot/boot.asm b/src/boot/boot.asm index 9566411..2ba99b9 100644 --- a/src/boot/boot.asm +++ b/src/boot/boot.asm @@ -1,4 +1,4 @@ -/* +%%if 0 First we need to specify the origin so that Os knows the offset needed for the data Ideally the origin should be 0x0000 and then the system should jump to the designated location in the case of this system is 0x7c00. @@ -18,9 +18,9 @@ are not enough to fill 510 bytes then it will pad it with 0's. Now then providing the boot signature which is 0x55AA, but we are writing here 0xAA55 due to endianess. -*/ +%%endif -/* +%%if 0 Use Makefile1 for build Now to run this in the system using qemu we will first create a binary file '.bin'. @@ -34,9 +34,9 @@ Now to run on qemu use this cmd cmd - 'qemu-system-x86_64 -hda ./boot.bin' -*/ +%%endif -/* +%%if 0 ORG 0x7c00 BITS 16 @@ -50,10 +50,10 @@ start: times 510-($ - $$) db 0 dw 0xAA55 -*/ +%%endif -/* +%%if 0 Use Makefile1 for build To print custom message on the booting screen we will use the below code. @@ -87,10 +87,10 @@ message: db 'Hello World!', 0 times 510-($ - $$) db 0 dw 0xAA55 -*/ +%%endif -/* +%%if 0 Use Makefile1 for build Ideally we place our start point 0x0000 and we jump from that to the desired location. @@ -148,10 +148,10 @@ message: db 'Hello World!', 0 times 510-($ - $$) db 0 dw 0xAA55 -*/ +%%endif -/* +%%if 0 Use Makefile1 for build This section we will write and call custom interrupts for Real Mode. @@ -231,11 +231,11 @@ message: db 'Hello World!', 0 times 510-($ - $$) db 0 dw 0xAA55 -*/ +%%endif -/* +%%if 0 Use Makefile1 for build Removing the unnecessary things from the code like interrupts and able to read the message.txt @@ -305,10 +305,10 @@ times 510-($ - $$) db 0 dw 0xAA55 buffer: -*/ +%%endif -/* +%%if 0 For here use Makefile2 and earlier use Makefile1 To start the processor in the protected mode after the real mode. @@ -410,10 +410,10 @@ load32: times 510-($ - $$) db 0 dw 0xAA55 -*/ +%%endif -/* +%%if 0 From here use Makefile and earlier use Makefile1 Now we are creating another file called kernel.asm so we are using this @@ -554,14 +554,14 @@ ata_lba_read: times 510-($ - $$) db 0 dw 0xAA55 -*/ +%%endif -/* +%%if 0 From here use Makefile and earlier use Makefile1 In this we are adding FAT16 system to our booting part so that kernel knows how to read the files. -*/ +%%endif ORG 0x7c00 BITS 16 diff --git a/src/config.h b/src/config.h index e3a8421..6a82fc6 100644 --- a/src/config.h +++ b/src/config.h @@ -30,4 +30,9 @@ #define USER_DATA_SEGMENT 0x23 #define USER_CODE_SEGMEnt 0x1b +#define PEACHOS_MAX_PROGRAM_ALLOCATIONS 1024 +#define PEACHOS_MAX_PROCESSES 12 + +#define PEACHOS_MAX_ISR80H_COMMANDS 1024 + #endif \ No newline at end of file diff --git a/src/gdt/gdt.h b/src/gdt/gdt.h index ce48e70..8c3a925 100644 --- a/src/gdt/gdt.h +++ b/src/gdt/gdt.h @@ -20,7 +20,7 @@ struct gdt{ uint8_t access; uint8_t high_flags; uint8_t base_24_31_bits; -}; +} __attribute__((packed)); /* create another sturcture which will use the gdt struct diff --git a/src/idt/idt.asm b/src/idt/idt.asm index de48684..1ebaf00 100644 --- a/src/idt/idt.asm +++ b/src/idt/idt.asm @@ -6,12 +6,14 @@ section .asm extern int21g_handler extern no_interrupt_handler +extern isr80h_handler global int21h global idt_load global no_interrupt global enable_interrupts global disable_interrupts +global isr80h_wrapper enable_interrupts: sti @@ -31,19 +33,49 @@ idt_load: ret int21h: - cli pushad call int21h_handler popad - sti iret ; we write this interrupt bcoz we dont want the kernel to do anything else if keyboard ; interrupt occurs otherwise it will loop in bios mode continously no_interrupt: - cli pushad call no_interrupt_handler popad - sti - iret \ No newline at end of file + iret + +; calling kernel from the userspace +; selecting 0x80 as interrupt to give control to kernel from userspace +isr80h_wrapper: + ; interrupt frame start + ; already pushed to us by the processor upon entry to this interrupt + ; uint32_t ip; + ; uint32_t cs; + ; uint32_t flags + ; uint32_t sp; + ; uint32_t ss; + ; pushes the general purpose regs to the stack + pushad + + ; interrupt frame end + + ; push the stack pointer so that we are pointing to + ; the interrupt frame + push esp + + ; EAX holds our cmd lets push it to the stack for isr80h_handler + push eax + call isr80h_handler + mov dword[tmp_res], eax + add esp, 8 + + ; restore general purpose regs for user land + popad + mov eax, [tmp_res] + iretd + +section .data +; inside here is stored the return result from isr80h_handler +tmp_res dd 0 \ No newline at end of file diff --git a/src/idt/idt.c b/src/idt/idt.c index 65b184f..afc3309 100644 --- a/src/idt/idt.c +++ b/src/idt/idt.c @@ -7,16 +7,20 @@ #include "kernel.h" #include "memory/memory.h" #include "io/io.h" +#include "task/task.h" struct idt_desc idt_descriptors[PEACHOS_TOTAL_INTERRUPTS]; struct idtr_desc idtr_descriptor; +static ISR80H_COMMAND isr80h_commands[PEACHOS_MAX_ISR80H_COMMANDS]; + /* this is called in idt.asm file */ extern void idt_load(struct idtr_desc* ptr); extern void int21h(); extern void no_interrupt(); +extern void isr80h_wrapper(); /* IO interrupt to recognize the keyboard interrupt @@ -58,7 +62,7 @@ void idt_set(int interrupt_no, void* address){ } /* - this is called to generate the interrupt + the interrupts will be initialized which can be used later */ void idt_init(){ memset(idt_descriptors, 0, sizeof(idt_descriptors)); @@ -71,9 +75,57 @@ void idt_init(){ idt_set(0, idt_zero); idt_set(0x21, int21h); + idt_set(0x80, isr80h_wrapper); /* load the interrupt descriptor table */ idt_load(&idtr_descriptor); +} + +/* + to make sure that the interrupt is valid +*/ +void isr80h_register_command(int command_id, ISR80H_COMMAND command){ + if(command_id < 0 || command_id >= PEACHOS_MAX_ISR80H_COMMANDS){ + panic("The command is out of box\n"); + } + + if(isr80h_commands[command_id]){ + panic("You are attempting to overwrite an existing command\n"); + } + + isr80h_commands[command_id] = command; +} + +/* + to handle the interrupt +*/ +void* isr80h_handler_command(int command, struct interrupt_frame* frame){ + void* result = 0; + if(command < 0 || command >= PEACHOS_MAX_ISR80H_COMMANDS){ + return 0; + } + + ISR80H_COMMAND command_func = isr80h_commands[command]; + if(!command_func){ + return 0; + } + + result = command_func(frame); + return result; +} + +/* + Interrupt handler when called will pass the command to kernel + to print the message from userspace +*/ +void* isr80h_handler(int command, struct interrupt_frame* frame){ + void* res = 0; + kernel_page(); + /* for multi-tasking/threading pusrposes by saving old task state */ + task_current_save_status(frame); + res = isr80h_handler_command(command, frame); + task_page(); + return res; } \ No newline at end of file diff --git a/src/idt/idt.h b/src/idt/idt.h index df2e71d..a0ed435 100644 --- a/src/idt/idt.h +++ b/src/idt/idt.h @@ -7,6 +7,9 @@ #include +struct interrupt_frame; +typedef void*(*ISR80H_COMMAND)(struct interrupt_frame* frame); + struct idt_desc{ uint16_t offset_1; // offset bits 0-15 uint16_t selector; // selector thats in out GDT @@ -20,8 +23,26 @@ struct idtr_desc{ uint32_t base; // base address of the start of the interrupt descriptor table } __attribute__((packed)); +struct interrupt_frame{ + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t reserved; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t ip; + uint32_t cs; + uint32_t flags; + /* user land stack pointer */ + uint32_t esp; + uint32_t ss; +} __attribute__((packed)); + void idt_init(); void enable_interrupts(); void disable_interrupts(); +void isr80h_register_command(int command_id,ISR80H_COMMAND command); #endif \ No newline at end of file diff --git a/src/isr80h/io.c b/src/isr80h/io.c new file mode 100644 index 0000000..692159a --- /dev/null +++ b/src/isr80h/io.c @@ -0,0 +1,19 @@ +/* + This is IO file for interrupt +*/ + +#include "io.h" +#include "task/task.h" +#include "kernel.h" + +/* + This is to print the command or string from the frame or task +*/ +void* isr80h_command1_print(struct interrupt_frame* frame){ + void* user_space_msg_buffer = task_get_stack_item(task_current(), 0); + char buf[1024]; + copy_string_from_task(task_current(), user_space_msg_buffer, buf, sizeof(buf)); + + print(buf); + return 0; +} \ No newline at end of file diff --git a/src/isr80h/io.h b/src/isr80h/io.h new file mode 100644 index 0000000..742b985 --- /dev/null +++ b/src/isr80h/io.h @@ -0,0 +1,10 @@ +/* + This is header file for IO operations for interrupts +*/ + +#ifndef ISR80H_IO_H +#define ISR80H_IO_H + +struct interrupt_frame; +void *isr80h_command1_print(struct interrupt_frame* frame); +#endif \ No newline at end of file diff --git a/src/isr80h/isr80h.c b/src/isr80h/isr80h.c new file mode 100644 index 0000000..3d7b8f2 --- /dev/null +++ b/src/isr80h/isr80h.c @@ -0,0 +1,12 @@ +/* + This will take care of interrupt 80 when generated +*/ +#include "isr80h.h" +#include "idt/idt.h" +#include "misc.h" +#include "io.h" + +void isr80h_register_commands(){ + isr80h_register_command(SYSTEM_COMMAND0_SUM, isr80h_command0_sum); + isr80h_register_command(SYSTEM_COMMAND1_PRINT, isr80h_command1_print); +} \ No newline at end of file diff --git a/src/isr80h/isr80h.h b/src/isr80h/isr80h.h new file mode 100644 index 0000000..ff75ef7 --- /dev/null +++ b/src/isr80h/isr80h.h @@ -0,0 +1,14 @@ +/* + This is header which take care of interrupt 80 when generated +*/ +#ifndef ISR80H_H +#define ISR80H_H + +enum SystemCommands{ + SYSTEM_COMMAND0_SUM, + SYSTEM_COMMAND1_PRINT, +}; + +void isr80h_register_commands(); + +#endif ISR80H_H \ No newline at end of file diff --git a/src/isr80h/misc.c b/src/isr80h/misc.c new file mode 100644 index 0000000..b2c6ee7 --- /dev/null +++ b/src/isr80h/misc.c @@ -0,0 +1,12 @@ +/* + This is miscillaneous sector where it will store and register interrupts +*/ +#include "misc.h" +#include "idt/idt.h" +#include "task/task.h" + +void* isr80h_command0_sum(struct interrupt_frame* frame){ + int v2 = (int)task_get_stack_item(task_current(), 1); + int v1 = (int)task_get_stack_item(task_current(), 0); + return (void*)(v1 + v2); +} \ No newline at end of file diff --git a/src/isr80h/misc.h b/src/isr80h/misc.h new file mode 100644 index 0000000..36e0ba1 --- /dev/null +++ b/src/isr80h/misc.h @@ -0,0 +1,10 @@ +/* + This is header for miscillaneous sector where it will store and register interrupts +*/ +#ifndef ISR80H_MISC_H +#define ISR80H_MISC_H + +struct interrupt_frame; +void* isr80h_command0_sum(struct interrupt_frame* frame); + +#endif ISR80H_MISC_H \ No newline at end of file diff --git a/src/kernel.asm b/src/kernel.asm index e3e4706..ce31f93 100644 --- a/src/kernel.asm +++ b/src/kernel.asm @@ -2,6 +2,8 @@ global _start global problem +global kernel_registers + extern kernel_main CODE_SEG equ 0x08 @@ -41,6 +43,14 @@ _start: jmp $ +kernel_registers: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov gs, ax + mov fs, ax + ret + problem: ; in idt.c there we are declaring int 0 for how to manage it ; so we are calling interrupt here diff --git a/src/kernel.c b/src/kernel.c index f35d5aa..1ebf7aa 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,6 +14,10 @@ #include "config.h" #include "gdt/gdt.h" #include "task/tss.h" +#include "task/task.h" +#include "task/process.h" +#include "status.h" +#include "isr80h/isr80h.h" uint16_t* video_mem = 0; uint16_t terminal_row = 0; @@ -105,6 +109,15 @@ void panic(const char* msg){ while(1){} } +/* + Will switch page directory from kernel page directory + and also change from registers from kernel registers +*/ +void kernel_page(){ + kernel_registers(); + paging_switch(kernel_chunk); +} + /* to declare the user and kernel segments */ @@ -120,32 +133,6 @@ struct gdt_structured gdt_structured[PEACHOS_TOTAL_GDT_SEGMENTS] = { }; void kernel_main(){ - /* - here we will see a letter 'A' in blue colour at the booting process with other data - on the screen. - - To run this run ./build.sh in cmd list and then go to bin dir and then run the - 'qemu-system-x86_64 -hda ./os.bin' - - char* video_mem = (char*)(0xB8000); - video_mem[0] = 'A'; - video_mem[1] = 1; - video_mem[2] = 'B'; - video_mem[3] = 2; - */ - - /* - Here we know this uses 2 bytes so we use uint_16 for more precision. - - For this we need to change the values which we provides like - we know A=0x41 and 1=0x01, so we will provide as '0x4101'. - - Here we need to provide 0x0141 because of edianess. - - uint16_t* video_mem = (uint16_t*)(0xB8000); - video_mem[0] = 0x0141; - */ - /* Everytime its not good to provide it with hex values. @@ -206,13 +193,6 @@ void kernel_main(){ */ kernel_chunk = paging_new_4gb(PAGING_IS_WRITEABLE | PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL); - /* - To directly read from the location into buffer - - char buf[512]; - disk_read_block(disk_get(0), 20, 4, &buf); - */ - /* In-charge of switching pages as in paging there is no contigous memory location. So, if the memory is contigous then there is no meaning of paging. @@ -222,37 +202,7 @@ void kernel_main(){ paging_4gb_chunk_get_directory is for getting location of page. */ - paging_switch(paging_4gb_chunk_get_directory(kernel_chunk)); - - /* - mapping the memory - - char *ptr = kzalloc(4096); - */ - - /* - setting up for paging, so here in virtual addr 0x1000 should map to the ptr addr. - So if we use another ptr pointing to 0x1000, the data will be same as even though - physical address is different as it is mapped to 0x1000 on virtual address. - - paging_set(paging_4gb_chunk_get_directory(kernel_chunk), (void*)0x1000, (uint32_t)ptr | PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL | PAGING_IS_WRITEABLE); - */ - - /* - testing the above mapping mechanism in working as we have a ptr pointing to 0x1000 virtual address - and the above ptr is pointing to 0x1000 virtual address having different physical address. - - Here we have not yet implemented the enable_pagin(), so it is not enabled. = - So by changing the values at ptr2, we will not change the data at different physical address. - - Output- ptr2 -AB and ptr - empty. - - char* ptr2 = (char*) 0x1000; - ptr2[0] = 'A'; - ptr2[1] = 'B'; - print(ptr2); - print(ptr); - */ + paging_switch(kernel_chunk); /* enabling the paging @@ -260,145 +210,20 @@ void kernel_main(){ enable_paging; /* - sometimes setting paging, it disables or triggers unneccessay interrupts + registering kernel commands */ - enable_interrupts; + isr80h_register_commands(); /* - using path parser to move from one part to another - - struct path_root* root_path = pathparser_parse("0:/bin/shell.exe", NULL); - if(root_path){ - - } - */ - - /* - Assigning disk 0 to read, then selecting single byte to read which is - 0x201 and storing that location data to c. - - struct disk_stream* stream = diskstreamer_new(0); - diskstreamer_seek(stream, 0x201); - unsigned char c = 0; - diskstreamer_read(stream, &c, 1); - to hold to see the data in qemu - while(1){} + providing the process */ - - /* - to check if the strcpy works properly - - char buf[20]; - strcpy(buf, "hello!"); - */ - - /* - testing the fat16 implementation using file descriptor using fopen, fread and fseek. - - first fd is created and from that, it will look for a file name hello.txt - if it finds then loads its directory and items. - Once loaded, we can now read and write into them in streams also. - - int fd = fopen("0:/hello.txt", "r"); - if(fd){ - print("\n we opend hello.txt file \n"); - char buf[14]; - fseek(fd, 2, SEEK_SET); - // now reading from pos 2 instead of 0 - fread(buf, 11, 1, fd); - // NULL terminator - buf[13] = 0x00; - print(buf); + struct process* process = 0; + int res = process_load("0:/blank.bin", &process); + if(res != PEACHOS_ALL_OK){ + panic("Failed to load blank.bin\n"); } - */ - - /* - testing filesystem using file programs - */ - int fd = fopen("0:/hello.txt", "r"); - print("\n file opened\n"); - if(fd){ - struct file_stat s; - fstat(fd, &s); - print("\n status of file\n"); - fclose(fd); - print("\n file closed\n"); - } - - /* - reading into the buffer - Place the init code for disk at the start of the kernel so that it init the disk - at the start so that it is easy to map and access the location through an interface. - - We can directly use the below without disk init, but a proper interface wont be create to regualrlly - and randomly accessing the data using API. We will need to know the exact location in the - physical memory for paging and maping. - - char buf[512]; - disk_read_sector(0, 1, buf); - */ - - /* - testing the above mapping mechanism in working as we have a ptr pointing to 0x1000 virtual address - and the above ptr is pointing to 0x1000 virtual address having different physical address. - - Here we have enabled paging - So by changing the values at ptr2, we will change the data at different physical address. - - Output - ptr2 - AB and ptr - AB. - - char* ptr2 = (char*) 0x1000; - ptr2[0] = 'A'; - ptr2[1] = 'B'; - print(ptr2); - print(ptr); - */ - void* ptr = kmalloc(50); - void* ptr2 = kmalloc(5000); - void* ptr3 = kmalloc(5600); - kfree(ptr); - void* ptr4 = kmalloc(50); - /* here we are using this to see if we have aloocated memory or not - if( ptr || ptr2 || ptr3 || ptr4){ + task_run_first_ever_task(); - } - */ - kfree(ptr2); - kfree(ptr3); - kfree(ptr4); - /* - disable interrupts so the system does not get interrupted while doing this - */ - disable_interrupts(); - - /* - generating an interrupt as we are dividing it number by zero - */ - problem(); - - /* - enabling interrupts so the system does get interrupted for another interrupts - */ - enable_interrupts(); - - /* - using io to provide output this char - The below code after outb is to do io using interrupts - - outb(0x60, 0xff); - */ - - /* - the above one is to directly call the i/o - This is used to handle the i/o using interrupts - - We are using keyboard to call this interrupt. - - this way we are only taking interrupt from keyboard only once - so we need will change it that is takes interrupt everytime. - - If we change the interrupt from 0x21 to 0x20, as 20 is for timer - then we will get continous interrupt on the screen for keyboard. - */ + while(1) {} } \ No newline at end of file diff --git a/src/kernel.h b/src/kernel.h index 5f9485a..e9c5f47 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -13,6 +13,8 @@ void kernel_main(); void print(const char* str); void panic(const char* msg); +void kernel_page(); +void kernel_registers(); #define ERROR(value) (void*)(value) #define ERROR_I(value) (int)(value) diff --git a/src/linker.ld b/src/linker.ld index c025b62..1857810 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -23,6 +23,11 @@ SECTIONS *(.text) } + .asm : ALIGN(4096) + { + *(.asm) + } + .rodata : ALIGN(4096) { *(.rodata) @@ -38,9 +43,4 @@ SECTIONS *(COMMON) *(.bss) } - - .asm : ALIGN(4096) - { - *(.asm) - } } \ No newline at end of file diff --git a/src/memory/paging/paging.asm b/src/memory/paging/paging.asm index 9f79d85..b4d1ff9 100644 --- a/src/memory/paging/paging.asm +++ b/src/memory/paging/paging.asm @@ -1,7 +1,7 @@ -/* +%%if 0 This is the assembly file for the paging to load and enable paging as C lang does not support this instructions in Intel -*/ +%%endif [BITS 32] diff --git a/src/memory/paging/paging.c b/src/memory/paging/paging.c index 47b02b0..e67be2a 100644 --- a/src/memory/paging/paging.c +++ b/src/memory/paging/paging.c @@ -55,9 +55,9 @@ struct paging_4gb_chunk* paging_new_4gb(uint8_t flags){ So, to get the data properly as the location of the data is scatter all the place, to retrive the data properly we use page switching method. */ -void paging_switch(uint32_t* directory){ - paging_load_directory(directory); - current_directory = directory; +void paging_switch(struct paging_4gb_chunk* directory){ + paging_load_directory(directory->directory_entry); + current_directory = directory->directory_entry; } /* @@ -101,6 +101,81 @@ int paging_get_indexes(void* virtual_address, uint32_t* directory_index_out, uin return res; } +/* + making sure that virtual and physical pages are alligned properly +*/ +void* paging_is_alligned_address(void* ptr){ + if((uint32_t)ptr % PAGING_PAGE_SIZE){ + return (void*)((uint32_t)ptr + PAGING_PAGE_SIZE - ((uint32_t)ptr % PAGING_PAGE_SIZE)); + } + + return ptr; +} + +/* + making sure that virtual and physical pages are mapped properly +*/ +int paging_map(struct paging_4gb_chunk* directory, void* virt, void* phys, int flags){ + if(((unsigned int)virt % PAGING_PAGE_SIZE) || ((unsigned int)phys % PAGING_PAGE_SIZE)){ + return -EINVARG; + } + + return paging_set(directory->directory_entry, virt, (uint32_t)phys | flags); +} + +/* + mapping the range of paging of the process +*/ +int paging_map_range(struct paging_4gb_chunk* directory, void* virt, void* phys, int count, int flags){ + int res = 0; + for(int i=0; i=PEACHOS_MAX_PROCESSES){ + return NULL; + } + + return processes[process_id]; +} + +/* + loading the binaries to the data to support the ELF file +*/ +static int process_load_binary(const char* filename, struct process* process){ + int res = 0; + int fd = fopen(filename, "r"); + if(!fd){ + res = -EIO; + goto out; + } + + struct file_stat stat; + res = fstat(fd, &stat); + if(res != PEACHOS_ALL_OK){ + goto out; + } + + void* program_data_ptr = kzalloc(stat.filesize); + if(!program_data_ptr){ + res = -ENOMEM; + goto out; + } + + if(fread(program_data_ptr, stat.filesize, 1, fd) != 1){ + res = -EIO; + goto out; + } + + process->ptr = program_data_ptr; + process->size = stat.filesize; + +out: + fclose(fd); + return res; +} + +/* + loading the data to the process +*/ +static int process_load_data(const char* filename, struct process* process){ + int res = 0; + /* incase we support ELF files */ + res = process_load_binary(filename, process); + return res; +} + +/* + to convert the process mapped memory into binary for ELF files +*/ +int process_map_binary(struct process* process){ + int res = 0; + paging_map_to(process->task->page_directory, (void*)PEACHOS_PROGRAM_VIRTUAL_ADDRESS, process->ptr, paging_align_address(process->ptr + process->size), PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL | PAGING_IS_WRITEABLE); + return res; +} + +/* + this functions assuems that the process is initialized correctly + otherwise calling this function before that will create kernel panic +*/ +int process_map_memory(struct process* process){ + int res = 0; + /* incase we support ELF files */ + res = process_map_binary(process); + if(res < 0){ + goto out; + } + + /* mapping the stack pointer */ + paging_map_to(process->task->page_directory, (void*)PEACHOS_PROGRAM_VIRTUAL_STACK_ADDRESS_END, process->stack, paging_align_address(process->stack+PEACHOS_USER_PROGRAM_STACK_SIZE), PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL | PAGING_IS_WRITEABLE); +out: + return res; +} + +/* + find the free slot in the process array to load and perform tasks +*/ +int process_get_free_slot(){ + for(int i=0; ifilename, filename, sizeof(_process->filename)); + _process->stack = program_stack_ptr; + _process->id = process_slot; + + /* create a task */ + task = task_new(_process); + if(ERROR_I(task == 0)){ + res = ERROR_I(task); + goto out; + } + + _process->task = task; + + res = process_map_memory(_process); + if(res<0){ + goto out; + } + + *process = _process; + + /* add the process to the array */ + processes[process_slot] = _process; + +out: + if(ISERR(res)){ + if(_process && _process->task){ + task_free(_process->task); + } + + kfree(_process); + } + return res; +} \ No newline at end of file diff --git a/src/task/process.h b/src/task/process.h new file mode 100644 index 0000000..a7ed199 --- /dev/null +++ b/src/task/process.h @@ -0,0 +1,48 @@ +/* + This is header file for processes which will be created and + handled properly by our OS. +*/ +#ifndef PROCESS_H +#define PROCESS_H + +#include +#include "config.h" +#include "memory/memory.h" +#include "status.h" +#include "task/task.h" +#include "memory/heap/kheap.h" +#include "fs/file.h" +#include "string/string.h" +#include "kernel.h" +#include "memory/paging/paging.h" + +/* + This is the structure of all the processes which will be created in this system +*/ +struct process{ + /* the process id */ + uint16_t id; + + char filename[PEACHOS_MAX_PATH]; + + /* themain process task */ + struct task* task; + + /* this is to track the memory allocated by the kernel */ + /* so we can free them at the termination of program */ + void* allocations[PEACHOS_MAX_PROGRAM_ALLOCATIONS]; + + /* the physical pointer to the process memory */ + void* ptr; + + /* the physical pointer to the stack memory */ + void* stack; + + /* the size of the data pointed to by ptr */ + uint32_t size; +}; + +int process_load(const char* filename, struct process** process); +int process_load_for_slot(const char* filename, struct process** process, int process_slot); + +#endif PROCESS_H \ No newline at end of file diff --git a/src/task/task.asm b/src/task/task.asm new file mode 100644 index 0000000..20d878b --- /dev/null +++ b/src/task/task.asm @@ -0,0 +1,75 @@ +; for user land functionality + +[BITS 32] + +section .asm + +global restore_general_purpose_registers +global user_registers +global task_return + +; void task_return(struct registers* regs); +task_return: + mov ebp, esp; + ; push the data segment (SS will be fine) + ; push the stack address + ; push the flags + ; push the code segment + ; push ip + + ; lets access the structure passed to us + mov ebx, [ebp+4] + ; push the data/stack selector + push dword [ebx+44] + ; push the stack pointer + push dword [ebx+40] + + ; push the flags + pushf + pop eax + or eax, 0x200 + push eax + + ; push the code segment + push dword [ebx+32] + + ; push the IP (program counter) to execute + push dword [ebx+28] + + ; setup some segment registers + mov ax, [ebx+44] + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + push dword [ebp+4] + call restore_general_purpose_registers + add esp, 4 + + ; lets leave kernel land and execute in user land + iretd + +; void restore general pusrpose registers (struct register* regs); +restore_general_purpose_registers: + push ebp + mov ebp, esp + mov ebx, [ebp+8] + mov edi, [ebx] + mov esi, [ebx+4] + mov ebp, [ebx+8] + mov edx, [ebx+16] + mov ecx, [ebx+20] + mov eax, [ebx+24] + mov ebx, [ebx+12] + pop epb + ret + +; void user_registers(); +user_registers: + mov ax, 0x23 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + ret \ No newline at end of file diff --git a/src/task/task.c b/src/task/task.c index 6392f46..73d9760 100644 --- a/src/task/task.c +++ b/src/task/task.c @@ -16,13 +16,13 @@ struct task* current_task = 0; struct task* task_tail = 0; struct task* task_head = 0; -int task_init(struct task* task); +int task_init(struct task* task, struct process* process); struct task* task_current(){ return current_task; }; -struct task* task_new(){ +struct task* task_new(struct process* process){ int res = 0; struct task* task = kzalloc(sizeof(struct task)); if(!task){ @@ -30,7 +30,7 @@ struct task* task_new(){ goto out; } - res = task_init(task); + res = task_init(task, process); if(res != PEACHOS_ALL_OK){ goto out; } @@ -38,6 +38,7 @@ struct task* task_new(){ if(task_head == 0){ task_head = task; task_tail = task; + current_task = task; goto out; } @@ -99,10 +100,122 @@ int task_free(struct task* task){ return 0; } +/* + switching the context of the tasks for task scheduling and task switching +*/ +int task_switch(struct task* task){ + current_task = task; + paging_switch(task->page_directory); + return 0; +} + +/* + To save the task as interrupt called so when interrupt returns, kernel starts + from the place where it paused +*/ +void task_save_state(struct task* task, struct interrupt_frame* frame){ + task->registers.ip = frame->ip; + task->registers.cs = frame->cs; + task->registers.flags = frame->flags; + task->registers.esp = frame->esp; + task->registers.ss = frame->ss; + task->registers.eax = frame->eax; + task->registers.ebp = frame->ebp; + task->registers.ebx = frame->ebx; + task->registers.ecx = frame->ecx; + task->registers.edi = frame->edi; + task->registers.edx = frame->edx; + task->registers.esi = frame->esi; +} + +/* + Copy string from user tasks +*/ +int copy_string_from_task(struct task* task, void* virtual, void* phys, int max){ + if(max >= PAGING_PAGE_SIZE){ + return -EINVARG; + } + + /* providing memory for task sharing */ + int res = 0; + char* tmp = kzalloc(max); + if(!tmp){ + res = -ENOMEM; + goto out; + } + + uint32_t* task_directory = task->page_directory->directory_entry; + uint32_t old_entry = paging_get(task_directory, tmp); + paging_map(task->page_directory, tmp, tmp, PAGING_IS_WRITEABLE | PAGING_IS_PRESENT | PAGING_ACCESS_FROM_ALL); + paging_switch(task->page_directory); + strncpy(tmp, virtual, max); + kernel_page(); + + res = paging_set(task_directory, tmp, old_entry); + if(res<0){ + res = -EIO; + goto out_free; + } + + strncpy(phys, tmp, max); + +out_free: + kfree(tmp); + +out: + return res; +} + +/* + to save the current stage of the process +*/ +void task_current_save_state(struct interrupt_frame* frame){ + if(!task_current()){ + panic("No current task to save\n"); + } + + struct task* task = task_current(); + task_save_state(task, frame); +} + +/* + takes page from kernel directory and loads into the task/page directory + + as during the interrupts, the kernel will called and when we switch back + we will look into task directory/space so when it return they see the + memory as it was before +*/ +int task_page(){ + user_registers(); + task_switch(current_task); + return 0; +} + +/* + changing page directory to point task page directory +*/ +int task_page_task(struct task* task){ + user_registers(); + paging_switch(task->page_directory); + return 0; +} + +/* + to run the very first task in the system +*/ +void task_run_first_ever_task(){ + if(!current_task){ + panic("task_run_first_ever_task(): No curretn task exists!"); + } + + task_switch(task_head); + task_return(&task_head->registers); +} + /* to initialize the task with the regesters */ -int task_init(struct task* task){ +int task_init(struct task* task, struct process* process){ memset(task, 0, sizeof(struct task)); /* mape the entire 4GB address space to itself */ @@ -114,7 +227,29 @@ int task_init(struct task* task){ /* for the first time program counter will point to the virtual address of process */ task->registers.ip = PEACHOS_PROGRAM_VIRTUAL_ADDRESS; task->registers.ss = USER_DATA_SEGMENT; + task->registers.cs = USER_CODE_SEGMEnt; task->registers.esp = PEACHOS_PROGRAM_VIRTUAL_STACK_ADDRESS_STATE; + task->process = process; + return 0; +} + +/* + assigning stack pointer and item from the task +*/ +void* task_get_stack_item(struct task* task, int index){ + void* result = 0; + + uint32_t* sp_ptr = (uint32_t*)task->registers.esp; + + /* switch to the given tasks page */ + task_page_task(task); + + result = (void*)sp_ptr[index]; + + /* switch back to the kernel page */ + kernel_page(); + + return result; } \ No newline at end of file diff --git a/src/task/task.h b/src/task/task.h index 5568f97..b98e72e 100644 --- a/src/task/task.h +++ b/src/task/task.h @@ -11,8 +11,14 @@ #include "memory/paging/paging.h" #include "memory/heap/kheap.h" #include "memory/memory.h" +#include "process.h" +#include "idt/idt.h" +#include "memory/paging/paging.h" +#include "string/string.h" + #include +struct interrupt_frame; /* here we are creating structures for register as we need to move and store registers as moving from kernel @@ -42,6 +48,9 @@ struct task{ /* the registers of the task when the task is not running */ struct registers registers; + /* the process of the task */ + struct process* process; + /* the next task in the linked list */ struct task* next; @@ -49,9 +58,26 @@ struct task{ struct task* prev; }; -struct task* task_new(); +struct task* task_new(struct process* process); struct task* task_current(); struct task* task_get_next(); + int task_free(struct task* task); +int task_switch(struct task* task); +int task_page(); + +/* runing the very first task in the system */ +void task_run_first_ever_task(); + +/* drop us into the user land */ +void task_return(struct registers* process); +void restore_general_purpose_registers(struct registers* regs); +void user_registers(); + +/* saving the task */ +void task_current_save_state(struct interrupt_frame* frame); +int copy_string_from_task(struct task* task, void* virtual, void* phys, int max); +void* task_get_stack_item(struct task* task, int index); +int task_page_task(struct task* task); #endif \ No newline at end of file diff --git a/src/task/tss.asm b/src/task/tss.asm index 18e4724..9c4718c 100644 --- a/src/task/tss.asm +++ b/src/task/tss.asm @@ -1,10 +1,10 @@ -/* +%%if 0 this is a assembly file for the TSS(Task Switching Segment) When the kernel switches from kernel mode to user mode it will pull this segment to continue its old work or from user mode to kernel mode, it will push this segment for future completion. -*/ +%%endif section .asm global tss_load