diff --git a/SANDHU__OS/Makefile b/SANDHU__OS/Makefile new file mode 100644 index 0000000..75143fb --- /dev/null +++ b/SANDHU__OS/Makefile @@ -0,0 +1,27 @@ +MKDIR_P := mkdir -p +OUT_DIR := $(PWD)/build +export TOP_DIR=$(PWD) +export LIB_DIR=${OUT_DIR}/lib +export BIN_DIR=${OUT_DIR}/bin +export ETC_DIR=${OUT_DIR}/etc +export LD_LIBRARY_PATH:=${LIB_DIR}:$(LD_LIBRARY_PATH) + +SUBDIRS = \ + src + +MAKE_UTILS_DIR := $(PWD)/makeUtils +export MAKE_UTILS_DIR + +all: $(OUT_DIR) + +$(OUT_DIR): + ${MKDIR_P} $(LIB_DIR) $(BIN_DIR) $(ETC_DIR) + +clean: rmBuild + +rmBuild: + rm -rf build iso/boot/kernel.elf bochsrc.txt bochslog.txt vivitsa.iso os.iso \ + .DS_Store com1.out *.o *.so; + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs diff --git a/SANDHU__OS/README.md b/SANDHU__OS/README.md new file mode 100644 index 0000000..9996de8 --- /dev/null +++ b/SANDHU__OS/README.md @@ -0,0 +1,42 @@ +## Details + +Currently this operating system has kernel with interrupt, paging, hea0p, +virtual file system support and multitasking. Yet to enable support for user +space applications. +(More information in Sandbox) + +## Usage + +### To build project + +```shell + # -s for make quite + $ ./build.sh -s +``` + +### To run project + +```shell + $ ./run.sh +``` + +### To build with debug symbols + +```shell + # -s for make quite, -g for debug + $ ./build.sh -s -g +``` + +### To run project in debug mode + +```shell + $ ./run.sh -d +``` + +#### Note: Make sure to build with debug symbols + +```shell + $ gdb or gdbtui + $ target remote localhost:1234 + $ file build/bin/kernel.elf (loads debugging symbols from the file) +``` diff --git a/SANDHU__OS/build.sh b/SANDHU__OS/build.sh new file mode 100755 index 0000000..46e71b1 --- /dev/null +++ b/SANDHU__OS/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +make $1 clean + +make $1 D=$2 diff --git a/SANDHU__OS/build/bin/kernel.elf b/SANDHU__OS/build/bin/kernel.elf new file mode 100755 index 0000000..c50c4a3 Binary files /dev/null and b/SANDHU__OS/build/bin/kernel.elf differ diff --git a/SANDHU__OS/build/etc/bochsrc.txt b/SANDHU__OS/build/etc/bochsrc.txt new file mode 100644 index 0000000..2a95dc8 --- /dev/null +++ b/SANDHU__OS/build/etc/bochsrc.txt @@ -0,0 +1,10 @@ +megs: 32 +display_library: sdl2 +romimage: file=/usr/share/bochs/BIOS-bochs-legacy +vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest +ata0-master: type=cdrom, path=os.iso, status=inserted +boot: cdrom +log: bochslog.txt +clock: sync=realtime, time0=local +cpu: count=1, ips=1000000 +com1: enabled=1, mode=file, dev=sandhu.out diff --git a/SANDHU__OS/build/lib/libcommon.a b/SANDHU__OS/build/lib/libcommon.a new file mode 100644 index 0000000..6eedc78 Binary files /dev/null and b/SANDHU__OS/build/lib/libcommon.a differ diff --git a/SANDHU__OS/build/lib/libfs.a b/SANDHU__OS/build/lib/libfs.a new file mode 100644 index 0000000..703f335 Binary files /dev/null and b/SANDHU__OS/build/lib/libfs.a differ diff --git a/SANDHU__OS/build/lib/libgdt.a b/SANDHU__OS/build/lib/libgdt.a new file mode 100644 index 0000000..db3d7ff Binary files /dev/null and b/SANDHU__OS/build/lib/libgdt.a differ diff --git a/SANDHU__OS/build/lib/libidt.a b/SANDHU__OS/build/lib/libidt.a new file mode 100644 index 0000000..43c73ff Binary files /dev/null and b/SANDHU__OS/build/lib/libidt.a differ diff --git a/SANDHU__OS/build/lib/libinitrd.a b/SANDHU__OS/build/lib/libinitrd.a new file mode 100644 index 0000000..b4ceffa Binary files /dev/null and b/SANDHU__OS/build/lib/libinitrd.a differ diff --git a/SANDHU__OS/build/lib/libio.a b/SANDHU__OS/build/lib/libio.a new file mode 100644 index 0000000..6770d23 Binary files /dev/null and b/SANDHU__OS/build/lib/libio.a differ diff --git a/SANDHU__OS/build/lib/libkb.a b/SANDHU__OS/build/lib/libkb.a new file mode 100644 index 0000000..a8a23a5 Binary files /dev/null and b/SANDHU__OS/build/lib/libkb.a differ diff --git a/SANDHU__OS/build/lib/libkheap.a b/SANDHU__OS/build/lib/libkheap.a new file mode 100644 index 0000000..95e5a3c Binary files /dev/null and b/SANDHU__OS/build/lib/libkheap.a differ diff --git a/SANDHU__OS/build/lib/liblogger.a b/SANDHU__OS/build/lib/liblogger.a new file mode 100644 index 0000000..2ddaf2d Binary files /dev/null and b/SANDHU__OS/build/lib/liblogger.a differ diff --git a/SANDHU__OS/build/lib/liborderedarray.a b/SANDHU__OS/build/lib/liborderedarray.a new file mode 100644 index 0000000..20a344e Binary files /dev/null and b/SANDHU__OS/build/lib/liborderedarray.a differ diff --git a/SANDHU__OS/build/lib/libpaging.a b/SANDHU__OS/build/lib/libpaging.a new file mode 100644 index 0000000..78bea52 Binary files /dev/null and b/SANDHU__OS/build/lib/libpaging.a differ diff --git a/SANDHU__OS/build/lib/libsched.a b/SANDHU__OS/build/lib/libsched.a new file mode 100644 index 0000000..250e9c3 Binary files /dev/null and b/SANDHU__OS/build/lib/libsched.a differ diff --git a/SANDHU__OS/build/lib/libtimer.a b/SANDHU__OS/build/lib/libtimer.a new file mode 100644 index 0000000..385b36b Binary files /dev/null and b/SANDHU__OS/build/lib/libtimer.a differ diff --git a/SANDHU__OS/iso/boot/grub/menu.lst b/SANDHU__OS/iso/boot/grub/menu.lst new file mode 100644 index 0000000..1cf5b68 --- /dev/null +++ b/SANDHU__OS/iso/boot/grub/menu.lst @@ -0,0 +1,6 @@ + default=0 + timeout=0 + + title os + kernel /boot/kernel.elf + module /modules/initrd diff --git a/SANDHU__OS/iso/boot/grub/stage2_eltorito b/SANDHU__OS/iso/boot/grub/stage2_eltorito new file mode 100644 index 0000000..817dd07 Binary files /dev/null and b/SANDHU__OS/iso/boot/grub/stage2_eltorito differ diff --git a/SANDHU__OS/iso/boot/kernel.elf b/SANDHU__OS/iso/boot/kernel.elf new file mode 100755 index 0000000..c50c4a3 Binary files /dev/null and b/SANDHU__OS/iso/boot/kernel.elf differ diff --git a/SANDHU__OS/iso/modules/initrd b/SANDHU__OS/iso/modules/initrd new file mode 100644 index 0000000..03db9e2 Binary files /dev/null and b/SANDHU__OS/iso/modules/initrd differ diff --git a/SANDHU__OS/makeUtils/Makefile.defs b/SANDHU__OS/makeUtils/Makefile.defs new file mode 100644 index 0000000..9a8ba3a --- /dev/null +++ b/SANDHU__OS/makeUtils/Makefile.defs @@ -0,0 +1,19 @@ +.PHONY: all clean install + +all: $(SUBDIRS) + for subdir in $(SUBDIRS) ; do \ + make -C $$subdir all || exit 1; \ + done + +clean: $(SUBDIRS) rmOBJS + for subdir in $(SUBDIRS) ; do \ + make -C $$subdir clean ; \ + done + +install: $(SUBDIRS) + for subdir in $(SUBDIRS) ; do \ + make -C $$subdir install || exit 1; \ + done + +rmOBJS: + rm -rf .DS_Store *.o *.so *.a *.out diff --git a/SANDHU__OS/makeUtils/Makefile.include b/SANDHU__OS/makeUtils/Makefile.include new file mode 100644 index 0000000..6e1c368 --- /dev/null +++ b/SANDHU__OS/makeUtils/Makefile.include @@ -0,0 +1,21 @@ +CC = gcc + +# Pass gdb debug flag from command line +# Usage `make D=-g` +CC += $(D) + +CFLAGS += -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \ + -nostartfiles -nodefaultlibs -Wall -Wextra -Werror + +AS = nasm +ASFLAGS = -f elf + +C_SOURCES += $(wildcard *.c) +S_SOURCES += $(wildcard *.s) +C_OBJECTS += $(C_SOURCES:.c=.o) +S_OBJECTS += $(S_SOURCES:.s=.o) + +LDFLAGS += \ + -L$(LIB_DIR) \ + +INCLUDE += \ diff --git a/SANDHU__OS/qemu.log b/SANDHU__OS/qemu.log new file mode 100644 index 0000000..a7dae94 --- /dev/null +++ b/SANDHU__OS/qemu.log @@ -0,0 +1,106 @@ +c[?7lSeaBIOS (version 1.15.0-1) + + +iPXE (https://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+BFF8B4A0+BFECB4A0 CA00 +Press Ctrl-B to configure iPXE (PCI 00:03.0)... + + +Booting from Hard Disk... +Boot failed: could not read the boot disk + +Booting from Floppy... +Boot failed: could not read the boot disk + +Booting from DVD/CD... +Loading stage2 .... + + GNU GRUB version 0.95 (639K lower / 3144576K upper memory)┌─────────────────────────────────────────────────────────────────────────┐││││││││││││││││││││││││└─────────────────────────────────────────────────────────────────────────┘ + Use the ↑ and ↓ keys to select which entry is highlighted. + Press enter to boot the selected OS, 'e' to edit the + commands before booting, or 'c' for a command-line.  os               Booting 'os' + +kernel /boot/kernel.elf + [Multiboot-elf, <0x100000:0x498b:0x0>, <0x105000:0x14e0:0x0>, <0x107000:0xa1 +0:0x225c>, shtab=0x10a230, entry=0x100d7c] +module /modules/initrd + [Multiboot-module @ 0x10c000, 0x1349 bytes +============================== +Testing COM port... it works!!! + +============================== +Testing Interrupt by raising interrupt 34 +Recieved interrupt 34!! + + +============================== +Testing paging, trying to access address +Testing paging, trying to access address 1155104 + +Recieved interrupt 14!! +Page fault! ( ) at address = 1155104 +Creating page at address 1155104 +Out of page fault, page allocation works!!! + +============================== +Testing kernel heap.... +============================== +Testing kernel malloc.... +Calling kmalloc() for allocating 8 bytes +kmalloc() allocated 8 bytes at address: 3221762116 + +Calling kmalloc() for allocating 10 bytes +kmalloc() allocated 10 bytes at address: 3221762144 + +Calling kmalloc() for allocating 8 bytes +kmalloc() allocated 8 bytes at address: 3221762174 + +============================== +Testing kernel free.... +Calling kfree() to deallocate address: 3221762116 + +Calling kmalloc() for allocating 20 bytes +kmalloc() allocated 20 bytes at address: 3221762202 + +Calling kmalloc() for allocating 8 bytes +kmalloc() allocated 8 bytes at address: 3221762116 + +============================== +Testing Multiboot... +Mboot address loaded at 183680 +Initrd loaded at address 1097728 +Multiboot modules end at address 1102665 +Number of modules loaded = 1 + +============================== +Testing virtual file system +reading contents of directory /dev + +Found file -> file1.txt + contents: Hello, you just loaded first file from VFS! + + +Found file -> file2.txt + contents: This is the second file! + + + +============================== +Testing multitasking +Calling process fork + + +============================== +fork() returned 2, and getpid() returned 1 +============================================================================ + +============================== +Keyboard Enabled, type something!!!! + + +============================== +fork() returned 0, and getpid() returned 2 +============================================================================ + +============================== +Keyboard Enabled, type something!!!! +qemu-system-i386: terminating on signal 15 from pid 1902 (/lib/systemd/systemd) diff --git a/SANDHU__OS/run.sh b/SANDHU__OS/run.sh new file mode 100755 index 0000000..da12312 --- /dev/null +++ b/SANDHU__OS/run.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +if [ "$#" -eq 1 ]; then + if [ $1 = "-d" ]; then + debug="-S"; + echo "Running in debug mode" + else + echo " './run.sh -d' to run in debug mode" + exit 1 + fi +fi + +cp build/bin/kernel.elf iso/boot/kernel.elf + +genisoimage -R \ +-b boot/grub/stage2_eltorito \ +-no-emul-boot \ +-boot-load-size 4 \ +-A os \ +-input-charset utf8 \ +-quiet \ +-boot-info-table \ +-o sandhu.iso \ +iso + +unset GTK_PATH # This is needed to run qemu on my system + +qemu-system-i386 -cdrom sandhu.iso -m 4G -s -serial stdio $debug diff --git a/SANDHU__OS/sandhu.iso b/SANDHU__OS/sandhu.iso new file mode 100644 index 0000000..0e151d4 Binary files /dev/null and b/SANDHU__OS/sandhu.iso differ diff --git a/SANDHU__OS/src/Makefile b/SANDHU__OS/src/Makefile new file mode 100644 index 0000000..d2fec75 --- /dev/null +++ b/SANDHU__OS/src/Makefile @@ -0,0 +1,9 @@ +SUBDIRS = \ + drivers \ + mm \ + utils \ + kernel \ + + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs diff --git a/SANDHU__OS/src/drivers/Makefile b/SANDHU__OS/src/drivers/Makefile new file mode 100644 index 0000000..9795957 --- /dev/null +++ b/SANDHU__OS/src/drivers/Makefile @@ -0,0 +1,10 @@ +SUBDIRS = \ + frame_buffer \ + interrupts \ + io \ + keyboard \ + serial_port \ + timer + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs diff --git a/SANDHU__OS/src/drivers/frame_buffer/Makefile b/SANDHU__OS/src/drivers/frame_buffer/Makefile new file mode 100644 index 0000000..8638b4c --- /dev/null +++ b/SANDHU__OS/src/drivers/frame_buffer/Makefile @@ -0,0 +1,5 @@ +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs diff --git a/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.c b/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.c new file mode 100644 index 0000000..a2fffc0 --- /dev/null +++ b/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.c @@ -0,0 +1,83 @@ +#include "frame_buffer.h" +#include + +static int8_t *fb = (int8_t *)FB_BASE_ADDRESS; +static uint16_t CURSOR_POS = 0; +static uint16_t CURSOR_POS_MAX = 2000; +static uint16_t BACKGROUND_COLOR = FB_GREEN; +static uint16_t FOREGROUND_COLOR = FB_DARK_GREY; + +/* fb_move_cursor: + * Moves the cursor of the framebuffer to the CURSOR_POS global variable + */ +void fb_move_cursor() { + outb(FB_COMMAND_PORT, FB_HIGH_BYTE_COMMAND); + outb(FB_DATA_PORT, ((CURSOR_POS >> 8) & 0x00FF)); + outb(FB_COMMAND_PORT, FB_LOW_BYTE_COMMAND); + outb(FB_DATA_PORT, CURSOR_POS & 0x00FF); +} + +/* fb_clear: + * Clear the contents on screen between start position and end position + * + * @param start Starting position + * @param end End position + */ + +void fb_clear(uint16_t start, uint16_t end) { + for (uint16_t i = start; i < end; i++) { + fb[2 * i] = ' '; + fb[2 * i + 1] = ((FB_BLACK & 0x0F) << 4) | (FB_WHITE & 0x0F); + } +} + +void fb_clear_all() { + fb_clear(0, CURSOR_POS_MAX); + CURSOR_POS = 0; + fb_move_cursor(); +} + +/* fb_write_cell: + * Writes a character with the given foreground and background to position i + * in the framebuffer. + * + * @param i The location in the framebuffer + * @param c The character + * @param fg The foreground color + * @param bg The background color + */ +void fb_write_cell(int8_t c, uint8_t fg, uint8_t bg) { + if (c == '\n') { + uint16_t cursor_temp_pos = CURSOR_POS; + CURSOR_POS = ((CURSOR_POS / 79) + 1) * 80; + if (CURSOR_POS >= CURSOR_POS_MAX) { + fb_clear(0, CURSOR_POS_MAX); + CURSOR_POS = 0; + } else { + fb_clear(cursor_temp_pos, CURSOR_POS); + } + } else if (c != '\0') { + if (CURSOR_POS >= CURSOR_POS_MAX) { + fb_clear(0, CURSOR_POS_MAX); + CURSOR_POS = 0; + } + fb[2 * CURSOR_POS] = c; + fb[2 * CURSOR_POS + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F); + CURSOR_POS++; + } +} + +int32_t fb_write(int8_t *buf, uint32_t len) { + uint32_t index_to_buffer = 0; + while (index_to_buffer < len) { + fb_write_cell(buf[index_to_buffer], BACKGROUND_COLOR, FOREGROUND_COLOR); + fb_move_cursor(); + index_to_buffer++; + } + return 0; +} + +void fb_set_color(uint16_t background, uint16_t foreground) { + BACKGROUND_COLOR = background; + FOREGROUND_COLOR = foreground; +} diff --git a/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.h b/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.h new file mode 100644 index 0000000..ff6e1ab --- /dev/null +++ b/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.h @@ -0,0 +1,39 @@ +#ifndef INCLUDE_FRAMEBUFFER_H +#define INCLUDE_FRAMEBUFFER_H + +#pragma once +#include + +/* The I/O ports */ +#define FB_COMMAND_PORT 0x3D4 +#define FB_DATA_PORT 0x3D5 + +/* The I/O port commands */ +#define FB_HIGH_BYTE_COMMAND 14 +#define FB_LOW_BYTE_COMMAND 15 + +/* Frame buffer base address */ +#define FB_BASE_ADDRESS 0xB8000 + +/* fb_write: + * writes the contents of the buffer buf of length len to the screen + * + * @param buf Buffer that has contents to be written to screen + * @param len Length of buffer + */ +int32_t fb_write(int8_t *buf, uint32_t len); + +/* fb_clear_all: + * Clear all the contents on screen + */ +void fb_clear_all(); + +/* fb_set_color: + * Sets the color of text to be displayed on screen + * + * @param background Background color + * @param foreground Foreground color + */ +void fb_set_color(uint16_t background, uint16_t foreground); + +#endif /* INCLUDE_FRAMEBUFFER_H */ diff --git a/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.o b/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.o new file mode 100644 index 0000000..ce0d94e Binary files /dev/null and b/SANDHU__OS/src/drivers/frame_buffer/frame_buffer.o differ diff --git a/SANDHU__OS/src/drivers/interrupts/Makefile b/SANDHU__OS/src/drivers/interrupts/Makefile new file mode 100644 index 0000000..d5f80e1 --- /dev/null +++ b/SANDHU__OS/src/drivers/interrupts/Makefile @@ -0,0 +1,24 @@ +all: libidt.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/drivers/io/ \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +# Generate Static library +SC_FLAG = ar -cvq + +libidt.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/drivers/interrupts/idt.c b/SANDHU__OS/src/drivers/interrupts/idt.c new file mode 100644 index 0000000..bd6c467 --- /dev/null +++ b/SANDHU__OS/src/drivers/interrupts/idt.c @@ -0,0 +1,116 @@ +#include "idt.h" +#include + +/* Function call to load IDT implemented in assembly. + * Extern allows to access ASM from this C code. + */ +extern void idt_flush(uint32_t); + +/* 256 interrupts!!! */ +idt_entry_t idt_entries[256]; + +/* When processor enters protected mode the first command you will need to give + * the two PICs is the initialise command (code 0x11). This command makes the + * PIC wait for 3 extra "initialisation words" on the data port. + */ +void init_pic() { + /* Start the initialization sequence */ + outb(PIC1, INITIALISE_COMMAND); + outb(PIC2, INITIALISE_COMMAND); + + /* Set new interrupt vector offset instead of default oofset */ + outb(PIC1_DATA, PIC1_VECTOR_OFFSET); + outb(PIC2_DATA, PIC2_VECTOR_OFFSET); + + /* Tell PIC1 there is Slave at PIN 2 (0000 0100) */ + outb(PIC1_DATA, PIC2_PORT_IN_PIC1); + + /* Tell Slave PIC its cascade identity (0000 0010) */ + outb(PIC2_DATA, PIC2_CASCADED_IDEN); + + /* Set PICs to operate in 8086/88 (MCS-80/85) mode */ + outb(PIC1_DATA, ICW4_8086); + outb(PIC2_DATA, ICW4_8086); + + /* Null out the data registers */ + outb(PIC1_DATA, 0x0); + outb(PIC2_DATA, 0x0); +} + +/* Set the value of IDT entry. */ +static void idt_set_gate(uint8_t num, uint32_t addressISR, uint16_t segmentSelector, + uint8_t accessGran) { + idt_entries[num].offset_low = (addressISR & 0xFFFF); + idt_entries[num].segment_selector = segmentSelector; + idt_entries[num].alwaysZero = 0; + + idt_entries[num].access_gran = accessGran; + + idt_entries[num].offset_high = addressISR >> 16; +} + +void init_idt() { + idt_ptr_t idt_ptr; + idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; + idt_ptr.base = (uint32_t)&idt_entries; + + /* Initialise PIC */ + init_pic(); + + /* Setting everything to 0 as handler for interrupts above 32 are not set */ + // memset(&idt_entries, 0, sizeof(idt_entry_t) * 256); + + /* Define handlers for first 32 which are required by processor */ + idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E); // ISR 0 + idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E); // ISR 1 + idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E); // ISR 2 + idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E); // ISR 3 + idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E); // ISR 4 + idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E); // ISR 5 + idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E); // ISR 6 + idt_set_gate(7, (uint32_t)isr7, 0x08, 0x8E); // ISR 7 + idt_set_gate(8, (uint32_t)isr8, 0x08, 0x8E); // ISR 8 + idt_set_gate(9, (uint32_t)isr9, 0x08, 0x8E); // ISR 9 + idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E); // ISR 10 + idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E); // ISR 11 + idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E); // ISR 12 + idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E); // ISR 13 + idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E); // ISR 14 + idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E); // ISR 15 + idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E); // ISR 16 + idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E); // ISR 17 + idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E); // ISR 18 + idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E); // ISR 19 + idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E); // ISR 20 + idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E); // ISR 21 + idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E); // ISR 22 + idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E); // ISR 23 + idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E); // ISR 24 + idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E); // ISR 25 + idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E); // ISR 26 + idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E); // ISR 27 + idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E); // ISR 28 + idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E); // ISR 29 + idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E); // ISR 30 + idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E); // ISR 31 + + /* Define handlers for 16 interrupt requests by pic */ + idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); // IRQ 0 + idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); // IRQ 1 + idt_set_gate(34, (uint32_t)irq2, 0x08, 0x8E); // IRQ 2 + idt_set_gate(35, (uint32_t)irq3, 0x08, 0x8E); // IRQ 3 + idt_set_gate(36, (uint32_t)irq4, 0x08, 0x8E); // IRQ 4 + idt_set_gate(37, (uint32_t)irq5, 0x08, 0x8E); // IRQ 5 + idt_set_gate(38, (uint32_t)irq6, 0x08, 0x8E); // IRQ 6 + idt_set_gate(39, (uint32_t)irq7, 0x08, 0x8E); // IRQ 7 + idt_set_gate(40, (uint32_t)irq8, 0x08, 0x8E); // IRQ 8 + idt_set_gate(41, (uint32_t)irq9, 0x08, 0x8E); // IRQ 9 + idt_set_gate(42, (uint32_t)irq10, 0x08, 0x8E); // IRQ 10 + idt_set_gate(43, (uint32_t)irq11, 0x08, 0x8E); // IRQ 11 + idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E); // IRQ 12 + idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E); // IRQ 13 + idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E); // IRQ 14 + idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E); // IRQ 15 + + idt_flush((uint32_t)&idt_ptr); +} diff --git a/SANDHU__OS/src/drivers/interrupts/idt.h b/SANDHU__OS/src/drivers/interrupts/idt.h new file mode 100644 index 0000000..47a8321 --- /dev/null +++ b/SANDHU__OS/src/drivers/interrupts/idt.h @@ -0,0 +1,169 @@ +#ifndef INCLUDE_IDT_H +#define INCLUDE_IDT_H + +#pragma once +#include + +/* The processor will sometimes need to signal your kernel. Something major may + * have happened, such as a divide-by-zero, or a page fault. To do this, it uses + * the first 32 interrupts. It is therefore doubly important that all of these + * are mapped and non-NULL - else the CPU will triple-fault and reset. + * + * + * The special, CPU-dedicated interrupts are shown below. + * + * 0 - Division by zero exception + * 1 - Debug exception + * 2 - Non maskable interrupt + * 3 - Breakpoint exception + * 4 - 'Into detected overflow' + * 5 - Out of bounds exception + * 6 - Invalid opcode exception + * 7 - No coprocessor exception + * 8 - Double fault (pushes an error code) + * 9 - Coprocessor segment overrun + * 10 - Bad TSS (pushes an error code) + * 11 - Segment not present (pushes an error code) + * 12 - Stack fault (pushes an error code) + * 13 - General protection fault (pushes an error code) + * 14 - Page fault (pushes an error code) + * 15 - Unknown interrupt exception + * 16 - Coprocessor fault + * 17 - Alignment check exception + * 18 - Machine check exception + * 19-31 - Reserved + * + * + * Following are the function call to above 32 interrupt handlers. + * Extern allows to access ASM from this C code. + */ +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +/* Common Definitions for PIC */ +#define PIC1 0x20 /* IO base address for master PIC */ +#define PIC2 0xA0 /* IO base address for slave PIC */ +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1 + 1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2 + 1) + +/* reinitialize the PIC controllers, giving them specified vector offsets + * rather than 8h and 70h, as configured by default + */ +#define INITIALISE_COMMAND 0x11 +#define PIC1_VECTOR_OFFSET 0x20 /* re-map to ISR 32 */ +#define PIC2_VECTOR_OFFSET 0x28 /* re-map to ISR 40 */ +#define PIC2_PORT_IN_PIC1 0x04 /* PIC1's port address for PIC2 - 00000100b */ +#define PIC2_CASCADED_IDEN 0x02 /* PIC2's identity is 2 for Master (PIC1)*/ +#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ + +/* To start using hardware interrupts Programmable Interrupt Controller (PIC) + * needs to be configured. The PIC makes it possible to map signals from the + * hardware to interrupts. The reasons for configuring the PIC are: Remap the + * interrupts. The PIC uses interrupts 0 - 15 for hardware interrupts by + * default, which conflicts with the CPU interrupts. Therefore the PIC + * interrupts must be remapped to another interval. Select which interrupts to + * receive. Set up the correct mode for the PIC. + * + * The hardware interrupts are shown in the table below: + * + * PIC1: + * 0 - Timer + * 1 - Keyboard + * 2 - PIC 2 + * 3 - COM 2 + * 4 - COM 1 + * 5 - LPT 2 + * 6 - Floppy disk + * 7 - LPT 1 + * + * PIC2: + * 8 - Real Time Clock + * 9 - General I/O + * 10 - General I/O + * 11 - General I/O + * 12 - General I/O + * 13 - Coprocessor + * 14 - IDE Bus + * 15 - IDE Bus + * + * Following are the function call to above 16 interrupt requests. + * Extern allows to access ASM from this C code. + */ +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +/* This structure contains the value of one IDT entry. + * We use the attribute 'packed' to tell GCC not to change + * any of the alignment in the structure. + */ +struct idt_entry_struct { + uint16_t offset_low; /* The lowest 16 bits of the 32 bit ISR address. */ + uint16_t segment_selector; /* Segment Selector. */ + uint8_t alwaysZero; /* This 8 bits are always 0. */ + uint8_t access_gran; /* Access flags, granularity and few reserved bits. */ + uint16_t offset_high; /* The highest 16 bits of the 32 bit ISR address. */ +} __attribute__((packed)); + +typedef struct idt_entry_struct idt_entry_t; + +/* This struct describes a IDT pointer. It points to the start of + * our array of IDT entries, and is in the format required by the + * lidt instruction. + */ +struct idt_ptr_struct { + uint16_t limit; /* The upper 16 bits of the table with entries. */ + uint32_t base; /* The address of the first idt_entry_t struct. */ +} __attribute__((packed)); + +typedef struct idt_ptr_struct idt_ptr_t; + +/* Function to initialize IDT */ +void init_idt(); + +#endif /* INCLUDE_IDT_H */ diff --git a/SANDHU__OS/src/drivers/interrupts/idt.o b/SANDHU__OS/src/drivers/interrupts/idt.o new file mode 100644 index 0000000..faef956 Binary files /dev/null and b/SANDHU__OS/src/drivers/interrupts/idt.o differ diff --git a/SANDHU__OS/src/drivers/interrupts/idt_asm.o b/SANDHU__OS/src/drivers/interrupts/idt_asm.o new file mode 100644 index 0000000..3a01184 Binary files /dev/null and b/SANDHU__OS/src/drivers/interrupts/idt_asm.o differ diff --git a/SANDHU__OS/src/drivers/interrupts/idt_asm.s b/SANDHU__OS/src/drivers/interrupts/idt_asm.s new file mode 100644 index 0000000..603b761 --- /dev/null +++ b/SANDHU__OS/src/drivers/interrupts/idt_asm.s @@ -0,0 +1,9 @@ +global idt_flush ; Allows the C code to call gdt_flush(). + +; load_idt - Loads the interrupt descriptor table (IDT). +; stack: [esp + 4] the address of the first entry in the IDT +; [esp ] the return address +idt_flush: +mov eax, [esp+4] ; load the address of the IDT into register eax +lidt [eax] ; load the IDT +ret ; return to the calling function diff --git a/SANDHU__OS/src/drivers/interrupts/isr.c b/SANDHU__OS/src/drivers/interrupts/isr.c new file mode 100644 index 0000000..6d602df --- /dev/null +++ b/SANDHU__OS/src/drivers/interrupts/isr.c @@ -0,0 +1,46 @@ +#include "isr.h" +#include +#include +#include + +isr_t interrupt_handlers[256]; +const uint8_t TIME_INTERRUPT_NUMBER = 32; +const uint8_t KEYBOARD_INTERRUPT_NUMBER = 33; + +/* Function to register interrupt handler with custom call back function */ +void register_interrupt_handler(uint8_t n, isr_t handler) { + interrupt_handlers[n] = handler; +} + +/* This gets called from our ASM interrupt handler stub. */ +void interrupt_handler(registers_t regs) { + /* Send an EOI (end of interrupt) signal to the PICs. */ + + /* If this interrupt involved PIC2/slave. */ + if (regs.stack_contents.int_no >= 40) { + outb(0xA0, 0x20); + } + /* Send reset signal to PIC1/master. */ + if (regs.stack_contents.int_no >= 32) { + outb(0x20, 0x20); + } + + /* Does not print if timer interrupt, + * (avoiding too many messages on screen). + */ + if ((regs.stack_contents.int_no != TIME_INTERRUPT_NUMBER) && + regs.stack_contents.int_no != KEYBOARD_INTERRUPT_NUMBER) { + print_serial("\nRecieved interrupt "); + print_screen("\nRecieved interrupt "); + print_serial(integer_to_string(regs.stack_contents.int_no)); + print_screen(integer_to_string(regs.stack_contents.int_no)); + print_serial("!!\n"); + print_screen("!!\n"); + } + + /* If there is a callback function registered call that function */ + if (interrupt_handlers[regs.stack_contents.int_no] != 0) { + isr_t handler = interrupt_handlers[regs.stack_contents.int_no]; + handler(regs); + } +} diff --git a/SANDHU__OS/src/drivers/interrupts/isr.h b/SANDHU__OS/src/drivers/interrupts/isr.h new file mode 100644 index 0000000..525156f --- /dev/null +++ b/SANDHU__OS/src/drivers/interrupts/isr.h @@ -0,0 +1,46 @@ +#ifndef INCLUDE_ISR_H +#define INCLUDE_ISR_H + +#pragma once +#include + +typedef struct cpu_state { + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; +} cpu_state_t; + +typedef struct stack_state { + uint32_t int_no; + uint32_t err_code; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t useresp; + uint32_t ss; +} stack_state_t; + +typedef struct registers { + /* Data segment selector */ + uint32_t ds; + /* Pushed by pusha */ + cpu_state_t cpu_registers; + /* Interrupt number and error code (if applicable). Pushed by the processor + * automatically. + */ + stack_state_t stack_contents; +} registers_t; + +typedef void (*isr_t)(registers_t); + +void register_interrupt_handler(uint8_t n, isr_t handler); + +/* Function to initialize IDT */ +void init_idt(); + +#endif /* INCLUDE_ISR_H */ diff --git a/SANDHU__OS/src/drivers/interrupts/isr.o b/SANDHU__OS/src/drivers/interrupts/isr.o new file mode 100644 index 0000000..6c43efb Binary files /dev/null and b/SANDHU__OS/src/drivers/interrupts/isr.o differ diff --git a/SANDHU__OS/src/drivers/interrupts/isr_asm.o b/SANDHU__OS/src/drivers/interrupts/isr_asm.o new file mode 100644 index 0000000..d123aac Binary files /dev/null and b/SANDHU__OS/src/drivers/interrupts/isr_asm.o differ diff --git a/SANDHU__OS/src/drivers/interrupts/isr_asm.s b/SANDHU__OS/src/drivers/interrupts/isr_asm.s new file mode 100644 index 0000000..9664759 --- /dev/null +++ b/SANDHU__OS/src/drivers/interrupts/isr_asm.s @@ -0,0 +1,140 @@ +; isr handler is implemented in isr.c +extern interrupt_handler + +;macro for no error code handler starts from here +%macro no_error_code_interrupt_handler 1 ; define a macro, taking one parameter + +global isr%1 ; %1 accesses the first parameter. + isr%1: + cli ; Disable interrupts + push dword 0 ; push 0 as error code + push dword %1 ; push the interrupt number + jmp common_interrupt_handler ; jump to the common handler + +%endmacro +; no error code handler macro end + + +;macro for error code handler starts from here +%macro error_code_interrupt_handler 1 ; define a macro, taking one parameter + +global isr%1 + isr%1: + cli ; Disable interrupts + push dword %1 ; push the interrupt number + jmp common_interrupt_handler ; jump to the common handler + +%endmacro +;macro for error code handler end + +;macro for interrupt handler for PIC starts +; This macro creates a stub for an IRQ - the first parameter is +; the IRQ number, the second is the ISR number it is remapped to. +%macro irq_pic_interrupt_handler 2 ; define a macro, taking two parameter + +global irq%1 ; %1 accesses the first parameter. + irq%1: + cli ; Disable interrupts + push dword 0 ; push 0 as error code + push dword %2 ; push the interrupt number + jmp common_interrupt_handler ; jump to the common handler for irq + +%endmacro +; interrupt handler for PIC macro end + +; define macros for all 32 interrupts, 8, 10, 11, 12, 13, 14 generate error code +no_error_code_interrupt_handler 0 +no_error_code_interrupt_handler 1 +no_error_code_interrupt_handler 2 +no_error_code_interrupt_handler 3 +no_error_code_interrupt_handler 4 +no_error_code_interrupt_handler 5 +no_error_code_interrupt_handler 6 +no_error_code_interrupt_handler 7 +error_code_interrupt_handler 8 +no_error_code_interrupt_handler 9 +error_code_interrupt_handler 10 +error_code_interrupt_handler 11 +error_code_interrupt_handler 12 +error_code_interrupt_handler 13 +error_code_interrupt_handler 14 +no_error_code_interrupt_handler 15 +no_error_code_interrupt_handler 16 +no_error_code_interrupt_handler 17 +no_error_code_interrupt_handler 18 +no_error_code_interrupt_handler 19 +no_error_code_interrupt_handler 20 +no_error_code_interrupt_handler 21 +no_error_code_interrupt_handler 22 +no_error_code_interrupt_handler 23 +no_error_code_interrupt_handler 24 +no_error_code_interrupt_handler 25 +no_error_code_interrupt_handler 26 +no_error_code_interrupt_handler 27 +no_error_code_interrupt_handler 28 +no_error_code_interrupt_handler 29 +no_error_code_interrupt_handler 30 +no_error_code_interrupt_handler 31 + +; define macros for all 16 IRQ interrupts +irq_pic_interrupt_handler 0,32 +irq_pic_interrupt_handler 1,33 +irq_pic_interrupt_handler 2,34 +irq_pic_interrupt_handler 3,35 +irq_pic_interrupt_handler 4,36 +irq_pic_interrupt_handler 5,37 +irq_pic_interrupt_handler 6,38 +irq_pic_interrupt_handler 7,39 +irq_pic_interrupt_handler 8,40 +irq_pic_interrupt_handler 9,41 +irq_pic_interrupt_handler 10,42 +irq_pic_interrupt_handler 11,43 +irq_pic_interrupt_handler 12,44 +irq_pic_interrupt_handler 13,45 +irq_pic_interrupt_handler 14,46 +irq_pic_interrupt_handler 15,47 + +; Common ISR stub. It saves the processor state, sets +; up for kernel mode segments, calls the C-level fault handler, +; and finally restores the stack frame. +common_interrupt_handler: ; the common parts of the generic + ; interrupt handler + ; save the registers + pusha ; Pushes eax, ebx, ecx, edx, edi, esi, + ; ebp, esp, + + mov ax, ds ; Lower 16-bits of eax = ds. + push eax ; save the data segment descriptor + + mov ax, 0x10 ; load the kernel data segment + mov ds, ax ; descriptor, this is because ISR is + mov es, ax ; defined in Kernel's data segment. + mov fs, ax + mov gs, ax + + ; call the C function + call interrupt_handler + + ; restore the registers + pop eax ; reload the original data segment + mov ds, ax ; descriptor + mov es, ax + mov fs, ax + mov gs, ax + + popa ; Pops edi,esi,ebp... + + ; restore the esp + add esp, 8 ; Cleans up the pushed error code and + ; pushed ISR number + + sti ; set interrupts + + ; return to the code that got interrupted + ; When an interrupt fires, the processor automatically pushes information + ; about the processor state onto the stack. The code segment, instruction + ; pointer, flags register, stack segment and stack pointer are pushed. The + ; IRET instruction is specifically designed to return from an interrupt. It + ; pops these values off the stack and returns the processor to the state it + ; was in originally. + iret diff --git a/SANDHU__OS/src/drivers/io/Makefile b/SANDHU__OS/src/drivers/io/Makefile new file mode 100644 index 0000000..a4fbb53 --- /dev/null +++ b/SANDHU__OS/src/drivers/io/Makefile @@ -0,0 +1,16 @@ +all: libio.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +# Generate Static library +SC_FLAG = ar -cvq + +libio.a: $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/drivers/io/io.h b/SANDHU__OS/src/drivers/io/io.h new file mode 100644 index 0000000..b854ddd --- /dev/null +++ b/SANDHU__OS/src/drivers/io/io.h @@ -0,0 +1,23 @@ +#ifndef INCLUDE_IO_H +#define INCLUDE_IO_H + +#pragma once +#include + +/** outb: + * Sends the given data to the given I/O port. Defined in io.s + * + * @param port The I/O port to send the data to + * @param data The data to send to the I/O port + */ +void outb(uint16_t port, uint8_t data); + +/** inb: + * Read a byte from an I/O port. + * + * @param port The address of the I/O port + * @return The read byte + */ +uint8_t inb(uint16_t port); + +#endif /* INCLUDE_IO_H */ diff --git a/SANDHU__OS/src/drivers/io/io.o b/SANDHU__OS/src/drivers/io/io.o new file mode 100644 index 0000000..427d9c9 Binary files /dev/null and b/SANDHU__OS/src/drivers/io/io.o differ diff --git a/SANDHU__OS/src/drivers/io/io.s b/SANDHU__OS/src/drivers/io/io.s new file mode 100644 index 0000000..60f4c7c --- /dev/null +++ b/SANDHU__OS/src/drivers/io/io.s @@ -0,0 +1,22 @@ +global outb ; make the label outb visible outside this file + +; outb - send a byte to an I/O port +; stack: [esp + 8] the data byte +; [esp + 4] the I/O port +; [esp ] return address +outb: + mov al, [esp + 8] ; move the data to be sent into the al register + mov dx, [esp + 4] ; move the address of the I/O port into the dx register + out dx, al ; send the data to the I/O port + ret ; return to the calling function + +global inb + +; inb - returns a byte from the given I/O port +; stack: [esp + 4] The address of the I/O port +; [esp ] The return address +inb: + mov dx, [esp + 4] ; move the address of the I/O port to the dx register + in al, dx ; read a byte from the I/O port and store it in the al + ; register + ret ; return the read byte diff --git a/SANDHU__OS/src/drivers/keyboard/Makefile b/SANDHU__OS/src/drivers/keyboard/Makefile new file mode 100644 index 0000000..967ac53 --- /dev/null +++ b/SANDHU__OS/src/drivers/keyboard/Makefile @@ -0,0 +1,22 @@ +all: libkb.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/drivers/io/ \ + -I$(TOP_DIR)/src/drivers/interrupts \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +# Generate Static library +SC_FLAG = ar -cvq + +libkb.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ diff --git a/SANDHU__OS/src/drivers/keyboard/kb.c b/SANDHU__OS/src/drivers/keyboard/kb.c new file mode 100644 index 0000000..ab74249 --- /dev/null +++ b/SANDHU__OS/src/drivers/keyboard/kb.c @@ -0,0 +1,136 @@ +#include "kb.h" +#include +#include +#include + +#define IRQ1 33 + +/* + * uskbd means US Keyboard Layout. This is a scancode table + * used to layout a standard US keyboard. + */ +int8_t uskbd[LEN_256] = { + 0, 27, /* Escape */ + '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ + '9', '0', '-', '=', '\b', /* Backspace */ + '\t', /* Tab */ + 'q', 'w', 'e', 'r', /* 19 */ + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ + 0, /* Control key */ + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ + '\'', '`', 0, /* Left shift */ + '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ + 'm', ',', '.', '/', 0, /* Right shift */ + '*', /* Num pad '*' */ + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + 0, /* 59 - F1 key ... > */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + '-', /* Num pad '-' */ + 0, /* Left Arrow */ + 0, 0, /* Right Arrow */ + '+', /* Num pad '+' */ + 0, /* 79 - End key*/ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ +}; + +int8_t uskbdShifted[LEN_256] = { + 0, 27, /* Escape */ + '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */ + '(', ')', '_', '+', '\b', /* Backspace */ + '\t', /* Tab */ + 'Q', 'W', 'E', 'R', /* 19 */ + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */ + 0, /* Control key */ + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */ + '\"', '~', 0, /* Left shift */ + '|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */ + 'M', '<', '>', '?', 0, /* Right shift */ + '*', /* Num pad '*' */ + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + 0, /* 59 - F1 key ... > */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + '-', /* Num pad '-' */ + 0, /* Left Arrow */ + 0, 0, /* Right Arrow */ + '+', /* Num pad '+' */ + 0, /* 79 - End key*/ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ + +}; + +static volatile uint8_t g_shiftPressed = 0; +static volatile uint8_t g_capsLockON = 0; + +/* Handles the keyboard interrupt */ +/* TODO: Test all characters, tab prints unknown character */ +void keyboard_callback(registers_t regs __attribute__((unused))) { + uint8_t scancode; + + /* Read from the keyboard's data buffer */ + scancode = inb(KEYBOARD_DATA_PORT); + + /* If the top bit of the byte we read from the keyboard is + * set, that means that a key has just been released */ + if (scancode & MASK_BIT8) { + /* Check if shift key was released */ + if (scancode == RELEASED_SHIFT_LEFT || scancode == RELEASED_SHIFT_RIGHT) { + g_shiftPressed = 0; + } + } else { + /* Check if it is capslock */ + if (scancode == PRESSED_CAPS_LOCK) { + g_capsLockON = !g_capsLockON; + return; + } + + if (g_capsLockON) { + print_serial_ch(uskbdShifted[scancode]); + print_screen_ch(uskbdShifted[scancode]); + } else { + /* Check if it is shift key */ + if (scancode == PRESSED_SHIFT_LEFT || scancode == PRESSED_SHIFT_RIGHT) { + g_shiftPressed = 1; + } else { + if (g_shiftPressed) { + print_serial_ch(uskbdShifted[scancode]); + print_screen_ch(uskbdShifted[scancode]); + } else { + print_serial_ch(uskbd[scancode]); + print_screen_ch(uskbd[scancode]); + } + } + } + } +} + +/* Installs the keyboard handler into IRQ1 */ +void init_keyboard() { + /* Register callback for keyboard interrupt (Interrupt 1) */ + register_interrupt_handler(IRQ1, keyboard_callback); +} diff --git a/SANDHU__OS/src/drivers/keyboard/kb.h b/SANDHU__OS/src/drivers/keyboard/kb.h new file mode 100644 index 0000000..8488bc5 --- /dev/null +++ b/SANDHU__OS/src/drivers/keyboard/kb.h @@ -0,0 +1,8 @@ +#ifndef INCLUDE_KEYBOARD_H +#define INCLUDE_KEYBOARD_H + +#pragma once + +void init_keyboard(); + +#endif /* INCLUDE_KEYBOARD_H */ diff --git a/SANDHU__OS/src/drivers/keyboard/kb.o b/SANDHU__OS/src/drivers/keyboard/kb.o new file mode 100644 index 0000000..bcc1a6f Binary files /dev/null and b/SANDHU__OS/src/drivers/keyboard/kb.o differ diff --git a/SANDHU__OS/src/drivers/serial_port/Makefile b/SANDHU__OS/src/drivers/serial_port/Makefile new file mode 100644 index 0000000..8638b4c --- /dev/null +++ b/SANDHU__OS/src/drivers/serial_port/Makefile @@ -0,0 +1,5 @@ +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs diff --git a/SANDHU__OS/src/drivers/serial_port/serial_port.c b/SANDHU__OS/src/drivers/serial_port/serial_port.c new file mode 100644 index 0000000..2d1dba9 --- /dev/null +++ b/SANDHU__OS/src/drivers/serial_port/serial_port.c @@ -0,0 +1,74 @@ +#include "serial_port.h" +#include "io.h" + +void serial_configure_baud_rate(uint16_t com, uint16_t divisor) { + /* Tell the serial port to first expect the highest 8 bits, then the lowest + * 8 bits. This is done by sending 0x80 to the line command port + */ + outb(SERIAL_LINE_COMMAND_PORT(com), SERIAL_LINE_ENABLE_DLAB); + outb(SERIAL_DATA_PORT(com), (divisor >> 8) & 0x00FF); + outb(SERIAL_DATA_PORT(com), divisor & 0x00FF); +} + +void serial_configure_line(uint16_t com) { + /* Bit: | 7 | 6 | 5 4 3 | 2 | 1 0 | + * Content: | d | b | prty | s | dl | + * Value: | 0 | 0 | 0 0 0 | 0 | 1 1 | = 0x03 + * data length of 8 bits, one stop bit, no parity bit, break control + * disabled and DLAB disabled + */ + outb(SERIAL_LINE_COMMAND_PORT(com), 0x03); +} + +void serial_configure_fifo_buffer(uint16_t com) { + /* Bit: | 7 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * Content: | lvl | bs | r | dma | clt | clr | e | + * Value: | 1 1 | 0 | 0 | 0 | 1 | 1 | 1 | = 0xC7 + */ + outb(SERIAL_FIFO_COMMAND_PORT(com), 0xC7); +} + +void serial_configure_modem(uint16_t com) { + /* Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * Content: | r | r | af | lb | ao2 | ao1 | rts | dtr | + * Value: | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | = 0x03 + */ + outb(SERIAL_MODEM_COMMAND_PORT(com), 0x03); +} + +int32_t serial_is_transmit_fifo_empty(uint16_t com) { + /* 0x20 = 0010 0000 */ + return inb(SERIAL_LINE_STATUS_PORT(com)) & 0x20; +} + +/** serial_write: + * writes the contents of the buffer buf of length len to the screen, since the + * serial port FIFO queue can hold 14 bytes, we will check if transmit buffer is + * empty only if the index is multiple of 8, by doing this we are avoiding + * uneccesary spin in checking fifo empty + * + * @param buf Buffer that has contents to be written to screen + * @param len Length of buffer + */ +int32_t serial_write(uint16_t com, int8_t *buf, uint32_t len) { + uint32_t indexToBuffer = 0, count = 0; + while (indexToBuffer < len) { + if (indexToBuffer == count) { + while (!serial_is_transmit_fifo_empty(com)) + ; + count += SERIAL_FIFO_BUFFER_LENGTH; + } + serial_write_byte(com, buf[indexToBuffer]); + indexToBuffer++; + } + return 0; +} + +void serial_write_byte(uint16_t port, int8_t byteData) { outb(port, byteData); } + +void serial_configure(uint16_t port, uint16_t baudRate) { + serial_configure_baud_rate(port, baudRate); + serial_configure_line(port); + serial_configure_fifo_buffer(port); + serial_configure_modem(port); +} diff --git a/SANDHU__OS/src/drivers/serial_port/serial_port.h b/SANDHU__OS/src/drivers/serial_port/serial_port.h new file mode 100644 index 0000000..07c23b1 --- /dev/null +++ b/SANDHU__OS/src/drivers/serial_port/serial_port.h @@ -0,0 +1,110 @@ +#ifndef INCLUDE_SERIALPORT_H +#define INCLUDE_SERIALPORT_H + +#pragma once +#include + +/* The I/O ports */ + +/* All the I/O ports are calculated relative to the data port. This is because + * all serial ports (COM1, COM2, COM3, COM4) have their ports in the same + * order, but they start at different values. + */ + +#define SERIAL_COM1_BASE 0x3F8 /* COM1 base port */ + +#define SERIAL_DATA_PORT(base) (base) +#define SERIAL_FIFO_COMMAND_PORT(base) (base + 2) +#define SERIAL_LINE_COMMAND_PORT(base) (base + 3) +#define SERIAL_MODEM_COMMAND_PORT(base) (base + 4) +#define SERIAL_LINE_STATUS_PORT(base) (base + 5) + +/* Divisor for different baud rates */ +enum BaudRate { Baud_115200 = 1, Baud_57600, Baud_19200, Baud_9600 }; + +/* The I/O port commands */ + +/* SERIAL_LINE_ENABLE_DLAB: + * Tells the serial port to expect first the highest 8 bits on the data port, + * then the lowest 8 bits will follow + */ +#define SERIAL_LINE_ENABLE_DLAB 0x80 + +/* SERIAL_FIFO_BUFFER_LENGTH: + * Define the macro for FIFO queue length + */ +#define SERIAL_FIFO_BUFFER_LENGTH 14 + +/** serial_configure_baud_rate: + * Sets the speed of the data being sent. The default speed of a serial + * port is 115200 bits/s. The argument is a divisor of that number, hence + * the resulting speed becomes (115200 / divisor) bits/s. + * + * @param com The COM port to configure + * @param divisor The divisor + */ +void serial_configure_baud_rate(uint16_t com, uint16_t divisor); + +/** serial_configure_line: + * Configures the line of the given serial port. The port is set to have a + * data length of 8 bits, no parity bits, one stop bit and break control + * disabled. + * + * @param com The serial port to configure + */ +void serial_configure_line(uint16_t com); + +/** serial_configure_fifo_buffer: + * 14 bytes as size of queue, clear both receiver and transmission FIFO + * queues, DMA bit ignored, r is reserved bit, bs is 16 byte FIFO, 14 bytes + * stored in FIFO which is lvl 11 + * + * @param com The serial port to configure + */ +void serial_configure_fifo_buffer(uint16_t com); + +/** serial_configure_modem: + * The modem control register is used for very simple hardware flow control via + * the Ready To Transmit (RTS) and Data Terminal Ready (DTR) pins. When + * configuring the serial port we want RTS and DTR to be 1, which means that we + * are ready to send data. + * + * @param com The serial port to configure + */ +void serial_configure_modem(uint16_t com); + +/** serial_is_transmit_fifo_empty: + * Checks whether the transmit FIFO queue is empty or not for the given COM + * port. + * + * @param com The COM port + * @return 0 if the transmit FIFO queue is not empty + * 1 if the transmit FIFO queue is empty + */ +int32_t serial_is_transmit_fifo_empty(uint16_t com); + +/** serial_write: + * writes the contents of the buffer buf of length len to the screen + * + * @param buf Buffer that has contents to be written to screen + * @param len Length of buffer + */ +int32_t serial_write(uint16_t com, int8_t *buf, uint32_t len); + +/** serial_write_byte: + * Write byte data to given serial port + * + * @param port Serial port to which data has to be written + * @param byte_data 8 bit data + */ +void serial_write_byte(uint16_t port, int8_t byteData); + +/** serial_configure: + * Configure serial port + * + * @param port Serial port which needs to be configured + * @param baudRate rate at which data needs to be transmitted + */ +void serial_configure(uint16_t port, uint16_t baudRate); + +#endif /* INCLUDE_SERIALPORT_H */ diff --git a/SANDHU__OS/src/drivers/serial_port/serial_port.o b/SANDHU__OS/src/drivers/serial_port/serial_port.o new file mode 100644 index 0000000..bfc18f0 Binary files /dev/null and b/SANDHU__OS/src/drivers/serial_port/serial_port.o differ diff --git a/SANDHU__OS/src/drivers/timer/Makefile b/SANDHU__OS/src/drivers/timer/Makefile new file mode 100644 index 0000000..8825cca --- /dev/null +++ b/SANDHU__OS/src/drivers/timer/Makefile @@ -0,0 +1,24 @@ +all: libtimer.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/drivers/interrupts \ + -I$(TOP_DIR)/src/drivers/io \ + -I$(TOP_DIR)/src/mm/paging \ + -I$(TOP_DIR)/src/mm/sched \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +# Generate Static library +SC_FLAG = ar -cvq + +libtimer.a: $(C_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ diff --git a/SANDHU__OS/src/drivers/timer/timer.c b/SANDHU__OS/src/drivers/timer/timer.c new file mode 100644 index 0000000..8d30f9e --- /dev/null +++ b/SANDHU__OS/src/drivers/timer/timer.c @@ -0,0 +1,82 @@ +#include "timer.h" +#include +#include +#include +#include +#include + +/* Define a macro for timer interrupt */ +#define IRQ0 32 +#define PIT_DEFAULT_CLOCK 1193180 +#define PIT_COMMAND_PORT 0x43 +#define PIT_CHANNEL0_DATA 0x40 + +/* We get approximately 100 ticks per second, so by ticks % 100 gives us time in + * seconds. So using 16 bit counter to keep track of ticks + */ +uint32_t TIMER_TICKS = 0; + +/* PIT command register has the following fields + * + * name | value | size | desc + * --------------------------- + * CNTR | 0 | 2 | select channel zero (for timer) + * RW | 3 | 2 | LS 8 bits will be sent first them MS 8 bits is sent + * MODE | 3 | 3 | generate square wave + * BCD | 0 | 1 | 16 bit counter + * COMMAND = 0x36 + */ +#define PIT_COMMAND 0x36 + +/* Callback function that prints tick to screen when there is timer interrupt */ +static void timer_callback(registers_t regs __attribute__((unused))) { + /* Increment our 'tick count' */ + TIMER_TICKS++; + /* Schedule next task */ + if (TIMER_TICKS % TIMER_FREQUENCY == 0) { + schedule(); + } +} + +void init_timer(uint32_t frequency) { + /* Register callback for timer interrupt (Interrupt 0) */ + register_interrupt_handler(IRQ0, timer_callback); + + /* The value we send to the PIT is the value to divide it's input clock + * (1193180 Hz) by, to get our required frequency. Important to note is + * that the divisor must be small enough to fit into 16-bits. + */ + uint32_t divisor = PIT_DEFAULT_CLOCK / frequency; + + /* Byte (0x36) sets the PIT to repeating mode (so that when the divisor + * counter reaches zero it's automatically refreshed) and tells it we want to + * set the divisor value. + */ + outb(PIT_COMMAND_PORT, PIT_COMMAND); + + /* Divisor has to be sent byte-wise, so split here into upper/lower bytes. */ + uint8_t ls_bits = (uint8_t)(divisor & 0xFF); + uint8_t ms_bits = (uint8_t)((divisor >> 8) & 0xFF); + + /* Send the frequency divisor. */ + outb(PIT_CHANNEL0_DATA, ls_bits); + outb(PIT_CHANNEL0_DATA, ms_bits); + + /* Enable timer interrupt, otherwise there won't be any interrupt */ + asm("sti"); +} + +void sleep(uint32_t centiSeconds) { + uint32_t ticks = TIMER_TICKS + centiSeconds; + /* If 32 bit number overflows */ + if (ticks < TIMER_TICKS) { + /* Wait till TIMER_TICKS to overflow */ + while (TIMER_TICKS > 20) + ; + while (TIMER_TICKS < ticks) + ; + } else { + while (TIMER_TICKS < ticks) + ; + } +} diff --git a/SANDHU__OS/src/drivers/timer/timer.h b/SANDHU__OS/src/drivers/timer/timer.h new file mode 100644 index 0000000..2c6b686 --- /dev/null +++ b/SANDHU__OS/src/drivers/timer/timer.h @@ -0,0 +1,21 @@ +#ifndef INCLUDE_TIMER_H +#define INCLUDE_TIMER_H + +#pragma once +#include + +/* PIT has an internal clock which oscillates at approximately 1.1931MHz, + * this macro defines desired frequency, dividing the default frequency by 100 + * gives us the frequency of 100Hz, so we get approximately 100 ticks per + * second. + */ +#define TIMER_FREQUENCY 100 + +void init_timer(uint32_t frequency); + +/* This will continuously loop until the given time (in centiSeconds, 100 + * centiSeconds is 1 second) has been reached + */ +void sleep(uint32_t centiSeconds); + +#endif /* INCLUDE_TIMER_H */ diff --git a/SANDHU__OS/src/drivers/timer/timer.o b/SANDHU__OS/src/drivers/timer/timer.o new file mode 100644 index 0000000..57aeaa8 Binary files /dev/null and b/SANDHU__OS/src/drivers/timer/timer.o differ diff --git a/SANDHU__OS/src/kernel/Makefile b/SANDHU__OS/src/kernel/Makefile new file mode 100644 index 0000000..f167867 --- /dev/null +++ b/SANDHU__OS/src/kernel/Makefile @@ -0,0 +1,35 @@ +LDFLAG += -T link.ld -melf_i386 +LIBS = -llogger -lgdt -lidt -lio -lcommon -ltimer -lkb -lpaging -lkheap \ + -lorderedarray -lfs -linitrd -lsched + +all: kernel.elf + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/drivers/interrupts \ + -I$(TOP_DIR)/src/drivers/keyboard \ + -I$(TOP_DIR)/src/drivers/serial_port \ + -I$(TOP_DIR)/src/drivers/timer \ + -I$(TOP_DIR)/src/mm/heap \ + -I$(TOP_DIR)/src/mm/paging \ + -I$(TOP_DIR)/src/mm/sched \ + -I$(TOP_DIR)/src/mm/segmentation \ + -I$(TOP_DIR)/src/mm/vfs/fs \ + -I$(TOP_DIR)/src/mm/vfs/initrd \ + -I$(TOP_DIR)/src/tests \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +kernel.elf: $(C_OBJECTS) $(S_OBJECTS) + ld $(LDFLAG) $(LDFLAGS) $(C_OBJECTS) $(S_OBJECTS) $(LIBS) -o $(BIN_DIR)/$@ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/kernel/kmain.c b/SANDHU__OS/src/kernel/kmain.c new file mode 100644 index 0000000..14a0333 --- /dev/null +++ b/SANDHU__OS/src/kernel/kmain.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function to initialize */ +void init(uint32_t mbootPointer, uint32_t stackPointer) { + /* Initialize segment descriptor tables */ + init_gdt(); + + /* Initialize segment descriptor tables */ + init_idt(); + + /* Initialize timer interrupt */ + init_timer(TIMER_FREQUENCY); + + /* Initialize display */ + init_display(); + + /* Configure serial port */ + serial_configure(SERIAL_COM1_BASE, Baud_115200); + + /* + * Get Multiboot Information like module start address and multiboot physical + * end address + */ + uint32_t initrdPhysicalStart; + uint32_t multibootPhysicalEnd; + uint32_t modsCount; + get_multiboot_info(mbootPointer, &initrdPhysicalStart, &multibootPhysicalEnd, + &modsCount); + + /* Initialise the initial ramdisk, and set it as the filesystem root */ + initialise_initrd(initrdPhysicalStart); + + /* Initialize paging */ + init_paging(multibootPhysicalEnd); + + /* Initialize multitasking */ + initialise_multitasking(stackPointer); + + /* Initialize keyboard */ + init_keyboard(); +} + +/* Kernel Main */ +/* GRUB stores a pointer to a struct in the register ebx that, + * describes at which addresses the modules are loaded. + */ +int32_t kmain(uint32_t mbootPointer, uint32_t stackPointer) { + // Initialize all modules + init(mbootPointer, stackPointer); + + // Run init tests defined in tests.h + run_all_tests(); + + return 0; +} diff --git a/SANDHU__OS/src/kernel/kmain.o b/SANDHU__OS/src/kernel/kmain.o new file mode 100644 index 0000000..323acd4 Binary files /dev/null and b/SANDHU__OS/src/kernel/kmain.o differ diff --git a/SANDHU__OS/src/kernel/link.ld b/SANDHU__OS/src/kernel/link.ld new file mode 100644 index 0000000..1e78710 --- /dev/null +++ b/SANDHU__OS/src/kernel/link.ld @@ -0,0 +1,28 @@ +ENTRY(loader) /* the name of the entry label */ + +SECTIONS { + . = 0x00100000; /* the code should be loaded at 1 MB */ + + .text ALIGN (0x1000) : /* align at 4 KB */ + { + *(.text) /* all text sections from all files */ + } + + .rodata ALIGN (0x1000) : /* align at 4 KB */ + { + *(.rodata*) /* all read-only data sections from all files */ + } + + .data ALIGN (0x1000) : /* align at 4 KB */ + { + *(.data) /* all data sections from all files */ + } + + .bss ALIGN (0x1000) : /* align at 4 KB */ + { + *(COMMON) /* all COMMON sections from all files */ + *(.bss) /* all bss sections from all files */ + } + + KERNEL_PHYSICAL_END = .; +} diff --git a/SANDHU__OS/src/kernel/loader.o b/SANDHU__OS/src/kernel/loader.o new file mode 100644 index 0000000..7f92aae Binary files /dev/null and b/SANDHU__OS/src/kernel/loader.o differ diff --git a/SANDHU__OS/src/kernel/loader.s b/SANDHU__OS/src/kernel/loader.s new file mode 100644 index 0000000..9a38607 --- /dev/null +++ b/SANDHU__OS/src/kernel/loader.s @@ -0,0 +1,63 @@ +; Entry symbol for ELF +global loader + +; size of stack in bytes +KERNEL_STACK_SIZE equ 4096 + +;setting up the Multiboot header - see GRUB docs for details + +; align loaded modules on page boundaries +MODULEALIGN equ 1 << 0 + +; provide memory map +MEMINFO equ 1 << 1 + +; this is the Multiboot 'flag' field +FLAGS equ MODULEALIGN | MEMINFO + +; 'magic number' lets bootloader find the header +MAGIC_NUMBER equ 0x1BADB002 + +; calculate the checksum (all options + checksum should equal 0) +CHECKSUM equ - (MAGIC_NUMBER + FLAGS) + +; Kernel End Physical Address is exported from linker script +extern KERNEL_PHYSICAL_END + +; start of the bss section +section .bss +; align at 4 bytes +align 4 +; label points to beginning of memory +KERNEL_STACK: + ; reserve stack for the kernel + resb KERNEL_STACK_SIZE + +; start of the text (code) section +section .text +; Align at 4 bytes +align 4 + ; write the magic number to the machine code, + dd MAGIC_NUMBER + ; the flags, + dd FLAGS + ; the checksum + dd CHECKSUM + +; the loader label (defined as entry point in linker script) +loader: + ; point esp to the start of the stack (end of memory area) + mov esp, KERNEL_STACK + KERNEL_STACK_SIZE + ; kmain function is defined elsewhere + extern kmain + ; and the kernel end address (commenting as bringing in multiboot) + ; push $KERNEL_PHYSICAL_END + ; push the stack pointer + push esp + ; push the multiboot information + push ebx + ; call kernel main function. + call kmain + .loop: + ; loop forever + jmp .loop diff --git a/SANDHU__OS/src/mm/Makefile b/SANDHU__OS/src/mm/Makefile new file mode 100644 index 0000000..c1126db --- /dev/null +++ b/SANDHU__OS/src/mm/Makefile @@ -0,0 +1,9 @@ +SUBDIRS = \ + heap \ + paging \ + sched \ + segmentation \ + vfs + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs diff --git a/SANDHU__OS/src/mm/heap/Makefile b/SANDHU__OS/src/mm/heap/Makefile new file mode 100644 index 0000000..d3ad1bf --- /dev/null +++ b/SANDHU__OS/src/mm/heap/Makefile @@ -0,0 +1,22 @@ +all: libkheap.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/mm/paging \ + -I$(TOP_DIR)/src/utils/array \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +# Generate Static library +SC_FLAG = ar -cvq + +libkheap.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ diff --git a/SANDHU__OS/src/mm/heap/kheap.c b/SANDHU__OS/src/mm/heap/kheap.c new file mode 100644 index 0000000..2bd075f --- /dev/null +++ b/SANDHU__OS/src/mm/heap/kheap.c @@ -0,0 +1,503 @@ +#include "kheap.h" +#include +#include +#include + +typedef struct { + /* Array of holes sorted by size (ordered array) */ + ordered_array_t index; + /* The start of heap. */ + uint32_t startAddress; + /* The end of heap. Can be expanded up to maxAddress. */ + uint32_t endAddress; + /* The maximum address the heap can be expanded to. */ + uint32_t maxAddress; + /* If set, accesible only in supervisor mode */ + uint8_t supervisor; + /* Page permission (if set, read only) */ + uint8_t readonly; +} heap_t; + +typedef struct { + uint32_t magic; // Magic number, used for error checking and identification. + uint8_t isHole; // 1 if this is a hole. 0 if this is a block. + uint32_t size; // size of the block, including the end footer. +} header_t; + +typedef struct { + uint32_t magic; // Magic number, same as in header_t. + header_t *header; // Pointer to the block header. +} footer_t; + +uint32_t g_CurrentPhysicalAddressTop = 0; +heap_t *g_KernelHeap = 0; + +/* + * Defined in paging.c (using extern for the sake of security, so that these are + * not exposed in header) + */ +extern page_directory_t *g_kernelDirectory; + +void set_physical_address_top(uint32_t kernelPhysicalEnd) { + g_CurrentPhysicalAddressTop = kernelPhysicalEnd; +} + +static int32_t find_smallest_hole(uint32_t size, uint8_t pageAlign, + heap_t *heap) { + /* Find the smallest hole that will fit. */ + uint32_t iterator = 0; + + while (iterator < heap->index.size) { + header_t *header = (header_t *)peek_ordered_array(iterator, &heap->index); + + /* If the user has requested the memory be page-aligned */ + if (pageAlign > 0) { + /* Page-align the starting point of this header. */ + uint32_t location = (uint32_t)header; + int32_t offset = 0; + + if (((location + sizeof(header_t)) & 0xFFFFF000) != 0) { + offset = 0x1000 - ((location + sizeof(header_t)) % 0x1000); + } + + int32_t holeSize = (int32_t)header->size - offset; + + /* Can we fit now? */ + if (holeSize >= (int32_t)size) + break; + } else if (header->size >= size) { + break; + } + iterator++; + } + + /* We got to the end and didn't find anything. */ + if (iterator == heap->index.size) { + return -1; + } else { + return iterator; + } +} + +static void expand(uint32_t newSize, heap_t *heap) { + if (newSize <= heap->endAddress - heap->startAddress) { + print_screen("\nError: Expand: New Size is not greater than old size!!!\n"); + return; + } + + /* Get the nearest following page boundary. */ + if (newSize & 0x00000FFF) { + newSize &= 0xFFFFF000; + newSize += 0x1000; + } + + /* Make sure we are not overreaching ourselves. */ + if (heap->startAddress + newSize > heap->maxAddress) { + print_screen("\nError: Expand: New Size is greater than max size!!!\n"); + return; + } + + uint32_t oldSize = heap->endAddress - heap->startAddress; + + uint32_t index = oldSize; + /* Allocate frames for new memory area */ + while (index < newSize) { + alloc_frame(get_page(heap->startAddress + index, 1, g_kernelDirectory), + (heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1); + index += 0x1000; + } + heap->endAddress = heap->startAddress + newSize; +} + +type_t alloc(uint32_t size, uint8_t pageAlign, heap_t *heap) { + + /* Make sure we take the size of header/footer into account. */ + uint32_t newSize = size + sizeof(header_t) + sizeof(footer_t); + + /* Find the smallest hole that will fit. */ + int32_t iterator = find_smallest_hole(newSize, pageAlign, heap); + + /* If we didn't find a suitable hole */ + if (iterator == -1) { + /* Save previous data. */ + uint32_t oldLength = heap->endAddress - heap->startAddress; + uint32_t oldEndAddress = heap->endAddress; + + /* We need to allocate some more space. */ + expand(oldLength + newSize, heap); + uint32_t newLength = heap->endAddress - heap->startAddress; + + /* + * Since there is not hole available and we have now expanded our heap, we + * need either add the new hole to list of available holes or create a new + * entry on sorted array of holes if this is first insertion + */ + uint32_t tmp = + (uint32_t)peek_ordered_array((heap->index.size - 1), &heap->index); + + /* If we didn't find ANY headers, we need to add one. */ + if (tmp == 0) { + header_t *header = (header_t *)oldEndAddress; + header->magic = HEAP_MAGIC; + header->size = newLength - oldLength; + header->isHole = 1; + footer_t *footer = + (footer_t *)(oldEndAddress + header->size - sizeof(footer_t)); + footer->magic = HEAP_MAGIC; + footer->header = header; + insert_ordered_array((type_t)header, &heap->index); + } else { + /* + * This will probably be the last header that has size less han required + * and hence needs adjusting. + */ + header_t *header = (header_t *)tmp; + header->size += newLength - oldLength; + // Rewrite the footer. + footer_t *footer = + (footer_t *)((uint32_t)header + header->size - sizeof(footer_t)); + footer->header = header; + footer->magic = HEAP_MAGIC; + } + /* + * We now have enough space. Recurse, and call the function again, so that + * in the next iteration we go and do the book keeping things like boundary + * check and removing the block from holes etc... + */ + return alloc(size, pageAlign, heap); + } + + /* If we find the smallest hole that will fit */ + header_t *origHoleHeader = + (header_t *)peek_ordered_array(iterator, &heap->index); + uint32_t origHolePos = (uint32_t)origHoleHeader; + uint32_t origHoleSize = origHoleHeader->size; + + /* + * Here we work out if we should split the hole we found into two parts. + * We will skip splitting the hole into two if the original hole size - + * requested hole size less than the overhead for adding a new hole as we will + * not have any space left to allocate in the new block. + */ + if ((origHoleSize - newSize) <= (sizeof(header_t) + sizeof(footer_t))) { + size += origHoleSize - newSize; + newSize = origHoleSize; + } + + /* + * If we need to page-align the data, do it now and make a new hole before + * our new block. + */ + if (pageAlign) { + uint32_t returnPos = origHolePos + sizeof(header_t); + if (returnPos & 0x00000FFF) { + uint32_t newLocation = + returnPos + 0x1000 - (returnPos & 0xFFF) - sizeof(header_t); + + /* If left over space has at least 1 byte add new hole */ + uint32_t residualSize = newLocation - origHolePos; + if ((origHoleSize - residualSize) > + (sizeof(header_t) + sizeof(footer_t))) { + header_t *holeHeader = (header_t *)origHolePos; + holeHeader->size = residualSize; + holeHeader->magic = HEAP_MAGIC; + holeHeader->isHole = 1; + footer_t *holeFooter = + (footer_t *)((uint32_t)newLocation - sizeof(footer_t)); + holeFooter->magic = HEAP_MAGIC; + holeFooter->header = holeHeader; + insert_ordered_array((type_t)holeHeader, &heap->index); + } else { + /* TODO: Implement logic to expand block on left to avoid + * fragmentation */ + } + + origHolePos = newLocation; + origHoleSize = origHoleSize - residualSize; + } + } else { + /* + * Else we don't need this hole any more as we will be allocating it, delete + * it from the index. + */ + remove_ordered_array(iterator, &heap->index); + } + + /* + * Create header and footer if this is newly allocated block or Overwrite the + * original if we expanded the last hole. + */ + header_t *blockHeader = (header_t *)origHolePos; + blockHeader->magic = HEAP_MAGIC; + blockHeader->isHole = 0; + blockHeader->size = newSize; + footer_t *blockFooter = (footer_t *)(origHolePos + sizeof(header_t) + size); + blockFooter->magic = HEAP_MAGIC; + blockFooter->header = blockHeader; + + /* + * We may need to write a new hole after the allocated block. + * We do this only if the new hole would have positive size... + */ + if (origHoleSize - newSize > 0) { + header_t *holeHeader = + (header_t *)(origHolePos + sizeof(header_t) + size + sizeof(footer_t)); + holeHeader->magic = HEAP_MAGIC; + holeHeader->isHole = 1; + holeHeader->size = origHoleSize - newSize; + footer_t *holeFooter = (footer_t *)((uint32_t)holeHeader + origHoleSize - + newSize - sizeof(footer_t)); + if ((uint32_t)holeFooter < heap->endAddress) { + holeFooter->magic = HEAP_MAGIC; + holeFooter->header = holeHeader; + } + /* + * Put the new hole in the index. If the footer is beyond the heap end + * address we will still add the hole to index so that we can expand the + * last hole without fragmentation. + */ + insert_ordered_array((type_t)holeHeader, &heap->index); + } + + return (type_t)((uint32_t)blockHeader + sizeof(header_t)); +} + +uint32_t kmalloc_int(uint32_t size, uint32_t align, uint32_t *pAddrPtr) { + /* if Kernel Heap is created and allocated */ + if (g_KernelHeap != 0) { + type_t addr = alloc(size, (uint8_t)align, g_KernelHeap); + if (align && ((uint32_t)addr & 0x00000FFF)) { + print_screen("\nError: kmalloc_int: returned address from alloc is not " + "page aligned!!!!\n"); + } + if (pAddrPtr != 0) { + page_t *page = get_page((uint32_t)addr, 0, g_kernelDirectory); + + *pAddrPtr = page->frame * 0x1000; + } + return (uint32_t)addr; + } else { + if (align == 1) { + if (g_CurrentPhysicalAddressTop & 0x00000FFF) { + // Align the placement address; + g_CurrentPhysicalAddressTop &= 0xFFFFF000; + g_CurrentPhysicalAddressTop += 0x1000; + } + } + if (pAddrPtr) { + *pAddrPtr = g_CurrentPhysicalAddressTop; + } + /* Increase physical address top so that it is always aligned at 4 bytes */ + g_CurrentPhysicalAddressTop += + (g_CurrentPhysicalAddressTop % sizeof(uint32_t)); + uint32_t tmp = g_CurrentPhysicalAddressTop; + g_CurrentPhysicalAddressTop += size; + return tmp; + } +} + +uint32_t kmalloc_a(uint32_t size) { return kmalloc_int(size, 1, 0); } + +uint32_t kmalloc_p(uint32_t size, uint32_t *pAddrPtr) { + return kmalloc_int(size, 0, pAddrPtr); +} + +uint32_t kmalloc_ap(uint32_t size, uint32_t *pAddrPtr) { + return kmalloc_int(size, 1, pAddrPtr); +} + +uint32_t kmalloc(uint32_t size) { return kmalloc_int(size, 0, 0); } + +/* + * Compare function for ordered array, sorted by header size ascending order + */ +static uint8_t header_t_less_than(type_t a, type_t b) { + return (((header_t *)a)->size < ((header_t *)b)->size) ? 1 : 0; +} + +heap_t *create_heap(uint32_t startAddr, uint32_t endAddr, uint32_t maxAddr, + uint8_t supervisor, uint8_t readonly) { + heap_t *heap = (heap_t *)kmalloc(sizeof(heap_t)); + + if (startAddr % 0x1000 != 0) { + print_screen("\nError: create_heap: Start Address is not page aligned\n"); + return 0; + } + + if (endAddr % 0x1000 != 0) { + print_screen("\nError: create_heap: End Address is not page aligned\n"); + return 0; + } + + /* Initialise the index. */ + heap->index = place_ordered_array((type_t)startAddr, HEAP_INDEX_SIZE, (compare_predicate_t)&header_t_less_than); + + /* + * Shift the start address forward to resemble where we can start putting + * data. + */ + startAddr += sizeof(type_t) * HEAP_INDEX_SIZE; + + /* Make sure the start address is page-aligned. */ + if (startAddr & 0x00000FFF) { + startAddr &= 0xFFFFF000; + startAddr += 0x1000; + } + + /* Write the start, end and max addresses into the heap structure. */ + heap->startAddress = startAddr; + heap->endAddress = endAddr; + heap->maxAddress = maxAddr; + heap->supervisor = supervisor; + heap->readonly = readonly; + + /* We start off with one large hole in the index. */ + header_t *hole = (header_t *)startAddr; + hole->size = endAddr - startAddr; + hole->magic = HEAP_MAGIC; + hole->isHole = 1; + insert_ordered_array((type_t)hole, &heap->index); + + return heap; +} + +void create_kernel_heap(uint32_t startAddr, uint32_t endAddr, + uint32_t maxAddr) { + g_KernelHeap = create_heap(startAddr, endAddr, maxAddr, 0, 0); +} + +static uint32_t contract(uint32_t newSize, heap_t *heap) { + if (newSize >= (heap->endAddress - heap->startAddress)) { + print_screen("\nError: contract: New size greater than current heap size"); + return (heap->endAddress - heap->startAddress); + } + + /* Page align */ + if (newSize & 0x0FFF) { + newSize &= 0x1000; + newSize += 0x1000; + } + + /* Don't contract too far! */ + if (newSize < HEAP_MIN_SIZE) + newSize = HEAP_MIN_SIZE; + + uint32_t oldSize = heap->endAddress - heap->startAddress; + uint32_t index = oldSize - 0x1000; + while (newSize < index) { + free_frame(get_page(heap->startAddress + index, 0, g_kernelDirectory)); + index -= 0x1000; + } + + heap->endAddress = heap->startAddress + newSize; + return newSize; +} + +static void free(void *ptr, heap_t *heap) { + if (ptr == 0) { + return; + } + + header_t *header = (header_t *)((uint32_t)ptr - sizeof(header_t)); + footer_t *footer = + (footer_t *)((uint32_t)header + header->size - sizeof(footer_t)); + + if (header->magic != HEAP_MAGIC) { + print_screen("\nError: free: Cannot verify header magic numer"); + } + + if (footer->magic != HEAP_MAGIC) { + print_screen("\nError: free: Cannot verify footer magic number"); + } + + /* Make us a hole */ + header->isHole = 1; + + /* We want to add this header into the 'free holes' index */ + char doAdd = 1; + + /* + * Unify left if the thing immediately to the left of us is a footer of free + * block + */ + footer_t *testFooter = (footer_t *)((uint32_t)header - sizeof(footer_t)); + if (testFooter->magic == HEAP_MAGIC && testFooter->header->isHole == 1) { + uint32_t cacheSize = header->size; + header = testFooter->header; + footer->header = header; + header->size += cacheSize; + /* Since this header is already in the index, we don't want to add */ + doAdd = 0; + } + + /* + * Unify right if the thing immediately to the right of us is a header of a + * free block + */ + header_t *testHeader = (header_t *)((uint32_t)footer + sizeof(footer_t)); + if (testHeader->magic == HEAP_MAGIC && testHeader->isHole) { + header->size += testHeader->size; + testFooter = (footer_t *)((uint32_t)testHeader + testHeader->size - + sizeof(footer_t)); + footer = testFooter; + /* Find and remove this header from the index. */ + uint32_t iterator = 0; + while ((iterator < heap->index.size) && + (peek_ordered_array(iterator, &heap->index) != (type_t)testHeader)) { + iterator++; + } + + if (iterator >= heap->index.size) { + print_screen("\nError: free: unify right found a free block that is not " + "present in index"); + return; + } + + remove_ordered_array(iterator, &heap->index); + } + + /* + * If the footer location is the end address, we can contract if we have + * expanded our heap beyond minimum heap size. + */ + if ((uint32_t)footer + sizeof(footer_t) == heap->endAddress) { + uint32_t oldLength = heap->endAddress - heap->startAddress; + uint32_t newLength = contract((uint32_t)header - heap->startAddress, heap); + + /* + * Check how big we will be after resizing. + * It might be possible we still have the header but footer stays outside + * heap end address since we contracted + */ + if (header->size - (oldLength - newLength) > 0) { + header->size -= oldLength - newLength; + footer = (footer_t *)((uint32_t)header + header->size - sizeof(footer_t)); + footer->magic = HEAP_MAGIC; + footer->header = header; + } else { + /* Remove temporary header before contract from the index. */ + uint32_t iterator = 0; + while ( + (iterator < heap->index.size) && + (peek_ordered_array(iterator, &heap->index) != (type_t)testHeader)) { + iterator++; + } + + if (iterator >= heap->index.size) { + print_screen("\nError: free: contract found a free block that is not " + "present in index"); + return; + } + + if (iterator < heap->index.size) { + remove_ordered_array(iterator, &heap->index); + } + } + } + + /* If required, add us to the index. */ + if (doAdd == 1) + insert_ordered_array((void *)header, &heap->index); +} + +void kfree(void *ptr) { free(ptr, g_KernelHeap); } diff --git a/SANDHU__OS/src/mm/heap/kheap.h b/SANDHU__OS/src/mm/heap/kheap.h new file mode 100644 index 0000000..683299a --- /dev/null +++ b/SANDHU__OS/src/mm/heap/kheap.h @@ -0,0 +1,85 @@ +#ifndef INCLUDE_KHEAP_H +#define INCLUDE_KHEAP_H + +#pragma once +#include + +#define KHEAP_START 0xC0000000 +#define KHEAP_INITIAL_SIZE 0x100000 +#define KHEAP_MAX_ADDRESS 0xCFFFF000 + +#define HEAP_INDEX_SIZE 0x20000 +#define HEAP_MAGIC 0xC0DED00D +#define HEAP_MIN_SIZE 0x70000 + +/* set_physical_address_top: + * Set the top of physical address global variable. This is required to keep + * track of the memory thats allocated till now. Initially, this is set to top + * of address where kernel ends. We keep moving this as memory is allocated. + * + * @param phyAddress Current Address End, we get this from linker script. + */ +void set_physical_address_top(uint32_t phyAddress); + +/* create_kernel_heap: + * Create a new kernel heap. + * + * @param startAddr Physical Address where we want to create heap + * @param endAddr Physical end address of heap + * @param maxAddr Physical address beyond which heap would not expand. + */ +void create_kernel_heap(uint32_t startAddr, uint32_t endAddr, uint32_t maxAddr); + +/* kmalloc_int: + * Allocate a chunk of memory, size in size. If align == 1, + * the chunk must be page-aligned. If pAddrPtr != 0, the physical + * location of the allocated chunk will be stored into phys. + * + * @param size Size of memory to be allocated + * @param align Align allocated memory at 4kb address + * @param pAddrPtr Store the physical address of the page + */ +uint32_t kmalloc_int(uint32_t size, uint32_t align, uint32_t *pAddrPtr); + +/* kmalloc_a: + * Allocate a chunk of memory, size in size. The chunk must be + * page aligned. + * + * @param size Size of memory to be allocated + */ +uint32_t kmalloc_a(uint32_t size); + +/* kmalloc_p: + * Allocate a chunk of memory, size in size. The physical address + * is returned in pAddrPtr. pAddrPtr MUST be a valid pointer to uint32_t! + * + * @param pAddrPtr Pointer to store the physical address of + * the page + */ +uint32_t kmalloc_p(uint32_t sz, uint32_t *pAddrPtr); + +/* kmalloc_p: + * Allocate a chunk of memory, size in size. The physical address + * is returned in pAddrPtr. It must be page-aligned. + * + * @param size Size of memory to be allocated + * @param pAddrPtr Pointer to store the physical address of + * the page + */ +uint32_t kmalloc_ap(uint32_t size, uint32_t *pAddrPtr); + +/* kmalloc: + * Generic function to allocate chunk of memory, size in size. + * + * @param size Size of memory to be allocated + */ +uint32_t kmalloc(uint32_t size); + +/* kfree: + * General deallocation function. + * + * @param ptr Pointer to be de-allocated + */ +void kfree(void *ptr); + +#endif /* INCLUDE_KHEAP_H */ diff --git a/SANDHU__OS/src/mm/heap/kheap.o b/SANDHU__OS/src/mm/heap/kheap.o new file mode 100644 index 0000000..2644f12 Binary files /dev/null and b/SANDHU__OS/src/mm/heap/kheap.o differ diff --git a/SANDHU__OS/src/mm/paging/Makefile b/SANDHU__OS/src/mm/paging/Makefile new file mode 100644 index 0000000..3982f2d --- /dev/null +++ b/SANDHU__OS/src/mm/paging/Makefile @@ -0,0 +1,25 @@ +all: libpaging.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/drivers/interrupts \ + -I$(TOP_DIR)/src/mm/heap \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +# Generate Static library +SC_FLAG = ar -cvq + +libpaging.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/mm/paging/paging.c b/SANDHU__OS/src/mm/paging/paging.c new file mode 100644 index 0000000..4967420 --- /dev/null +++ b/SANDHU__OS/src/mm/paging/paging.c @@ -0,0 +1,334 @@ +#include "paging.h" +#include +#include +#include +#include + +/* The kernel's page directory */ +page_directory_t *g_kernelDirectory = 0; + +/* The current page directory */ +page_directory_t *g_currentDirectory = 0; + +/* Variables for house keeping, whether page frame is free or used */ +uint32_t *g_FrameIndexArray; +uint32_t g_NumOfFrames; + +/* + * Accessing g_CurrentPhysicalAddressTop defined in kheap.c through extern since + * we use it in page_fault handler + */ +extern uint32_t g_CurrentPhysicalAddressTop; + +/* + * Function call to copy physical pages implemented in assembly. + * Extern allows to access ASM from this C code. + */ +extern void copy_page_physical(uint32_t, uint32_t); + +/* Macros used in the bitset algorithms */ +#define INDEX_FROM_BIT(a) (a / 32) +#define OFFSET_FROM_BIT(a) (a % 32) + +/* Page Fault interrupt handler function forward declaration, definition towards + * the end + */ +void page_fault(registers_t regs); + +/* Function to mark corresponding frame in the variable as not free */ +static void set_frame(uint32_t frameAddr) { + uint32_t frame = frameAddr / 0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + g_FrameIndexArray[idx] |= (0x1 << off); +} + +/* Function to mark corresponding frame in the variable as free */ +static void clear_frame(uint32_t frameAddr) { + uint32_t frame = frameAddr / 0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + g_FrameIndexArray[idx] &= ~(0x1 << off); +} + +/* Utility function to get index of first free frame */ +static int32_t first_frame() { + uint32_t i, j; + for (i = 0; i < INDEX_FROM_BIT(g_NumOfFrames); ++i) { + if (g_FrameIndexArray[i] != 0xFFFFFFFF) { + for (j = 0; j < 32; ++j) { + uint32_t toTest = 0x1 << j; + if (!(g_FrameIndexArray[i] & toTest)) { + return ((i * 32) + j); + } + } + } + } + /* No free frames available */ + return -1; +} + +void alloc_frame(page_t *page, uint32_t isKernel, uint32_t isWriteable) { + if (page->frame != 0) { + return; + } else { + uint32_t idx = first_frame(); + if (idx == (uint32_t)-1) { + print_screen("No Free Frame, Kernel Panic"); + while (1) { + } + } + set_frame(idx * 0x1000); + page->present = 1; + page->rw = (isWriteable) ? 1 : 0; + page->user = (isKernel) ? 0 : 1; + page->frame = idx; + } +} + +void free_frame(page_t *page) { + uint32_t frame; + if (!(frame = page->frame)) { + return; + } else { + clear_frame(frame); + page->frame = 0x0; + } +} + +void init_paging(uint32_t kernelPhysicalEnd) { + + set_physical_address_top(kernelPhysicalEnd); + + /* + * The size of physical memory. + * Assuming it is KHEAP_MAX_ADDRESS big + */ + uint32_t memPageEnd = KHEAP_MAX_ADDRESS; + + g_NumOfFrames = (memPageEnd / 0x1000) + 1; + g_FrameIndexArray = (uint32_t *)kmalloc(INDEX_FROM_BIT(g_NumOfFrames)); + custom_memset((uint8_t *)g_FrameIndexArray, 0, INDEX_FROM_BIT(g_NumOfFrames)); + + /* Create a page directory for kernel and set it as curent page directory */ + uint32_t phys; + g_kernelDirectory = + (page_directory_t *)kmalloc_ap(sizeof(page_directory_t), &phys); + custom_memset((uint8_t *)g_kernelDirectory, 0, sizeof(page_directory_t)); + /* + * Get the offset of tablesPhysical from the start of the page_directory_t + * structure. + */ + uint32_t offset = + (uint32_t)g_kernelDirectory->tablesPhysical - (uint32_t)g_kernelDirectory; + g_kernelDirectory->physicalAddr = phys + offset; + + /* + * Call to get pages only forces page tables to be created. We will map them + * before we actually allocate + */ + uint32_t i = 0; + for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += 0x1000) + get_page(i, 1, g_kernelDirectory); + + /* + * We need to identity map (phys addr = virt addr) from 0x0 to the end of + * used memory, so we can access this transparently, as if paging wasn't + * enabled. + */ + for (i = 0; i < g_CurrentPhysicalAddressTop + 0x1000; i += 0x1000) { + /* Setting page readable but not writeable from userspace */ + alloc_frame(get_page(i, 1, g_kernelDirectory), 0, 0); + } + + /* Now allocate those pages for heap */ + for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += 0x1000) { + alloc_frame(get_page(i, 1, g_kernelDirectory), 0, 0); + } + + /* Register our page fault handler */ + register_interrupt_handler(14, page_fault); + + /* Enable paging! */ + switch_page_directory(g_kernelDirectory); + + /* Initialise the kernel heap */ + create_kernel_heap(KHEAP_START, KHEAP_START + KHEAP_INITIAL_SIZE, + KHEAP_MAX_ADDRESS); + + /* Switch directory */ + switch_page_directory(clone_directory(g_kernelDirectory)); +} + +void switch_page_directory(page_directory_t *dir) { + g_currentDirectory = dir; + /* Write page table physical address to cr3 */ + asm volatile("mov %0, %%cr3" ::"r"(dir->physicalAddr)); + uint32_t cr0; + /* Read cr0 register to variable cr0 */ + asm volatile("mov %%cr0, %0" : "=r"(cr0)); + /* Set enable paging bit of the cr0 variable ! */ + cr0 |= 0x80000000; + /* Write back cr0 variable value to cr0 register */ + asm volatile("mov %0, %%cr0" ::"r"(cr0)); +} + +page_t *get_page(uint32_t address, uint8_t make, page_directory_t *dir) { + /* Turn the address into an index */ + address /= 0x1000; + /* Find the page table containing this address */ + uint32_t tableIdx = address / 1024; + /* Return page if it is already created */ + if (dir->tables[tableIdx]) { + return &dir->tables[tableIdx]->pages[address % 1024]; + } else if (make) { + uint32_t tmp; + dir->tables[tableIdx] = + (page_table_t *)kmalloc_ap(sizeof(page_table_t), &tmp); + custom_memset((uint8_t *)dir->tables[tableIdx], 0, 0x1000); + /* PRESENT, RW, US. */ + dir->tablesPhysical[tableIdx] = tmp | 0x7; + return &dir->tables[tableIdx]->pages[address % 1024]; + } else { + return 0; + } +} + +/* Page Fault interrupt handler function */ +void page_fault(registers_t regs) { + /* + * A page fault has occurred. + * The faulting address is stored in the CR2 register. + */ + uint32_t faultingAddress; + asm volatile("mov %%cr2, %0" : "=r"(faultingAddress)); + + /* The error code gives us details of what happened. */ + /* Page not present */ + uint32_t present = !(regs.stack_contents.err_code & 0x1); + /* Read Only */ + uint32_t rWrite = regs.stack_contents.err_code & 0x2; + /* Accessing kernel page from User mode */ + uint32_t uMode = regs.stack_contents.err_code & 0x4; + /* Overwritten CPU-reserved bits of page entry */ + uint32_t reserved = regs.stack_contents.err_code & 0x8; + /* Caused by an instruction fetch */ + uint32_t iFetch = regs.stack_contents.err_code & 0x10; + + print_screen("Page fault! ( "); + print_serial("Page fault! ( "); + if (present) { + print_screen("not present "); + } else { + if (rWrite) { + print_screen("read-only "); + } + if (uMode) { + print_screen("user-mode "); + } + if (reserved) { + print_screen("reserved "); + } + if (iFetch) { + print_screen("instruction fetch "); + } + } + print_screen(") at address = "); + print_screen(integer_to_string(faultingAddress)); + print_screen("\n"); + print_serial(") at address = "); + print_serial(integer_to_string(faultingAddress)); + print_serial("\n"); + + print_screen("Creating page at address "); + print_screen(integer_to_string(faultingAddress)); + print_screen("\n"); + print_serial("Creating page at address "); + print_serial(integer_to_string(faultingAddress)); + print_serial("\n"); + +/* For testing we will allocate frame when there is page not found fault */ +#if 1 + alloc_frame(get_page(faultingAddress, 1, g_kernelDirectory), 0, 0); +#endif + + /* Optionally we can stop execution here, disabling this so that paging can + * be tested by doing the page fault + */ + // while (1) {} +} + +/* + * Utility function to clone page table + * + * TODO: Implement COW (Copy on Write) instead of copying the full table + */ +static page_table_t *clone_table(page_table_t *src, uint32_t *physAddr) { + page_table_t *table = + (page_table_t *)kmalloc_ap(sizeof(page_table_t), physAddr); + custom_memset((uint8_t *)table, 0, sizeof(page_directory_t)); + + for (uint32_t i = 0; i < 1024; ++i) { + /* If frame exist, clone it */ + if (src->pages[i].frame) { + /* + * kernel mode and user mode flags here doesn't matter as we set them + * based on flags in source page + */ + alloc_frame(&table->pages[i], 0, 0); + /* Copy permissions */ + if (src->pages[i].present) + table->pages[i].present = 1; + if (src->pages[i].rw) + table->pages[i].rw = 1; + if (src->pages[i].user) + table->pages[i].user = 1; + if (src->pages[i].accessed) + table->pages[i].accessed = 1; + if (src->pages[i].dirty) + table->pages[i].dirty = 1; + /* + * Physically copy the data across. This function is in paging.s as it + * requires paging to be disabled + */ + copy_page_physical(src->pages[i].frame * 0x1000, + table->pages[i].frame * 0x1000); + } + } + return table; +} + +page_directory_t *clone_directory(page_directory_t *src) { + uint32_t phys; + page_directory_t *dir = + (page_directory_t *)kmalloc_ap(sizeof(page_directory_t), &phys); + custom_memset((uint8_t *)dir, 0, sizeof(page_directory_t)); + + /* + * Get the offset of tablesPhysical from the start of the page_directory_t + * structure. + */ + uint32_t offset = (uint32_t)dir->tablesPhysical - (uint32_t)dir; + + /* Then the physical address of dir->tablesPhysical is: */ + dir->physicalAddr = phys + offset; + + /* Clone page table */ + for (uint32_t i = 0; i < 1024; ++i) { + /* If table entry doesn't exist skip it */ + if (!src->tables[i]) + continue; + + /* If source table is kernel table the don't copy just use the same table */ + if (g_kernelDirectory->tables[i] == src->tables[i]) { + dir->tables[i] = src->tables[i]; + dir->tablesPhysical[i] = src->tablesPhysical[i]; + } else { + uint32_t phys = 0; + dir->tables[i] = clone_table(src->tables[i], &phys); + /* PRESENT, RW, US. */ + dir->tablesPhysical[i] = phys | 0x07; + } + } + return dir; +} diff --git a/SANDHU__OS/src/mm/paging/paging.h b/SANDHU__OS/src/mm/paging/paging.h new file mode 100644 index 0000000..8a1d3ce --- /dev/null +++ b/SANDHU__OS/src/mm/paging/paging.h @@ -0,0 +1,102 @@ +#ifndef INCLUDE_PAGING_H +#define INCLUDE_PAGING_H + +#pragma once +#include + +typedef struct page { + /* Page is present in memory if set */ + uint32_t present : 1; + + /* Read-only if clear, readwrite if set */ + uint32_t rw : 1; + + /* Supervisor level only if clear */ + uint32_t user : 1; + + /* Page been accessed since last refresh if set */ + uint32_t accessed : 1; + + /* Page been written to since last refresh if set */ + uint32_t dirty : 1; + + /* Amalgamation of unused and reserved bits */ + uint32_t unused : 7; + + /* Frame address (shifted right 12 bits). Since the frames are aligned at 4kb + * least 12 bits are always zero. + */ + uint32_t frame : 20; +} page_t; + +typedef struct page_table { + page_t pages[1024]; +} page_table_t; + +typedef struct page_directory { + /* Array of pointers to pagetables. */ + page_table_t *tables[1024]; + + /* + * Array of pointers to the pagetables above, but gives their *physical* + * location, for loading into the CR3 register. + */ + uint32_t tablesPhysical[1024]; + + /* Required for cloning page direcotry */ + uint32_t physicalAddr; +} page_directory_t; + +/** init_paging: + * Sets up the environment, page directories etc and enables paging. + * + * @param kernelPhysicalEnd Physical address of location where loaded kernel + * ends + */ +void init_paging(uint32_t kernelPhysicalEnd); + +/** switch_page_directory: + * Causes the specified page directory to be loaded into the CR3 register. + * + * @param new Address of the new page directory to be switched to. + */ +void switch_page_directory(page_directory_t *new); + +/** get_page: + * Retrieves a pointer to the page required. If make == 1, if the page-table in + * which this page should reside isn't created, create it! + * + * @param address Physical address is for which the virtual page is required + * @param make Create page table if not created already. + * @param dir Pointer to the page directory + */ +page_t *get_page(uint32_t address, uint8_t make, page_directory_t *dir); + +/** alloc_frame: + * Marks that the frame is allocated based on the index calculated by page + * address. Also sets the page attributes in page table + * + * @param page Pointer to page address + * @param isKernel If set, marks page accesible only in kernel mode + * @param isWriteable If not set, markes page as read only + */ +void alloc_frame(page_t *page, uint32_t isKernel, uint32_t isWriteable); + +/** free_frame: + * Marks the current page frame as not present and removes it from the list of + * frames that exist + * + * @param page Pointer to page address + */ +void free_frame(page_t *page); + +/** clone_directory: + * Makes copy of current page directory, only non kernel pages are copied! + * Kernel pages are linked as it is. + * + * @param src Pointer to source page directory + * @return Pointer to cloned oage directory + */ +page_directory_t *clone_directory(page_directory_t *src); + +#endif /* INCLUDE_PAGING_H */ diff --git a/SANDHU__OS/src/mm/paging/paging.o b/SANDHU__OS/src/mm/paging/paging.o new file mode 100644 index 0000000..4d1cbb5 Binary files /dev/null and b/SANDHU__OS/src/mm/paging/paging.o differ diff --git a/SANDHU__OS/src/mm/paging/paging_asm.o b/SANDHU__OS/src/mm/paging/paging_asm.o new file mode 100644 index 0000000..b026897 Binary files /dev/null and b/SANDHU__OS/src/mm/paging/paging_asm.o differ diff --git a/SANDHU__OS/src/mm/paging/paging_asm.s b/SANDHU__OS/src/mm/paging/paging_asm.s new file mode 100644 index 0000000..760771b --- /dev/null +++ b/SANDHU__OS/src/mm/paging/paging_asm.s @@ -0,0 +1,31 @@ +[GLOBAL copy_page_physical] +copy_page_physical: + push ebx ; According to __cdecl, we must preserve the contents of EBX. + pushf ; push EFLAGS, so we can pop it and reenable interrupts + ; later, if they were enabled anyway. + cli ; Disable interrupts, so we aren't interrupted. + ; Load these in BEFORE we disable paging! + mov ebx, [esp+12] ; Source address + mov ecx, [esp+16] ; Destination address + + mov edx, cr0 ; Get the control register... + and edx, 0x7fffffff ; and... + mov cr0, edx ; Disable paging. + + mov edx, 1024 ; 1024*4bytes = 4096 bytes + +.loop: + mov eax, [ebx] ; Get the word at the source address + mov [ecx], eax ; Store it at the dest address + add ebx, 4 ; Source address += sizeof(word) + add ecx, 4 ; Dest address += sizeof(word) + dec edx ; One less word to do + jnz .loop + + mov edx, cr0 ; Get the control register again + or edx, 0x80000000 ; and... + mov cr0, edx ; Enable paging. + + popf ; Pop EFLAGS back. + pop ebx ; Get the original value of EBX back. + ret diff --git a/SANDHU__OS/src/mm/sched/Makefile b/SANDHU__OS/src/mm/sched/Makefile new file mode 100644 index 0000000..1619fd5 --- /dev/null +++ b/SANDHU__OS/src/mm/sched/Makefile @@ -0,0 +1,26 @@ +all: libsched.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/drivers/interrupts \ + -I$(TOP_DIR)/src/mm/heap/ \ + -I$(TOP_DIR)/src/mm/paging/ \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +# Generate Static library +SC_FLAG = ar -cvq + +libsched.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/mm/sched/sched.c b/SANDHU__OS/src/mm/sched/sched.c new file mode 100644 index 0000000..d23847b --- /dev/null +++ b/SANDHU__OS/src/mm/sched/sched.c @@ -0,0 +1,203 @@ +#include "sched.h" +#include +#include +#include +#include + +/* The pointer to current process/task */ +volatile task_t *g_currentTask; +/* Pointer to queue of processess/tasks that are ready to be scheduled */ +volatile task_t *g_readyQueue; +/* Placeholder to store original stack pointer */ +uint32_t g_initialStackPointer; + +/* + * Accessing g_kernelDirectory and g_currentDirectory defined in paging.c + * through extern since we use it for scheduling + */ +extern page_directory_t *g_kernelDirectory; +extern page_directory_t *g_currentDirectory; + +/* + * Function call to get the current instruction pointer implemented in assembly. + * Extern allows to access ASM from this C code. + */ +extern uint32_t read_eip(); +/* + * Function call to switch task, implemented in assembly. + * Extern allows to access ASM from this C code. + */ +extern void task_switch(uint32_t eip, uint32_t pageDirPhysicalAddr, uint32_t ebp, + uint32_t esp); + +/* Global variable for PID, PID of first process is 1 and incremented everytime + * we fork a new process */ +uint32_t g_PID = 1; + +void initialise_multitasking(uint32_t stackPointer) { + /* Disable interrupts */ + asm volatile("cli"); + + /* Store the current stack pointer */ + g_initialStackPointer = stackPointer; + + /* + * Relocate the stack to predefined location and mark it as non kernel memory + * so that next time we clone page directory we copy stack instead of linking + * it (clone page directory only copies non kernel pages) + */ + move_stack((void *)MEM_3_5GB, MEM_4KB); + + /* Initialise the first task (kernel task) */ + g_currentTask = g_readyQueue = (task_t *)kmalloc(sizeof(task_t)); + g_currentTask->pid = g_PID++; + g_currentTask->ebp = 0; + g_currentTask->esp = 0; + g_currentTask->eip = 0; + g_currentTask->pageDirectory = g_currentDirectory; + g_currentTask->next = 0; + + /* Enable interrupts back */ + asm volatile("sti"); +} + +void move_stack(void *newStackAddress, uint32_t size) { + uint32_t i; + /* Allocate pages for the new stack, allocation works in ascending order of + * address, stack grows in descending mem address + */ + for (i = (uint32_t)newStackAddress; + i >= ((uint32_t)newStackAddress - size - MEM_4KB); i -= MEM_4KB) { + // General-purpose stack is in user-mode. + alloc_frame(get_page(i, 1, g_currentDirectory), 0 /* User mode */, + 1 /* Is writable */); + } + + /* + * Since page table is modified flush the TLB, simply by writing back to cr3 + */ + uint32_t pdAddr; + asm volatile("mov %%cr3, %0" : "=r"(pdAddr)); + asm volatile("mov %0, %%cr3" : : "r"(pdAddr)); + + uint32_t oldStackPointer = 0; + uint32_t oldBasePointer = 0; + asm volatile("mov %%esp, %0" : "=r"(oldStackPointer)); + asm volatile("mov %%ebp, %0" : "=r"(oldBasePointer)); + + /* Offset to add to old stack addresses to get a new stack address */ + uint32_t offset = (uint32_t)newStackAddress - g_initialStackPointer; + + uint32_t newStackPointer = oldStackPointer + offset; + uint32_t newBasePointer = oldBasePointer + offset; + + /* TODO: replace size argument with size parameter*/ + custom_memcpy((void *)newStackPointer, (void *)oldStackPointer, + g_initialStackPointer - oldStackPointer); + + /* + * If the value of tmp is inside the range of the old stack, assume it is a + * base pointer and remap it. This will unfortunately remap ANY value in + * this range, whether they are base pointers or not. + */ + for (i = (uint32_t)newStackAddress; i > (uint32_t)newStackAddress - size; + i -= 4) { + uint32_t tmp = *(uint32_t *)i; + if ((oldStackPointer < tmp) && (tmp < g_initialStackPointer)) { + tmp = tmp + offset; + uint32_t *tmp2 = (uint32_t *)i; + *tmp2 = tmp; + } + } + + /* Change stack */ + asm volatile("mov %0, %%esp" : : "r"(newStackPointer)); + asm volatile("mov %0, %%ebp" : : "r"(newBasePointer)); +} + +void schedule() { + /* If we haven't initialised tasking yet, return */ + if (!g_currentTask) + return; + + uint32_t esp, ebp, eip; + asm volatile("mov %%esp, %0" : "=r"(esp)); + asm volatile("mov %%ebp, %0" : "=r"(ebp)); + + /* + * Read the instruction pointer: + * One of two things could have happened when this function exits - + * (a) We called the function and it returned the EIP as requested. + * (b) We have just switched tasks, and because the saved EIP is essentially + * the instruction after read_eip(), it will seem as if read_eip has + * just returned. + * In the second case we need to return immediately. To detect it we put a + * dummy value in EAX further down at the end of this function. As C returns + * values in EAX, it will look like the return value is this dummy value! + * (0x12345). + */ + eip = read_eip(); + + /* Have we just switched tasks? */ + if (eip == 0x12345) + return; + + g_currentTask->eip = eip; + g_currentTask->esp = esp; + g_currentTask->ebp = ebp; + + /* Since g_currentTask is initialised with g_readyQueue*/ + g_currentTask = g_currentTask->next; + if (!g_currentTask) + g_currentTask = g_readyQueue; + + eip = g_currentTask->eip; + esp = g_currentTask->esp; + ebp = g_currentTask->ebp; + g_currentDirectory = g_currentTask->pageDirectory; + + task_switch(eip, g_currentDirectory->physicalAddr, ebp, esp); +} + +uint32_t fork() { + asm volatile("cli"); + + task_t *parentTask = (task_t *)g_currentTask; + page_directory_t *directory = clone_directory(g_currentDirectory); + task_t *newTask = (task_t *)kmalloc(sizeof(task_t)); + + newTask->pid = g_PID++; + newTask->esp = 0; + newTask->ebp = 0; + newTask->eip = 0; + newTask->pageDirectory = directory; + newTask->next = 0; + + /* Add it to the end of the ready queue */ + task_t *tempTask = (task_t *)g_readyQueue; + while (tempTask->next) + tempTask = tempTask->next; + tempTask->next = newTask; + + /* Forked process starts executing from current instruction of parent */ + uint32_t eip = read_eip(); + + /* We could be the parent or the child here - check */ + if (g_currentTask == parentTask) { + /* We are the parent, so set up the esp/ebp/eip for our child */ + uint32_t esp; + asm volatile("mov %%esp, %0" : "=r"(esp)); + uint32_t ebp; + asm volatile("mov %%ebp, %0" : "=r"(ebp)); + newTask->esp = esp; + newTask->ebp = ebp; + newTask->eip = eip; + asm volatile("sti"); + return newTask->pid; + } else { + /* We are the child */ + return 0; + } +} + +uint32_t getpid() { return g_currentTask->pid; } diff --git a/SANDHU__OS/src/mm/sched/sched.h b/SANDHU__OS/src/mm/sched/sched.h new file mode 100644 index 0000000..6df0d24 --- /dev/null +++ b/SANDHU__OS/src/mm/sched/sched.h @@ -0,0 +1,54 @@ +#ifndef INCLUDE_SCHED_H +#define INCLUDE_SCHED_H + +#pragma once +#include +#include + +typedef struct task { + /* TODO: Add parent pid information and implement join */ + /* Process ID */ + uint32_t pid; + /* Base pointer */ + uint32_t ebp; + /* Stack pointer */ + uint32_t esp; + /* Instruction pointer */ + uint32_t eip; + /* Pointer to process page directory */ + page_directory_t *pageDirectory; + /* Pointer to next task */ + struct task *next; +} task_t; + +/** initialise_tasking: + * Function to initialize multitasking + * @param stackPointer Initial address of the stack when kernel is loaded + */ +void initialise_multitasking(uint32_t stackPointer); + +/** schedule: + * Schedule next task when the timer elapsed (Based of frequency variable + * TIMER_FREQUENCY in timer.h) + */ +void schedule(); + +/** fork: + * API to fork the process and create new one out of it + */ +uint32_t fork(); + +/** move_stack: + * Relocate stack to new address + * @param newStackAddress Pointer to address where the stack need to be moved + * @param size Size of the stack + */ +void move_stack(void *newStackAddress, uint32_t size); + +/** get_pid: + * returns PID of the process + * @return Process ID + */ +uint32_t getpid(); + +#endif /* INCLUDE_SCHED_H */ diff --git a/SANDHU__OS/src/mm/sched/sched.o b/SANDHU__OS/src/mm/sched/sched.o new file mode 100644 index 0000000..80ac637 Binary files /dev/null and b/SANDHU__OS/src/mm/sched/sched.o differ diff --git a/SANDHU__OS/src/mm/sched/sched_asm.o b/SANDHU__OS/src/mm/sched/sched_asm.o new file mode 100644 index 0000000..c7831e1 Binary files /dev/null and b/SANDHU__OS/src/mm/sched/sched_asm.o differ diff --git a/SANDHU__OS/src/mm/sched/sched_asm.s b/SANDHU__OS/src/mm/sched/sched_asm.s new file mode 100644 index 0000000..20bb1ab --- /dev/null +++ b/SANDHU__OS/src/mm/sched/sched_asm.s @@ -0,0 +1,30 @@ +[GLOBAL read_eip] +read_eip: + ; Get the return address + pop eax + ; Can't use RET because return address popped off the stack. + jmp eax + +; Here we: +; * Stop interrupts so we don't get interrupted. +; * Temporarily put the new EIP location in ECX. +; * Temporarily put the new page directory's physical address in EAX. +; * Set the base and stack pointers +; * Set the page directory +; * Put a dummy value (0x12345) in EAX so that above we can recognize that +; we've just switched task. +; * Restart interrupts. The STI instruction has a delay - it doesn't take +; effect until after the next instruction. +; * Jump to the location in ECX (remember we put the new EIP in there). + +[GLOBAL task_switch] +task_switch: + cli; + mov ecx, [esp+4] ; EIP + mov eax, [esp+8] ; physical address of current directory + mov ebp, [esp+12] ; EBP + mov esp, [esp+16] ; ESP + mov cr3, eax ; set the page directory + mov eax, 0x12345 ; magic number to detect a task switch + sti; + jmp ecx diff --git a/SANDHU__OS/src/mm/segmentation/Makefile b/SANDHU__OS/src/mm/segmentation/Makefile new file mode 100644 index 0000000..85dcd4e --- /dev/null +++ b/SANDHU__OS/src/mm/segmentation/Makefile @@ -0,0 +1,25 @@ +all: libgdt.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/utils/common \ + +AS = nasm +ASFLAGS = -f elf + +# Generate Static library +SC_FLAG = ar -cvq + +libgdt.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/mm/segmentation/gdt.c b/SANDHU__OS/src/mm/segmentation/gdt.c new file mode 100644 index 0000000..393936f --- /dev/null +++ b/SANDHU__OS/src/mm/segmentation/gdt.c @@ -0,0 +1,67 @@ +#include "gdt.h" + +/* Access ASM function from C code. */ +extern void gdt_flush(uint32_t, uint32_t); + +/* Define number of segments, including null segment */ +#define NUM_OF_SEGMENTS 3 + +/* Define number of kernel segments */ +#define NUM_OF_KERNEL_SEGMENTS 2 + +/* Define 3 entries each for null, kernel code and kernel data */ +gdt_entry_t gdt_entries[NUM_OF_SEGMENTS]; + +/* Set the value of GDT entry. */ +static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, + uint8_t gran) { + gdt_entries[num].base_low = (base & 0xFFFF); + gdt_entries[num].base_middle = (base >> 16) & 0xFF; + gdt_entries[num].base_high = (base >> 24) & 0xFF; + + gdt_entries[num].limit_low = (limit & 0xFFFF); + + /* + * name | value | size | desc + * --------------------------- + * P | 1 | 1 | segment present in memory + * DPL | pl | 2 | privilege level + * S | 1 | 1 | descriptor type, 0 = system, 1 = code or data + * Type | type | 4 | segment type, how the segment can be accessed + * Access = 0x9A privilege 0 code segment, Access = 0x92 for privilege 0 data + * segment + */ + gdt_entries[num].access = access; + + /* + * name | value | size | desc + * --------------------------- + * G | 1 | 1 | granularity, size of segment unit, 1 = 4kB + * D/B | 1 | 1 | size of operation size, 0 = 16 bits, 1 = 32 bits + * L | 0 | 1 | 1 = 64 bit code + * AVL | 0 | 1 | "available for use by system software" + * LIM | 0xF | 4 | the four highest bits of segment limit + * Granularity = 0xCF as far as highest bits of segment limit is 0xFFFFFFFF + */ + gdt_entries[num].granularity = gran; +} + +void init_gdt() { + gdt_ptr_t gdt_ptr; + + /* Define array to hold kernel segment offset address, excluding null entry */ + uint32_t gdt_kernel_segments_offset[NUM_OF_KERNEL_SEGMENTS]; + + gdt_ptr.limit = (sizeof(gdt_entry_t) * NUM_OF_SEGMENTS) - 1; + gdt_ptr.base = (uint32_t)&gdt_entries; + + gdt_set_gate(0, 0, 0, 0, 0); // Null segment + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel Code segment + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Kernel Data segment + + for (uint32_t i = 0, j = 8; i < NUM_OF_KERNEL_SEGMENTS; i++) { + gdt_kernel_segments_offset[i] = j; + j += 8; + } + gdt_flush((uint32_t)&gdt_ptr, (uint32_t)&gdt_kernel_segments_offset); +} diff --git a/SANDHU__OS/src/mm/segmentation/gdt.h b/SANDHU__OS/src/mm/segmentation/gdt.h new file mode 100644 index 0000000..5462ed9 --- /dev/null +++ b/SANDHU__OS/src/mm/segmentation/gdt.h @@ -0,0 +1,37 @@ +#ifndef INCLUDE_GDT_H +#define INCLUDE_GDT_H + +#pragma once +#include + +/* This structure contains the value of one GDT entry. + * We use the attribute 'packed' to tell GCC not to change + * any of the alignment in the structure. + */ +struct gdt_entry_struct { + uint16_t limit_low; // The lower 16 bits of the limit. + uint16_t base_low; // The lower 16 bits of the base. + uint8_t base_middle; // The next 8 bits of the base. + uint8_t + access; // Access flags, determine what ring this segment can be used in. + uint8_t granularity; + uint8_t base_high; // The last 8 bits of the base. +} __attribute__((packed)); + +typedef struct gdt_entry_struct gdt_entry_t; + +/* This struct describes a GDT pointer. It points to the start of + * our array of GDT entries, and is in the format required by the + * lgdt instruction. + */ +struct gdt_ptr_struct { + uint16_t limit; // The upper 16 bits of table with entries. + uint32_t base; // The address of the first gdt_entry_t struct. +} __attribute__((packed)); + +typedef struct gdt_ptr_struct gdt_ptr_t; + +/* Function to initialize GDT */ +void init_gdt(); + +#endif /* INCLUDE_GDT_H */ diff --git a/SANDHU__OS/src/mm/segmentation/gdt.o b/SANDHU__OS/src/mm/segmentation/gdt.o new file mode 100644 index 0000000..fcf882b Binary files /dev/null and b/SANDHU__OS/src/mm/segmentation/gdt.o differ diff --git a/SANDHU__OS/src/mm/segmentation/gdt_asm.o b/SANDHU__OS/src/mm/segmentation/gdt_asm.o new file mode 100644 index 0000000..ad8e1ca Binary files /dev/null and b/SANDHU__OS/src/mm/segmentation/gdt_asm.o differ diff --git a/SANDHU__OS/src/mm/segmentation/gdt_asm.s b/SANDHU__OS/src/mm/segmentation/gdt_asm.s new file mode 100644 index 0000000..f47f98c --- /dev/null +++ b/SANDHU__OS/src/mm/segmentation/gdt_asm.s @@ -0,0 +1,16 @@ +global gdt_flush ; Allows the C code to call gdt_flush(). + +gdt_flush: + mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter. + mov ebx, [esp+8] ; Get the pointer to segments offsets in GDT. + lgdt [eax] ; Load the new GDT pointer + + mov ax, [ebx + 4] ; 0x10 is the offset in the GDT to our data segment + mov ds, ax ; Load all data segment selectors + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump! +.flush: + ret diff --git a/SANDHU__OS/src/mm/vfs/Makefile b/SANDHU__OS/src/mm/vfs/Makefile new file mode 100644 index 0000000..aa146ed --- /dev/null +++ b/SANDHU__OS/src/mm/vfs/Makefile @@ -0,0 +1,6 @@ +SUBDIRS = \ + fs \ + initrd + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs diff --git a/SANDHU__OS/src/mm/vfs/fs/Makefile b/SANDHU__OS/src/mm/vfs/fs/Makefile new file mode 100644 index 0000000..facb5ec --- /dev/null +++ b/SANDHU__OS/src/mm/vfs/fs/Makefile @@ -0,0 +1,19 @@ +all: libfs.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/utils/common \ + +# Generate Static library +SC_FLAG = ar -cvq + +libfs.a: $(C_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ diff --git a/SANDHU__OS/src/mm/vfs/fs/fs.c b/SANDHU__OS/src/mm/vfs/fs/fs.c new file mode 100644 index 0000000..0920e15 --- /dev/null +++ b/SANDHU__OS/src/mm/vfs/fs/fs.c @@ -0,0 +1,55 @@ +#include "fs.h" + +/* filesystem root */ +fs_node_t *fs_root = 0; + +uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + /* If node has a read callback, call it */ + if (node->read != 0) { + return node->read(node, offset, size, buffer); + } else { + return 0; + } +} + +uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + /* If node has a write callback, call it */ + if (node->write != 0) { + return node->write(node, offset, size, buffer); + } else { + return 0; + } +} + +int32_t open_fs(fs_node_t *node, uint8_t write) { + /* If node has a open callback, call it */ + if (node->open != 0) { + return node->open(node, write); + } else { + return -1; + } +} + +void close_fs(fs_node_t *node) { + /* If node has a close callback, call it */ + if (node->close != 0) + node->close(node); +} + +uint8_t readdir_fs(fs_node_t *node, uint32_t index, fs_node_t *directory) { + /* If the node is a directory and it has a readdir callback, call it */ + if ((node->type & LEN_7) == FS_DIRECTORY && node->readdir != 0) { + return node->readdir(node, index, directory); + } else { + return 1; + } +} + +fs_node_t *finddir_fs(fs_node_t *node, char *name) { + /* If the node is a directory and it has a finddir callback, call it */ + if ((node->type & LEN_7) == FS_DIRECTORY && node->finddir != 0) { + return node->finddir(node, name); + } else { + return 0; + } +} diff --git a/SANDHU__OS/src/mm/vfs/fs/fs.h b/SANDHU__OS/src/mm/vfs/fs/fs.h new file mode 100644 index 0000000..933e974 --- /dev/null +++ b/SANDHU__OS/src/mm/vfs/fs/fs.h @@ -0,0 +1,133 @@ +#ifndef INCLUDE_FS_H +#define INCLUDE_FS_H + +#pragma once +#include + +/* MAcros to identify the node type */ +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x03 +#define FS_BLOCKDEVICE 0x04 +#define FS_PIPE 0x05 +#define FS_SYMLINK 0x06 +/* Skipping 0x07 so that 0x08 can be masked easily to checj if it is a mount */ +#define FS_MOUNTPOINT 0x08 + +/* Forward declarations (for below callbacks)*/ +struct fs_node; + +/* + * POSIX specific file specific callbacks APIs, every node will have this + * functions supported + */ + +/* read file */ +typedef uint32_t (*read_type_t)(struct fs_node *, uint32_t, uint32_t, uint8_t *); + +/* write to file */ +typedef uint32_t (*write_type_t)(struct fs_node *, uint32_t, uint32_t, uint8_t *); + +/* open file */ +typedef int32_t (*open_type_t)(struct fs_node *, uint8_t write); + +/* close file */ +typedef void (*close_type_t)(struct fs_node *); + +/* read nth entry in the directory, return 0 if index is out of bound */ +typedef uint8_t (*readdir_type_t)(struct fs_node *, uint32_t, struct fs_node *); + +/* find the entry in directory, return 0 if not present */ +typedef struct fs_node *(*finddir_type_t)(struct fs_node *, char *name); + +/* File node struct */ +typedef struct fs_node { + /* Filename (limited to 64 characters) */ + int8_t name[LEN_64]; + /* Permissions mask (unix-like mask - user, group, others) */ + uint32_t mask; + /* Owning user */ + uint32_t uid; + /* Owning group */ + uint32_t gid; + /* Node type - directory/file/mounttype */ + uint32_t type; + /* Device-specific - for filesystem to identify files (POSIX specific) */ + uint32_t inode; + /* Size of the file, in bytes */ + uint32_t length; + read_type_t read; + write_type_t write; + open_type_t open; + close_type_t close; + readdir_type_t readdir; + finddir_type_t finddir; + /* For MounPoint, directories and Symlinks, contents and size */ + struct fs_node *contents; + uint32_t size; +} fs_node_t; + +/* + * POSIX specific file specific functions for file system to support + */ + +/** read_fs: + * read the contents of the file specified by node. + * + * @param node Pointer to file node + * @param offset Offset from where to start reading + * @param size Size to read + * @param buffer Pointer to a buffer to which the contents are to be + * copied + * @return Size of data read in number of bytes + */ +uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); + +/** write_fs: + * write to the file specified by node. + * + * @param node Pointer to file node + * @param offset Offset from where to start writing + * @param size Size to write + * @param buffer Pointer to a buffer to which the contents are to be + * copied + */ +uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); + +/** open_fs: + * open the file specified by node. + * + * @param node Pointer to file node + * @param offset Offset from where to start writing + * @param write Flag to specify mode, 1 write, 0 read + * @return file descriptor (a uniqure number) if success -1 otherwise + */ +int32_t open_fs(fs_node_t *node, uint8_t write); + +/** close_fs: + * close the file specified by node. + * + * @param node Pointer to file node + */ +void close_fs(fs_node_t *node); + +/** readdir_fs: + * read directory specified by node. + * + * @param node Pointer to directory node + * @param index Index of entry in direcoty + * @param directory Pointer to directory entry at index if exist, return 0 + * if success 0 otherwise + */ +uint8_t readdir_fs(fs_node_t *node, uint32_t index, fs_node_t *directory); + +/** findir_fs: + * if file/directory in the directory specified by node. + * + * @param node Pointer to directory node + * @param name name of the directory or file to find + * @return Pointer to file/directory node if exist 0 otherwise + */ +fs_node_t *finddir_fs(fs_node_t *node, int8_t *name); + +#endif /* INCLUDE_FS_H */ diff --git a/SANDHU__OS/src/mm/vfs/fs/fs.o b/SANDHU__OS/src/mm/vfs/fs/fs.o new file mode 100644 index 0000000..76c693e Binary files /dev/null and b/SANDHU__OS/src/mm/vfs/fs/fs.o differ diff --git a/SANDHU__OS/src/mm/vfs/initrd/Makefile b/SANDHU__OS/src/mm/vfs/initrd/Makefile new file mode 100644 index 0000000..16252e0 --- /dev/null +++ b/SANDHU__OS/src/mm/vfs/initrd/Makefile @@ -0,0 +1,21 @@ +all: libinitrd.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/mm/heap \ + -I$(TOP_DIR)/src/mm/vfs/fs \ + -I$(TOP_DIR)/src/utils/common + +# Generate Static library +SC_FLAG = ar -cvq + +libinitrd.a: $(C_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ diff --git a/SANDHU__OS/src/mm/vfs/initrd/initrd.c b/SANDHU__OS/src/mm/vfs/initrd/initrd.c new file mode 100644 index 0000000..8ca6b94 --- /dev/null +++ b/SANDHU__OS/src/mm/vfs/initrd/initrd.c @@ -0,0 +1,139 @@ +#include "initrd.h" +#include +#include + +/* + * Global list of file headers, based on inode we will index this list and get + * the contents + */ +initrd_file_header_t *g_FILE_HEADERS; +/* Root directory node */ +fs_node_t *g_INITRD_ROOT_DIR; +/* Global variable to keep track of inodes */ +static uint32_t g_INODE; +/* Name of root directory */ +static const char g_ROOT_DIR[2] = "/"; + +static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, + uint8_t *buffer) { + initrd_file_header_t header = g_FILE_HEADERS[node->inode]; + if (offset > header.length) + return 0; + if (offset + size > header.length) + size = header.length - offset; + custom_memcpy(buffer, (uint8_t *)(header.offset + offset), size); + return size; +} + +static uint8_t initrd_readdir(fs_node_t *node, uint32_t index, + fs_node_t *directory) { + if (directory == 0) { + return 1; + } + + if (index >= node->size) { + return 1; + } + + custom_memcpy((uint8_t *)directory, (uint8_t *)&node->contents[index], + sizeof(fs_node_t)); + return 0; +} + +static fs_node_t *initrd_finddir(fs_node_t *node, char *name) { + for (uint32_t i = 0; i < node->size; i++) + if (!custom_strcmp(name, node->contents[i].name, 1)) + return &node->contents[i]; + return 0; +} + +/* Initialise the root directory, /dev directory and populate the them */ +void initialise_initrd(uint32_t location) { + uint32_t numOfNodes = *((uint32_t *)location); + initrd_file_header_t *fileHeaderPtr = + (initrd_file_header_t *)(location + sizeof(uint32_t)); + + /* Allocate size of 64 global file node headers we can expand it later */ + g_FILE_HEADERS = + (initrd_file_header_t *)kmalloc(sizeof(initrd_file_header_t) * LEN_64); + + /* Initialise the root directory */ + g_INITRD_ROOT_DIR = (fs_node_t *)kmalloc(sizeof(fs_node_t)); + /* Initialise the /dev directory, we mount our fs here */ + fs_node_t *initrdDevDir = (fs_node_t *)kmalloc(sizeof(fs_node_t)); + /* Initialise /dev nodes */ + fs_node_t *initrdDevNodes = + (fs_node_t *)kmalloc(sizeof(fs_node_t) * numOfNodes); + + /* Populate /root directory */ + custom_strcpy(g_INITRD_ROOT_DIR->name, &g_ROOT_DIR[0]); + g_INITRD_ROOT_DIR->mask = g_INITRD_ROOT_DIR->uid = g_INITRD_ROOT_DIR->gid = 0; + g_INITRD_ROOT_DIR->inode = g_INODE++; + g_INITRD_ROOT_DIR->length = 0; + g_INITRD_ROOT_DIR->type = FS_DIRECTORY; + g_INITRD_ROOT_DIR->read = g_INITRD_ROOT_DIR->write = 0; + g_INITRD_ROOT_DIR->open = 0; + g_INITRD_ROOT_DIR->close = 0; + g_INITRD_ROOT_DIR->readdir = &initrd_readdir; + g_INITRD_ROOT_DIR->finddir = &initrd_finddir; + /* For now we will only have /dev in our /root directory */ + g_INITRD_ROOT_DIR->contents = initrdDevDir; + g_INITRD_ROOT_DIR->size = 1; + g_FILE_HEADERS[g_INITRD_ROOT_DIR->inode].magic = 0xCA; + custom_strcpy(g_FILE_HEADERS[g_INITRD_ROOT_DIR->inode].name, + g_INITRD_ROOT_DIR->name); + g_FILE_HEADERS[g_INITRD_ROOT_DIR->inode].type = FS_DIRECTORY; + g_FILE_HEADERS[g_INITRD_ROOT_DIR->inode].offset = 0; + g_FILE_HEADERS[g_INITRD_ROOT_DIR->inode].length = 0; + + /* Populate /dev directory */ + custom_strcpy(initrdDevDir->name, "dev"); + initrdDevDir->mask = initrdDevDir->uid = initrdDevDir->gid = 0; + initrdDevDir->inode = g_INODE++; + initrdDevDir->length = 0; + initrdDevDir->type = FS_DIRECTORY; + initrdDevDir->read = initrdDevDir->write = 0; + initrdDevDir->open = 0; + initrdDevDir->close = 0; + initrdDevDir->readdir = &initrd_readdir; + initrdDevDir->finddir = &initrd_finddir; + /* /dev will have files loaded from initrd */ + initrdDevDir->contents = initrdDevNodes; + initrdDevDir->size = numOfNodes; + g_FILE_HEADERS[initrdDevDir->inode].magic = 0xCA; + custom_strcpy(g_FILE_HEADERS[initrdDevDir->inode].name, initrdDevDir->name); + g_FILE_HEADERS[initrdDevDir->inode].type = FS_DIRECTORY; + g_FILE_HEADERS[initrdDevDir->inode].offset = 0; + g_FILE_HEADERS[initrdDevDir->inode].length = 0; + + /* + * Copy initrd file header to global variable, although this is duplicate this + * simplifies the maintainance of file system as we keep on adding file nodes + * during run time + */ + custom_memcpy((uint8_t *)&g_FILE_HEADERS[g_INODE], (uint8_t *)fileHeaderPtr, + sizeof(initrd_file_header_t) * numOfNodes); + + for (uint32_t i = 0; i < numOfNodes; i++) { + /* + * Edit the file's header - currently it holds the file offset + * relative to the start of the ramdisk. We want it relative to the start + * of memory + */ + g_FILE_HEADERS[g_INODE].offset += location; + + /* Populate nodes */ + custom_strcpy(initrdDevNodes[i].name, &(g_FILE_HEADERS[g_INODE].name[0])); + initrdDevNodes[i].mask = initrdDevNodes[i].uid = initrdDevNodes[i].gid = 0; + initrdDevNodes[i].length = g_FILE_HEADERS[g_INODE].length; + initrdDevNodes[i].inode = g_INODE++; + initrdDevNodes[i].type = FS_FILE; + initrdDevNodes[i].read = &initrd_read; + initrdDevNodes[i].write = 0; + initrdDevNodes[i].readdir = 0; + initrdDevNodes[i].finddir = 0; + initrdDevNodes[i].open = 0; + initrdDevNodes[i].close = 0; + initrdDevNodes[i].contents = 0; + } +} diff --git a/SANDHU__OS/src/mm/vfs/initrd/initrd.h b/SANDHU__OS/src/mm/vfs/initrd/initrd.h new file mode 100644 index 0000000..c5e3407 --- /dev/null +++ b/SANDHU__OS/src/mm/vfs/initrd/initrd.h @@ -0,0 +1,28 @@ +#ifndef INCLUDE_INITRD_H +#define INCLUDE_INITRD_H + +#pragma once +#include +#include + +typedef struct { + /* Magic number, for error checking */ + uint8_t magic; + /* Filename */ + int8_t name[LEN_64]; + /* Node type, file = 1, directory = 2 */ + int8_t type; + /* Offset in the initrd where file starts */ + uint32_t offset; + /* Length of the file */ + uint32_t length; +} initrd_file_header_t; + +/** initialise_initrd: + * Initialises the initial ramdisk. + * + * @param location Address of the multiboot module + */ +void initialise_initrd(uint32_t location); + +#endif /* INCLUDE_INITRD_H */ diff --git a/SANDHU__OS/src/mm/vfs/initrd/initrd.o b/SANDHU__OS/src/mm/vfs/initrd/initrd.o new file mode 100644 index 0000000..4c7a9cb Binary files /dev/null and b/SANDHU__OS/src/mm/vfs/initrd/initrd.o differ diff --git a/SANDHU__OS/src/tests/tests.h b/SANDHU__OS/src/tests/tests.h new file mode 100644 index 0000000..ad8655e --- /dev/null +++ b/SANDHU__OS/src/tests/tests.h @@ -0,0 +1,234 @@ +#ifndef INCLUDE_TESTS_H +#define INCLUDE_TESTS_H + +/* Forward declare sleep function from timer.h */ +void sleep(uint32_t centiSeconds); + +/* Defined in kheap.c */ +extern uint32_t g_CurrentPhysicalAddressTop; +/* Defined in initrd.c */ +extern fs_node_t *g_INITRD_ROOT_DIR; + +void run_all_tests() { + + // test logger + print_screen("\n=============================="); + print_serial("\n=============================="); + print_screen("\nTesting Printf... it works!!!"); + print_serial("\nTesting COM port... it works!!!"); + + // test interrupts + print_screen("\n\n=============================="); + print_serial("\n\n=============================="); + print_screen("\nTesting Interrupt by raising interrupt 34"); + print_serial("\nTesting Interrupt by raising interrupt 34"); + asm volatile("int $0x22"); + + // test paging + print_screen("\n\n=============================="); + print_serial("\n\n=============================="); + print_screen("\nTesting paging, trying to access address "); + print_serial("\nTesting paging, trying to access address "); + print_screen(integer_to_string(g_CurrentPhysicalAddressTop + 0x1000)); + print_serial("\nTesting paging, trying to access address "); + print_serial(integer_to_string(g_CurrentPhysicalAddressTop + 0x1000)); + print_screen("\n"); + print_serial("\n"); + uint32_t *ptr = (uint32_t *)(g_CurrentPhysicalAddressTop + 0x1000); + *ptr = 10; + print_screen("Out of page fault, page allocation works!!!\n"); + print_serial("Out of page fault, page allocation works!!!\n"); + + print_screen("\nTesting continues please wait..."); + /* Sleep for 10 seconds (1000 centiSeconds) */ + sleep(1000); + clear_screen(); + + // test heap + print_screen("\n=============================="); + print_serial("\n=============================="); + print_screen("\nTesting kernel heap.... "); + print_serial("\nTesting kernel heap.... "); + + print_screen("\n=============================="); + print_serial("\n=============================="); + print_screen("\nTesting kernel malloc.... "); + print_serial("\nTesting kernel malloc.... "); + + print_screen("\nCalling kmalloc() for allocating 8 bytes"); + print_serial("\nCalling kmalloc() for allocating 8 bytes"); + uint32_t *x = (uint32_t *)kmalloc(8); + print_screen("\nkmalloc() allocated 8 bytes at address: "); + print_screen(integer_to_string((uint32_t)x)); + print_screen("\n"); + print_serial("\nkmalloc() allocated 8 bytes at address: "); + print_serial(integer_to_string((uint32_t)x)); + print_serial("\n"); + + print_screen("\nCalling kmalloc() for allocating 10 bytes"); + print_serial("\nCalling kmalloc() for allocating 10 bytes"); + uint32_t y = kmalloc(10); + print_screen("\nkmalloc() allocated 10 bytes at address: "); + print_screen(integer_to_string(y)); + print_screen("\n"); + print_serial("\nkmalloc() allocated 10 bytes at address: "); + print_serial(integer_to_string(y)); + print_serial("\n"); + + print_screen("\nCalling kmalloc() for allocating 8 bytes"); + print_serial("\nCalling kmalloc() for allocating 8 bytes"); + uint32_t z = kmalloc(8); + print_screen("\nkmalloc() allocated 8 bytes at address: "); + print_screen(integer_to_string(z)); + print_screen("\n"); + print_serial("\nkmalloc() allocated 8 bytes at address: "); + print_serial(integer_to_string(z)); + print_serial("\n"); + + print_screen("\n=============================="); + print_serial("\n=============================="); + print_screen("\nTesting kernel free.... "); + print_serial("\nTesting kernel free.... "); + + print_screen("\nCalling kfree() to deallocate address: "); + print_serial("\nCalling kfree() to deallocate address: "); + print_screen(integer_to_string((uint32_t)x)); + print_serial(integer_to_string((uint32_t)x)); + print_screen("\n"); + print_serial("\n"); + kfree((void *)x); + + print_screen("\nCalling kmalloc() for allocating 20 bytes"); + print_serial("\nCalling kmalloc() for allocating 20 bytes"); + x = (uint32_t *)kmalloc(20); + print_screen("\nkmalloc() allocated 20 bytes at address: "); + print_screen(integer_to_string((uint32_t)x)); + print_screen("\n"); + print_serial("\nkmalloc() allocated 20 bytes at address: "); + print_serial(integer_to_string((uint32_t)x)); + print_serial("\n"); + + print_screen("\nCalling kmalloc() for allocating 8 bytes"); + print_serial("\nCalling kmalloc() for allocating 8 bytes"); + uint32_t *p = (uint32_t *)kmalloc(8); + print_screen("\nkmalloc() allocated 8 bytes at address: "); + print_screen(integer_to_string((uint32_t)p)); + print_screen("\n"); + print_serial("\nkmalloc() allocated 8 bytes at address: "); + print_serial(integer_to_string((uint32_t)p)); + print_serial("\n"); + + print_screen("\nTesting continues please wait..."); + /* Sleep for 10 seconds (1000 centiSeconds) */ + sleep(1000); + clear_screen(); + + // test multiboot + print_screen("\n=============================="); + print_serial("\n=============================="); + print_screen("\nTesting Multiboot..."); + print_serial("\nTesting Multiboot..."); + + uint32_t mboot_ptr = get_multiboot_address(); + print_screen("\nMboot address loaded at "); + print_serial("\nMboot address loaded at "); + print_screen(integer_to_string(mboot_ptr)); + print_serial(integer_to_string(mboot_ptr)); + + uint32_t initrdPhysicalStart; + uint32_t multibootPhysicalEnd; + uint32_t modsCount; + get_multiboot_info(mboot_ptr, &initrdPhysicalStart, &multibootPhysicalEnd, + &modsCount); + print_screen("\nInitrd loaded at address "); + print_serial("\nInitrd loaded at address "); + print_screen(integer_to_string(initrdPhysicalStart)); + print_serial(integer_to_string(initrdPhysicalStart)); + print_screen("\nMultiboot modules end at address "); + print_serial("\nMultiboot modules end at address "); + print_screen(integer_to_string(multibootPhysicalEnd)); + print_serial(integer_to_string(multibootPhysicalEnd)); + print_screen("\nNumber of modules loaded = "); + print_serial("\nNumber of modules loaded = "); + print_screen(integer_to_string(modsCount)); + print_serial(integer_to_string(modsCount)); + + // test virtual file system + print_screen("\n\n=============================="); + print_serial("\n\n=============================="); + print_screen("\nTesting virtual file system"); + print_screen("\nreading contents of directory /dev\n"); + print_serial("\nTesting virtual file system"); + print_serial("\nreading contents of directory /dev\n"); + + // list the contents of /dev + fs_node_t *node = (fs_node_t *)kmalloc(sizeof(fs_node_t)); + /* root (/) at this point has just /dev so directly access contents */ + fs_node_t *fs_root = g_INITRD_ROOT_DIR->contents; + for (uint32_t i = 0; i < fs_root->size; ++i) { + readdir_fs(fs_root, i, node); + if (node->type == FS_FILE) { + print_screen("\nFound file -> "); + print_serial("\nFound file -> "); + print_screen(node->name); + print_serial(node->name); + print_screen("\n\t contents: "); + print_serial("\n\t contents: "); + int8_t buf[LEN_256]; + uint32_t sz = read_fs(node, 0, LEN_256, (uint8_t *)&(buf[0])); + uint32_t j; + for (j = 0; j < sz; j++) { + print_screen_ch(buf[j]); + print_serial_ch(buf[j]); + } + print_screen("\n"); + print_serial("\n"); + } else { + print_screen("\nFound dir "); + print_serial("\nFound dir "); + print_screen(node->name); + print_serial(node->name); + print_screen("\n"); + print_serial("\n"); + } + } + + print_screen("\nTesting continues please wait..."); + /* Sleep for 10 seconds (1000 centiSeconds) */ + sleep(1000); + clear_screen(); + + // test multitasking + print_screen("\n\n=============================="); + print_serial("\n\n=============================="); + print_screen("\nTesting multitasking"); + print_screen("\nCalling process fork\n"); + print_serial("\nTesting multitasking"); + print_serial("\nCalling process fork\n"); + + uint32_t ret = fork(); + + print_screen("\n\n==============================\n"); + print_serial("\n\n==============================\n"); + print_screen("fork() returned "); + print_serial("fork() returned "); + print_screen(integer_to_string(ret)); + print_serial(integer_to_string(ret)); + print_screen(", and getpid() returned "); + print_serial(", and getpid() returned "); + print_screen(integer_to_string(getpid())); + print_serial(integer_to_string(getpid())); + + print_screen("\n============================================================" + "================\n"); + print_serial("\n============================================================" + "================\n"); + + // test keyboard + print_screen("\n=============================="); + print_serial("\n=============================="); + print_screen("\nKeyboard Enabled, type something!!!!\n"); + print_serial("\nKeyboard Enabled, type something!!!!\n"); +} + +#endif /* INCLUDE_TESTS_H */ diff --git a/SANDHU__OS/src/utils/Makefile b/SANDHU__OS/src/utils/Makefile new file mode 100644 index 0000000..246ff9f --- /dev/null +++ b/SANDHU__OS/src/utils/Makefile @@ -0,0 +1,14 @@ +COPY_FILES = bochsConfig/bochsrc.txt + +SUBDIRS = \ + array \ + common \ + logger + +all: copyConfigFiles + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +copyConfigFiles: + cp -f $(COPY_FILES) ${ETC_DIR}/ diff --git a/SANDHU__OS/src/utils/array/Makefile b/SANDHU__OS/src/utils/array/Makefile new file mode 100644 index 0000000..c3954cb --- /dev/null +++ b/SANDHU__OS/src/utils/array/Makefile @@ -0,0 +1,27 @@ +all: liborderedarray.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +#C_SOURCES += $(TOP_DIR)/src/drivers/frame_buffer/frame_buffer.c \ +# $(TOP_DIR)/src/drivers/serial_port/serial_port.c + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/mm/heap \ + -I$(TOP_DIR)/src/utils/common \ + -I$(TOP_DIR)/src/utils/logger + +# Generate Static library +SC_FLAG = ar -cvq + +liborderedarray.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/utils/array/ordered_array.c b/SANDHU__OS/src/utils/array/ordered_array.c new file mode 100644 index 0000000..c282a47 --- /dev/null +++ b/SANDHU__OS/src/utils/array/ordered_array.c @@ -0,0 +1,77 @@ +#include "ordered_array.h" +#include +#include +#include + +ordered_array_t create_ordered_array(uint32_t maxSize, + compare_predicate_t compare) { + ordered_array_t toRet; + toRet.array = (type_t *)kmalloc(maxSize * sizeof(type_t)); + custom_memset((uint8_t *)toRet.array, 0, maxSize * sizeof(type_t)); + toRet.size = 0; + toRet.maxSize = maxSize; + toRet.compare = compare; + return toRet; +} + +ordered_array_t place_ordered_array(void *address, uint32_t maxSize, + compare_predicate_t compare) { + ordered_array_t toRet; + toRet.array = (type_t *)address; + custom_memset((uint8_t *)toRet.array, 0, maxSize * sizeof(type_t)); + toRet.size = 0; + toRet.maxSize = maxSize; + toRet.compare = compare; + return toRet; +} + +void destroy_ordered_array(ordered_array_t *array __attribute__((unused))) { + kfree(array->array); +} + +void insert_ordered_array(type_t item, ordered_array_t *array) { + if (!array->compare) { + print_screen( + "\nError: insert_ordered_array : No compare function provided\n"); + return; + } + + uint32_t iterator = 0; + while ((iterator < array->size) && + (array->compare(array->array[iterator], item))) { + iterator++; + } + + // If we don't find spot in between to insert, insert to the end + if (iterator == array->size) { + array->array[array->size++] = item; + } + // if We find spot insert and shift all the elements to right + else { + type_t tmp = array->array[iterator]; + array->array[iterator] = item; + while (iterator < array->size) { + iterator++; + type_t tmp2 = array->array[iterator]; + array->array[iterator] = tmp; + tmp = tmp2; + } + array->size++; + } +} + +type_t peek_ordered_array(uint32_t index, ordered_array_t *array) { + if (index >= array->size) { + print_screen("\nError: peek_ordered_array : Index out of bound\n"); + return 0; + } + return array->array[index]; +} + +void remove_ordered_array(uint32_t index, ordered_array_t *array) { + while (index < array->size) { + array->array[index] = array->array[index + 1]; + index++; + } + array->size--; +} diff --git a/SANDHU__OS/src/utils/array/ordered_array.h b/SANDHU__OS/src/utils/array/ordered_array.h new file mode 100644 index 0000000..1aa67e4 --- /dev/null +++ b/SANDHU__OS/src/utils/array/ordered_array.h @@ -0,0 +1,72 @@ +#ifndef ORDERED_ARRAY_H +#define ORDERED_ARRAY_H + +#pragma once +#include + +/* Define template to support multiple datatypes */ +typedef void *type_t; + +/* Function pointer for compare function, returns non zero if true else zero */ +typedef uint8_t (*compare_predicate_t)(type_t, type_t); + +typedef struct { + type_t *array; + uint32_t size; + uint32_t maxSize; + compare_predicate_t compare; +} ordered_array_t; + +/* create_ordered_array: + * Creates an ordered array. + * + * @param maxSize Maximum size of array + * @param compare Function pointer for compare (Array is sorted based on the + * compare function either in ascending or in descending order) + */ +ordered_array_t create_ordered_array(uint32_t maxSize, + compare_predicate_t compare); + +/* place_ordered_array: + * Place array at specified address. + * + * @param address Pointer to address at which we want the array to be placed + * (Assuming this memory is already allocated) + * @param maxSize Maximum size of array + * @param compare Function pointer for compare (Array is sorted based on the + * compare function either in ascending or in descending order) + */ +ordered_array_t place_ordered_array(void *addr, uint32_t max_size, + compare_predicate_t compare); + +/* destroy_ordered_array: + * Destructor for the ordered array. + * + * @param array Pointer to ordered array created earlier + */ +void destroy_ordered_array(ordered_array_t *array); + +/* insert_ordered_array: + * Add an item into the array. + * @param item Element to add casted to (void *) + * @param array Pointer to ordered array + */ +void insert_ordered_array(type_t item, ordered_array_t *array); + +/* peek_ordered_array: + * Get the item at index specified. + * + * @param index Index at which we want to peek + * @param array Pointer to ordered array + */ +type_t peek_ordered_array(uint32_t index, ordered_array_t *array); + +/* remove_ordered_array: + * Deletes the item at location from the array. + * + * @param index Index at which we want to lookup + * @param array Pointer to ordered array + */ +void remove_ordered_array(uint32_t index, ordered_array_t *array); + +#endif // ORDERED_ARRAY_H diff --git a/SANDHU__OS/src/utils/array/ordered_array.o b/SANDHU__OS/src/utils/array/ordered_array.o new file mode 100644 index 0000000..8aaf472 Binary files /dev/null and b/SANDHU__OS/src/utils/array/ordered_array.o differ diff --git a/SANDHU__OS/src/utils/bochsConfig/bochsrc.txt b/SANDHU__OS/src/utils/bochsConfig/bochsrc.txt new file mode 100644 index 0000000..2a95dc8 --- /dev/null +++ b/SANDHU__OS/src/utils/bochsConfig/bochsrc.txt @@ -0,0 +1,10 @@ +megs: 32 +display_library: sdl2 +romimage: file=/usr/share/bochs/BIOS-bochs-legacy +vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest +ata0-master: type=cdrom, path=os.iso, status=inserted +boot: cdrom +log: bochslog.txt +clock: sync=realtime, time0=local +cpu: count=1, ips=1000000 +com1: enabled=1, mode=file, dev=sandhu.out diff --git a/SANDHU__OS/src/utils/common/Makefile b/SANDHU__OS/src/utils/common/Makefile new file mode 100644 index 0000000..86281ca --- /dev/null +++ b/SANDHU__OS/src/utils/common/Makefile @@ -0,0 +1,19 @@ +all: libcommon.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +# Generate Static library +SC_FLAG = ar -cvq + +libcommon.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/utils/common/helpers.c b/SANDHU__OS/src/utils/common/helpers.c new file mode 100644 index 0000000..27c68db --- /dev/null +++ b/SANDHU__OS/src/utils/common/helpers.c @@ -0,0 +1,120 @@ +#include "helpers.h" +#include "multiboot.h" + +/* global variable to store pointer to multiboot info */ +uint32_t g_MULTIBOOT_PTR; + +int8_t g_BUFFER[LEN_10]; + +int8_t *integer_to_string(uint32_t number) { + uint32_t i = 0; + while (i < LEN_10) { + g_BUFFER[i] = '\0'; + i++; + } + + if (number == 0) { + g_BUFFER[0] = '0'; + return g_BUFFER; + } + + uint32_t temp_number = number; + int8_t buffer_rev[10] = ""; + i = 0; + while (temp_number > 0) { + buffer_rev[i] = '0' + (temp_number % 10); + temp_number /= 10; + i++; + } + + uint32_t j = 0; + while (i > 1) { + g_BUFFER[--i] = buffer_rev[j++]; + } + + g_BUFFER[--i] = buffer_rev[j]; + + return g_BUFFER; +} + +void get_multiboot_info(uint32_t mboot_ptr, uint32_t *initrdPhysicalStart, + uint32_t *multibootPhysicalEnd, uint32_t *modsCount) { + g_MULTIBOOT_PTR = mboot_ptr; + multiboot_info_t *mbinfo = (multiboot_info_t *)mboot_ptr; + multiboot_module_t *mod = (multiboot_module_t *)mbinfo->mods_addr; + + *initrdPhysicalStart = (uint32_t)((uint32_t *)mod->mod_start); + *multibootPhysicalEnd = + (uint32_t)((uint32_t *)mod[mbinfo->mods_count - 1].mod_end); + *modsCount = mbinfo->mods_count; +} + +uint32_t get_multiboot_address() { return g_MULTIBOOT_PTR; } + +uint32_t custom_strlen(const int8_t *str) { + uint32_t i; + for (i = 0; str[i]; i++) + ; + + return i; +} + +void custom_memset(uint8_t *address, uint32_t val, uint32_t size) { + for (uint32_t i = 0; i < size; ++i) { + *address = val; + ++address; + } +} + +void custom_memcpy(uint8_t *destination, const uint8_t *source, uint32_t size) { + uint8_t *pdest = (uint8_t *)destination; + uint8_t *psrc = (uint8_t *)source; + uint32_t loops = (size / sizeof(uint32_t)); + for (uint32_t index = 0; index < loops; ++index) { + *((uint32_t *)pdest) = *((uint32_t *)psrc); + pdest += sizeof(uint32_t); + psrc += sizeof(uint32_t); + } + loops = (size % sizeof(uint32_t)); + for (uint32_t index = 0; index < loops; ++index) { + *pdest = *psrc; + ++pdest; + ++psrc; + } +} + +void custom_strcpy(int8_t *destination, const int8_t *source) { + uint32_t i = 0; + for (i = 0; source[i] != '\0'; ++i) { + destination[i] = source[i]; + } + destination[i] = '\0'; +} + +uint8_t custom_strcmp(const int8_t *stringFirst, const int8_t *stringSecond, + uint8_t ignoreCase) { + uint32_t i = 0; + for (i = 0; stringFirst[i] && stringSecond[i]; ++i) { + if (ignoreCase) { + /* If characters are same or inverting the 6th bit (inverting case) makes + * them same + */ + if (stringFirst[i] == stringSecond[i] || + (stringFirst[i] ^ LEN_32) == stringSecond[i]) + continue; + else + break; + } else { + if (stringFirst[i] == stringSecond[i]) + continue; + else + break; + } + } + + /* Compare the last (or first mismatching in case of not same) characters */ + if (stringFirst[i] == stringSecond[i]) + return 0; + + return 1; +} diff --git a/SANDHU__OS/src/utils/common/helpers.h b/SANDHU__OS/src/utils/common/helpers.h new file mode 100644 index 0000000..dc8aa99 --- /dev/null +++ b/SANDHU__OS/src/utils/common/helpers.h @@ -0,0 +1,59 @@ +#ifndef INCLUDE_HELPERS_H +#define INCLUDE_HELPERS_H + +#pragma once +#include "types.h" + +/* Helper function to convert interger to string, used in logger */ +int8_t *integer_to_string(uint32_t number); + +/* Helper function to get physical end address of multiboot modules */ +void get_multiboot_info(uint32_t mboot_ptr, uint32_t *initrdPhysicalStart, + uint32_t *multibootPhysicalEnd, uint32_t *modsCount); + +/* Helper function to get address of multiboot strcut */ +uint32_t get_multiboot_address(); + +/* Helper function to calculate length of string, used in logger */ +uint32_t custom_strlen(const int8_t *str); + +/* Helper function for memset, used in paging and heap */ +void custom_memset(uint8_t *address, uint32_t val, uint32_t size); + +/** custom_memcpy: + * Helper function for memcpy, used in initrd. This is a very basic + * implementation and assumes we are not copying overlapping memories and + * unaligned memory copying is not optimized + * + * @param destination Destination address + * @param source Source address + * @param size Number of bytes to be copied + */ +void custom_memcpy(uint8_t *destination, const uint8_t *source, uint32_t size); + +/** custom_strcpy: + * Helper function for strcpy, used in initrd. This is a very basic + * implementation and appends '\0' in the end. Boundary conditions that are not + * handled are similiar to that of strcpy + * + * @param destination Destination address + * @param source Source address + * @param size Number of bytes to be copied + */ +void custom_strcpy(int8_t *destination, const int8_t *source); + +/** custom_strcmp: + * Helper function for strcmp, used in initrd. This is a very basic + * implementation just compares and return 0 is match 1 otherwise, parameter has + * additional flag ignore case because in the file system same filename with + * different case is not allowed. + * + * @param stringFirst Pointer to first string + * @param stringSecond Pointer to second string + * @param ignoreCase compare case-insensitively is set + * @return size 0 if match, 1 otherwise + */ +uint8_t custom_strcmp(const int8_t *stringFirst, const int8_t *stringSecond, + uint8_t ignoreCase); + +#endif /* INCLUDE_HELPERS_H */ diff --git a/SANDHU__OS/src/utils/common/helpers.o b/SANDHU__OS/src/utils/common/helpers.o new file mode 100644 index 0000000..84ddedd Binary files /dev/null and b/SANDHU__OS/src/utils/common/helpers.o differ diff --git a/SANDHU__OS/src/utils/common/multiboot.h b/SANDHU__OS/src/utils/common/multiboot.h new file mode 100644 index 0000000..713df19 --- /dev/null +++ b/SANDHU__OS/src/utils/common/multiboot.h @@ -0,0 +1,274 @@ +/* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 + +/* The magic field should contain this. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* Flags set in the 'flags' member of the multiboot header. */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* Flags to be set in the 'flags' member of the multiboot info structure. */ + +/* is there basic lower/upper memory information? */ +#define MULTIBOOT_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MULTIBOOT_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MULTIBOOT_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 + +/* is there a full memory map? */ +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MULTIBOOT_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* Feature flags. */ + multiboot_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info +{ + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_mod_list +{ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + + /* Module command line */ + multiboot_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + multiboot_uint32_t pad; +}; +typedef struct multiboot_mod_list multiboot_module_t; + +/* APM BIOS info. */ +struct multiboot_apm_info +{ + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ diff --git a/SANDHU__OS/src/utils/common/types.h b/SANDHU__OS/src/utils/common/types.h new file mode 100644 index 0000000..80054d6 --- /dev/null +++ b/SANDHU__OS/src/utils/common/types.h @@ -0,0 +1,54 @@ +#ifndef INCLUDE_TYPES_H +#define INCLUDE_TYPES_H + +/* Typedefs, to standardise sizes across platforms. + * These typedefs are written for 32-bit X86. + */ +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned char uint8_t; +typedef char int8_t; + +/* Frame buffer supported color value */ +#define FB_BLACK 0 +#define FB_BLUE 1 +#define FB_GREEN 2 +#define FB_CYAN 3 +#define FB_RED 4 +#define FB_MAGENTA 5 +#define FB_BROWN 6 +#define FB_LIGHT_GREY 7 +#define FB_DARK_GREY 8 +#define FB_LIGHT_BLUE 9 +#define FB_LIGHT_GREEN 10 +#define FB_LIGHT_CYAN 11 +#define FB_LIGHT_RED 12 +#define FB_LIGHT_MAGENTA 13 +#define FB_LIGHT_BROWN 14 +#define FB_WHITE 15 + +/* Keyboard driver constants */ +#define KEYBOARD_DATA_PORT 0x60 +#define PRESSED_CAPS_LOCK 58 +#define PRESSED_SHIFT_LEFT 42 +#define PRESSED_SHIFT_RIGHT 54 +#define RELEASED_SHIFT_LEFT 170 +#define RELEASED_SHIFT_RIGHT 182 + +/* Length constants */ +enum Size { + LEN_7 = 7, + LEN_10 = 10, + LEN_32 = 32, + LEN_64 = 64, + LEN_256 = 256, + LEN_512 = 512 +}; + +enum memSize { MEM_4KB = 0x1000, MEM_3_5GB = 0xE0000000 }; + +enum mask { MASK_BIT8 = 0x80 }; + +#endif /* INCLUDE_TYPES_H */ diff --git a/SANDHU__OS/src/utils/initrdGen/Makefile b/SANDHU__OS/src/utils/initrdGen/Makefile new file mode 100644 index 0000000..e3ec133 --- /dev/null +++ b/SANDHU__OS/src/utils/initrdGen/Makefile @@ -0,0 +1,25 @@ +.PHONY: all clean install + +all: initrdGen + +clean: $(SUBDIRS) rmOBJS + for subdir in $(SUBDIRS) ; do \ + make -C $$subdir clean ; \ + done + +install: + echo "Install not supported, please copy manually" + +rmOBJS: + rm -rf .DS_Store *.o *.so *.a *.out initrdGen initrd + +CC = gcc + +C_SOURCES += $(wildcard *.c) +C_OBJECTS += $(C_SOURCES:.c=.o) + +initrdGen : $(C_OBJECTS) + $(CC) $^ -o $@ + +%.o: %.c + $(CC) -c $< -o $@ diff --git a/SANDHU__OS/src/utils/initrdGen/README.md b/SANDHU__OS/src/utils/initrdGen/README.md new file mode 100644 index 0000000..afdc483 --- /dev/null +++ b/SANDHU__OS/src/utils/initrdGen/README.md @@ -0,0 +1,28 @@ +## To generate initrd image that can be loaded into kernel as module + +## Usage + + Files that needs to loaded as initrd should be passed as argument at odd +index and the desired/new filename within OS should be specified at even index. + +TODO: Support for directories and multi level files (files within directories) + +### To compile + +```shell + # -s for make quite + $ make -s +``` + +### To generate module + +```shell + $ ./initrdGen "i/p file name 1" "o/p file name 1" "i/p file name 2" \ + "o/p file name 2" .......... "i/p file name N" "o/p file name N" +``` + +### Example + +```shell + $ ./initrdGen file1.txt file1.txt file2.txt file2.txt +``` diff --git a/SANDHU__OS/src/utils/initrdGen/file1.txt b/SANDHU__OS/src/utils/initrdGen/file1.txt new file mode 100644 index 0000000..15d597a --- /dev/null +++ b/SANDHU__OS/src/utils/initrdGen/file1.txt @@ -0,0 +1 @@ +Hello, you just loaded first file from VFS! diff --git a/SANDHU__OS/src/utils/initrdGen/file2.txt b/SANDHU__OS/src/utils/initrdGen/file2.txt new file mode 100644 index 0000000..5a0e38c --- /dev/null +++ b/SANDHU__OS/src/utils/initrdGen/file2.txt @@ -0,0 +1 @@ +This is the second file! diff --git a/SANDHU__OS/src/utils/initrdGen/initrdGen.c b/SANDHU__OS/src/utils/initrdGen/initrdGen.c new file mode 100644 index 0000000..cab9852 --- /dev/null +++ b/SANDHU__OS/src/utils/initrdGen/initrdGen.c @@ -0,0 +1,56 @@ +#include +#include +#include + +struct initrd_header { + unsigned char magic; + char name[64]; + unsigned char type; + unsigned int offset; + unsigned int length; +}; + +int main(char argc, char **argv) { + int nheaders = (argc - 1) / 2; + struct initrd_header headers[64]; + printf("size of header: %zu\n", sizeof(struct initrd_header)); + unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int); + + int i; + for (i = 0; i < nheaders; i++) { + printf("writing file %s->%s at 0x%x\n", argv[i * 2 + 1], argv[i * 2 + 2], + off); + strcpy(headers[i].name, argv[i * 2 + 2]); + headers[i].offset = off; + headers[i].type = 1; + FILE *stream = fopen(argv[i * 2 + 1], "r"); + if (stream == 0) { + printf("Error: file not found: %s\n", argv[i * 2 + 1]); + return 1; + } + fseek(stream, 0, SEEK_END); + headers[i].length = ftell(stream); + off += headers[i].length; + fclose(stream); + headers[i].magic = 0xCA; + } + + FILE *wstream = fopen("./initrd", "w"); + unsigned char *data = (unsigned char *)malloc(off); + fwrite(&nheaders, sizeof(int), 1, wstream); + fwrite(headers, sizeof(struct initrd_header), 64, wstream); + + for (i = 0; i < nheaders; i++) { + FILE *stream = fopen(argv[i * 2 + 1], "r"); + unsigned char *buf = (unsigned char *)malloc(headers[i].length); + fread(buf, 1, headers[i].length, stream); + fwrite(buf, 1, headers[i].length, wstream); + fclose(stream); + free(buf); + } + + fclose(wstream); + free(data); + + return 0; +} diff --git a/SANDHU__OS/src/utils/logger/Makefile b/SANDHU__OS/src/utils/logger/Makefile new file mode 100644 index 0000000..62bae41 --- /dev/null +++ b/SANDHU__OS/src/utils/logger/Makefile @@ -0,0 +1,29 @@ +all: liblogger.a + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.include + +C_SOURCES += $(TOP_DIR)/src/drivers/frame_buffer/frame_buffer.c \ + $(TOP_DIR)/src/drivers/serial_port/serial_port.c + +# Include Common Makefile +-include ${MAKE_UTILS_DIR}/Makefile.defs + +INCLUDE += \ + -I$(TOP_DIR)/src/drivers/frame_buffer \ + -I$(TOP_DIR)/src/drivers/io \ + -I$(TOP_DIR)/src/drivers/serial_port \ + -I$(TOP_DIR)/src/drivers/timer \ + -I$(TOP_DIR)/src/utils/common + +# Generate Static library +SC_FLAG = ar -cvq + +liblogger.a: $(C_OBJECTS) $(S_OBJECTS) + $(SC_FLAG) $(LIB_DIR)/$@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ diff --git a/SANDHU__OS/src/utils/logger/logger.c b/SANDHU__OS/src/utils/logger/logger.c new file mode 100644 index 0000000..56606e8 --- /dev/null +++ b/SANDHU__OS/src/utils/logger/logger.c @@ -0,0 +1,63 @@ +#include "logger.h" +#include +#include +#include +#include + +char message[] = "\ + \ + /$$ /$$ /$$ /$$ /$$ /$$ \ +| $$$ /$$$|__/ |__/ | $$ |__/ \ +| $$$$ /$$$$ /$$ /$$$$$$$ /$$ | $$ /$$ /$$$$$$$ /$$ /$$ /$$ /$$\ +| $$ $$/$$ $$| $$| $$__ $$| $$ | $$ | $$| $$__ $$| $$ | $$| $$ /$$/\ +| $$ $$$| $$| $$| $$ | $$| $$ | $$ | $$| $$ \\ $$| $$ | $$ \\ $$$$/ \ +| $$\\ $ | $$| $$| $$ | $$| $$ | $$ | $$| $$ | $$| $$ | $$ >$$ $$ \ +| $$ \\/ | $$| $$| $$ | $$| $$ | $$$$$$$$| $$| $$ | $$| $$$$$$/ /$$/\\ $$\ +|__/ |__/|__/|__/ |__/|__/ |________/|__/|__/ |__/ \\______/ |__/ \\__/\ + \ + \ +"; + + +char message2[] = "\ + \ + oooooooo8 oooo oooo \ + 888 ooooooo oo oooooo ooooo888 888ooooo oooo oooo \ + 888oooooo ooooo888 888 888 888 888 888 888 888 888 \ + 888 888 888 888 888 888 888 888 888 888 888 \ + o88oooo888 88ooo88 8o o888o o888o 88ooo888o o888o o888o 888o88 8o \ + \ + oooooooo8 oooo o88 o888 \ + 888 ooooooo 888ooooo oooo 888 \ + 888oooooo ooooo888 888 888 888 888 \ + 888 888 888 888 888 888 888 \ + o88oooo888 88ooo88 8o o888o o888o o888o o888o \ + \ + \ +"; + +void print_screen(int8_t buffer[]) { fb_write(buffer, custom_strlen(buffer)); } + +void print_serial(int8_t buffer[]) { + serial_write(SERIAL_COM1_BASE, buffer, custom_strlen(buffer)); +} + +void print_screen_ch(int8_t ch) { fb_write(&ch, 1); } + +void print_serial_ch(int8_t ch) { serial_write(SERIAL_COM1_BASE, &ch, 1); } + +void clear_screen() { fb_clear_all(); } + +/** init_display: + * Reset screen and display splash screen + */ +void init_display() { + fb_clear_all(); + fb_set_color(FB_BLACK, FB_WHITE); + fb_write(message, 881); + fb_set_color(FB_BLACK, FB_LIGHT_GREEN); + fb_write(message2, 1121); + /* Sleep for 5 seconds (500 centiSeconds) */ + sleep(500); + fb_set_color(FB_BLACK, FB_WHITE); +} diff --git a/SANDHU__OS/src/utils/logger/logger.h b/SANDHU__OS/src/utils/logger/logger.h new file mode 100644 index 0000000..72be714 --- /dev/null +++ b/SANDHU__OS/src/utils/logger/logger.h @@ -0,0 +1,45 @@ +#ifndef INCLUDE_LOGGER_H +#define INCLUDE_LOGGER_H + +#pragma once +#include + +/** print_serial: + * writes the char array buffer of length len to serial console + * + * @param buffer Buffer that has contents to be written to serial port + */ +void print_serial(int8_t buffer[]); + +/** print_serial: + * writes the char to serial console + * + * @param ch Buffer that has contents to be written to serial port + */ +void print_serial_ch(int8_t ch); + +/** print_screen: + * writes the char buffer buf of length len to Screen + * + * @param buffer Buffer that has contents to be written to Screen + */ +void print_screen(int8_t buffer[]); + +/** print_screen: + * writes the char to Screen + * + * @param ch Buffer that has contents to be written to Screen + */ +void print_screen_ch(int8_t ch); + +/** clear_screen: + * Clears the contents on screen + */ +void clear_screen(); + +/** init_display: + * Initializes the frame buffer + */ +void init_display(); + +#endif /* INCLUDE_LOGGER_H */ diff --git a/SANDHU__OS/src/utils/logger/logger.o b/SANDHU__OS/src/utils/logger/logger.o new file mode 100644 index 0000000..c131625 Binary files /dev/null and b/SANDHU__OS/src/utils/logger/logger.o differ diff --git a/SANDHU__OS/travisRun.sh b/SANDHU__OS/travisRun.sh new file mode 100755 index 0000000..a3dd661 --- /dev/null +++ b/SANDHU__OS/travisRun.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +if [ "$#" -eq 1 ]; then + if [ $1 = "-d" ]; then + debug="-S"; + echo "Running in debug mode" + else + echo " './run.sh -d' to run in debug mode" + exit 1 + fi +fi + +cp build/bin/kernel.elf iso/boot/kernel.elf + +genisoimage -R \ +-b boot/grub/stage2_eltorito \ +-no-emul-boot \ +-boot-load-size 4 \ +-A os \ +-input-charset utf8 \ +-quiet \ +-boot-info-table \ +-o sandhu.iso \ +iso + +unset GTK_PATH # This is needed to run qemu on my system + +qemu-system-i386 -nographic -cdrom sandhu.iso -m 4G -s -serial mon:stdio $debug > qemu.log 2>&1 &