├── .gitignore ├── Makefile ├── README.md ├── core ├── hal │ ├── Makefile │ ├── include │ │ ├── cpu.h │ │ ├── gdt.h │ │ ├── idt.h │ │ └── reg.h │ ├── libhal.a │ └── source │ │ ├── cpu.c │ │ ├── gdt.c │ │ ├── hal.c │ │ └── idt.c ├── include │ ├── ctype │ ├── ctype.h │ ├── hal.h │ ├── null.h │ ├── size.h │ ├── stdarg │ ├── stdarg.h │ ├── stdint │ ├── stdint.h │ ├── stdio.h │ ├── string.h │ └── va_list.h ├── kernel │ ├── Makefile │ ├── include │ │ └── console.h │ ├── linker.ld │ ├── loader.s │ └── source │ │ ├── console.c │ │ └── kernel.c └── lib │ ├── Makefile │ ├── libhal.a │ ├── libstd.a │ └── source │ ├── stdio.c │ └── string.c ├── grub └── stage2_eltorito ├── initialise.sh └── screenshots └── home.png /.gitignore: -------------------------------------------------------------------------------- 1 | bochs/ 2 | compiler/ 3 | core/hal/obj 4 | core/kernel/bin 5 | core/kernel/obj 6 | core/lib/obj 7 | experiment/ 8 | iso/ 9 | theory/ 10 | *.iso 11 | *.depend 12 | core/lib/*.a 13 | core/lib/*.so -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Usefull directories 2 | LIB_DIR = ./core/lib 3 | KER_DIR = ./core/kernel 4 | HAL_DIR = ./core/hal 5 | 6 | 7 | # Output files 8 | KNAME = kernel.bin 9 | KERNEL = $(KER_DIR)/bin/$(KNAME) 10 | ISO = os32.iso 11 | 12 | 13 | # Tools for building 14 | CCOM = compiler/bin/i686-elf-gcc 15 | CPPCOM = compiler/bin/i686-elf-g++ 16 | AS = compiler/bin/i686-elf-as 17 | 18 | 19 | # Flags for building tools 20 | CFLAG = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -L$(LIB_DIR) 21 | CPPFLAG = -c -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti -L$(LIB_DIR) 22 | 23 | 24 | # Libraries used 25 | LIB = -lhal -lstd 26 | 27 | 28 | # Object files 29 | _OBJ = console.o kernel.o loader.o 30 | OBJ = $(_OBJ:%.o=$(KER_DIR)/obj/debug/%.o) 31 | 32 | 33 | # Linker file 34 | LD_FILE = ./core/kernel/linker.ld 35 | 36 | 37 | # Bochs emulator 38 | BOCHS = bochs 39 | BCONFIG = bochsconfig.txt 40 | 41 | 42 | #-------------------------------------------------------------------------- 43 | # Linking all object to kernel 44 | $(KERNEL): $(OBJ) $(LIB_DIR)/libhal.a $(LIB_DIR)/libstd.a 45 | $(CCOM) -T $(LD_FILE) -o $(KERNEL) -ffreestanding -O2 -nostdlib $(OBJ) -lgcc -L$(LIB_DIR) $(LIB) 46 | 47 | $(LIB_DIR)/libhal.a: $(HAL_DIR)/libhal.a 48 | cp $(HAL_DIR)/libhal.a $(LIB_DIR)/libhal.a 49 | 50 | #-------------------------------------------------------------------------- 51 | 52 | all: hal stdlib kernel $(KERNEL) 53 | 54 | #-------------------------------------------------------------------------- 55 | # Building all modules 56 | 57 | # Building kernel 58 | kernel: 59 | cd $(KER_DIR); make depend; make; 60 | 61 | 62 | # Building HAL 63 | hal: 64 | cd $(HAL_DIR); make depend; make; 65 | 66 | 67 | # Building stdlib 68 | stdlib: 69 | cd $(LIB_DIR); make depend; make; 70 | 71 | # Setup directory and dependencies file for first run 72 | configure: 73 | chmod +x initialise.sh 74 | ./initialise.sh 75 | #------------------------------------------------------------------------- 76 | 77 | 78 | # Generating iso image of OS 79 | iso: $(ISO) 80 | 81 | 82 | $(ISO): $(KERNEL) 83 | cp $(KERNEL) iso/boot/$(KNAME) 84 | genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot -input-charset utf8 -boot-load-size 4 -boot-info-table -o $(ISO) iso 85 | 86 | 87 | # Running OS in bochs emulator 88 | run: $(ISO) 89 | bochs -f $(BOCHS)/$(BCONFIG) -q 90 | 91 | # Delete all object files in Binary folder 92 | clean: 93 | rm $(KERNEL) $(ISO) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Basic Hybrid Kernel 2 | > Hybrid Kernel with minimal features like interrupt handling, command line interface 3 | 4 | GNU GRUB(GRand Unified Bootloader) legacy is used as bootloader 5 | 6 | ## Requirement 7 | * `gcc` cross Compiler [get prebuild binaries here](http://wiki.osdev.org/GCC_Cross-Compiler). 8 | 9 | * bochs x86 Emulator for running kernel in virtual environment. 10 | ``` 11 | [sudo] apt-get install bochs 12 | [sudo] apt-get install bochs-sdl (for GUI support) 13 | ``` 14 | * `genisoimage` to generate ISO image of kernel. 15 | ``` 16 | [sudo] apt-get install genisoimage 17 | ``` 18 | * `makedepend` for generating dependencies 19 | ``` 20 | [sudo] apt-get install xutils-dev 21 | ``` 22 | 23 | ## Installation 24 | * Clone the repository 25 | ``` 26 | git clone https://github.com/Kapilks/Basic-Kernel.git 27 | ``` 28 | * Setup the directory 29 | ``` 30 | [sudo] make configure 31 | ``` 32 | * Build `hal` (Hardware Abstraction Layer) library, `stdlib` for C and kernel binaries
33 | (Can be done separately) 34 | ``` 35 | [sudo] make all 36 | ``` 37 | * Generate the bootable iso image of kernel 38 | ``` 39 | [sudo] make iso 40 | ``` 41 | * Run kernel in `bochs` 42 | ``` 43 | [sudo] make run 44 | ``` 45 | 46 | ## Directory Structure of ISO image 47 | - iso 48 | - boot 49 | - grub 50 | - menu.lst 51 | - stage2_eltorito 52 | - kernel.bin 53 | 54 | ## Screenshot 55 | ![Welcome Screen](screenshots/home.png) 56 | -------------------------------------------------------------------------------- /core/hal/Makefile: -------------------------------------------------------------------------------- 1 | # Output librabry file 2 | LIB_ARCH = libhal.a 3 | 4 | 5 | # Usefull directories 6 | INC_DIR = ../include 7 | INC_HAL_DIR = ./include 8 | SRC_DIR = ./source 9 | D_OBJ_DIR = ./obj/debug 10 | R_OBJ_DIR = ./obj/release 11 | 12 | 13 | # Tools for building 14 | CCOM = ../../compiler/bin/i686-elf-gcc 15 | CPPCOM = ../../compiler/bin/i686-elf-g++ 16 | ASM = ../../compiler/bin/i686-elf-as 17 | ARCH = ../../compiler/bin/i686-elf-ar 18 | MAKEDEPEND = makedepend 19 | 20 | 21 | # Flags for building tools 22 | CFLAG = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -I$(INC_DIR) -I$(INC_HAL_DIR) 23 | CPPFLAG = -c -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti -I$(INC_DIR) -I$(INC_HAL_DIR) 24 | ARFLAG = -vrcs 25 | 26 | 27 | _SOURCE = hal.c gdt.c idt.c cpu.c 28 | 29 | # Contain path to source files 30 | SRC_FILE = $(_SOURCE:%.c=$(SRC_DIR)/%.c) 31 | 32 | # Output debug object file 33 | D_OBJ = $(_SOURCE:%.c=$(D_OBJ_DIR)/%.o) 34 | 35 | # Output release object file 36 | R_OBJ = $(_SOURCE:%.c=$(R_OBJ_DIR)/%.o) 37 | 38 | # Output dependency file 39 | DEP = .depend 40 | 41 | #------------------------------------------------------------------------- 42 | 43 | lib: $(LIB_ARCH) 44 | 45 | $(LIB_ARCH): $(D_OBJ) 46 | $(ARCH) $(ARFLAG) $(LIB_ARCH) $(D_OBJ) 47 | 48 | $(D_OBJ_DIR)/%.o: $(SRC_DIR)/%.c 49 | $(CCOM) $< -o $@ $(CFLAG) 50 | 51 | 52 | # Include dependency files for object files 53 | include $(DEP) 54 | 55 | # Clean object files 56 | clean: 57 | rm $(D_OBJ_DIR)/* 58 | rm $(LIB_ARCH) 59 | 60 | # Generate dependency for course and output to DEP file 61 | depend: 62 | $(MAKEDEPEND) -v -f$(DEP) -Y$(INC_DIR) -I$(INC_HAL_DIR) $(SRC_FILE) 63 | rm $(DEP).bak -------------------------------------------------------------------------------- /core/hal/include/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef CPU_H 2 | #define CPU_H 3 | 4 | 5 | //************************ 6 | // Processor interface for managing processors, 7 | // processor cores, data structure 8 | // File: cpu.h 9 | //************************ 10 | // 11 | 12 | 13 | #ifndef ARCH_x86 14 | #error "[cpu.h] platform not implimented. Define ARCH_X86 for HAL" 15 | #endif /* ARCH_x86 */ 16 | 17 | 18 | #include 19 | #include 20 | 21 | 22 | /* Setup the processor idt, gdt */ 23 | int32 initializeProcessor(); 24 | 25 | /* Shutdown processor */ 26 | void shutdownProcessor(); 27 | 28 | 29 | #endif /* CPU_H */ -------------------------------------------------------------------------------- /core/hal/include/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef GDT_H 2 | #define GDT_H 3 | 4 | 5 | //************************ 6 | /* GDT: Global Descripter Table */ 7 | // 8 | // Contain function to setup Global Descriptor Table(GDT) 9 | // This handles memory map for system and permission level 10 | // File: gdt.h 11 | //************************ 12 | 13 | 14 | #ifndef ARCH_x86 15 | #error "[gdt.h] platform not implimented. Define ARCH_X86 for HAL" 16 | #endif /* ARCH_x86 */ 17 | 18 | 19 | #include 20 | 21 | 22 | // Maximum number of descriptor allowed 23 | #define I86_MAX_GDT_DESCRIPTOR 3 24 | 25 | 26 | 27 | /* GDTDescripter bit flags */ 28 | 29 | /* Access bit */ 30 | // Set this to 0 31 | // CPU set it 1 when segment is accessed 32 | #define I86_GDT_DESC_ACCESS 0x0001 //0000000000000001 33 | 34 | /* Readable/Writable bit */ 35 | // Readable bit for Code selector 36 | // Writable bit for Data selector 37 | #define I86_GDT_DESC_READWRITE 0x0002 //0000000000000010 38 | 39 | /* Direction/Conforming bit */ 40 | // Direction bit for Data selector 41 | // Conforming bit for Code selector 42 | #define I86_GDT_DESC_EXPANSION 0x0004 //0000000000000100 43 | 44 | /* Executable bit */ 45 | // Code/Data Segement 46 | // Default Data Segment(0) 47 | #define I86_GDT_DESC_EXEC_CODE 0x0008 //0000000000001000 48 | 49 | /* Descripter bit */ 50 | // System/Code-Data Descripter 51 | // Default System Descripter 52 | #define I86_GDT_DESC_CODEDATA 0x0010 //0000000000010000 53 | 54 | /* DPL(Descripter Priviledge Level) bits */ 55 | #define I86_GDT_DESC_DPL 0x0060 //0000000001100000 56 | 57 | /* In memory bit (Virtual Memory) */ 58 | #define I86_GDT_DESC_MEMORY 0x0080 //0000000010000000 59 | 60 | /* Masks out limitHigh (High 4 bits of limit) */ 61 | #define I86_GDT_DESC_LIMITHI_MASK 0x0f00 //0000111100000000 62 | 63 | /* OS Reserve bit (Next reserve bit always 0)*/ 64 | #define I86_GDT_DESC_RESERVE_OS 0x1000 //0001000000000000 65 | 66 | /* Segment type 32bit/16bit */ 67 | // Default 16bit(0) 68 | #define I86_GDT_DESC_SEG_TYPE 0x4000 //0100000000000000 69 | 70 | /* 4KB Page size */ 71 | // Default 1byte 72 | #define I86_GDT_DESC_PAGE_4KB 0x8000 //1000000000000000 73 | 74 | 75 | /* Descripter for GDT */ 76 | // GDT is array of GDTDescripter 77 | // limit - 20 bits 78 | // base - 32 bits 79 | struct GDTDescriptor 80 | { 81 | uint16 limit; // 0-15 bits of Segment limit 82 | uint16 baseLow; // 0-15 bits of Segment base address 83 | uint8 baseMid; // 16-23 bits of Segment base address 84 | uint16 flags; // Bit mask for different bit flags 85 | uint8 baseHigh; // 24-31 bits of Segment base address 86 | }__attribute__((__packed__)); 87 | 88 | 89 | /* Public Function */ 90 | 91 | /* Put the given formed descripter at position index from the parameter passed */ 92 | void gdtPutDescriptor(uint32 index, uint32 base, uint32 limit /* 20 bits only */, uint16 flags); 93 | 94 | /* Return pointer to the descripter */ 95 | struct GDTDescriptor* gdtGetDesciptor(uint32 index); 96 | 97 | /* Setup GDT */ 98 | int32 initializeGdt(); 99 | 100 | 101 | #endif /* GDT_H */ -------------------------------------------------------------------------------- /core/hal/include/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef IDT_H 2 | #define IDT_H 3 | 4 | 5 | //************************ 6 | /* IDT: Interrupt Descripter Table */ 7 | // 8 | // IDT is responsible for managing interrupt related functionality 9 | // File: idt.h 10 | //************************ 11 | 12 | 13 | #ifndef ARCH_x86 14 | #error "[idt.h] platform not implimented. Define ARCH_X86 for HAL" 15 | #endif /* ARCH_x86 */ 16 | 17 | 18 | #include 19 | 20 | 21 | /* I86 Has 256 interrupts (0-255) */ 22 | #define I86_MAX_INTERRUPTS 256 23 | 24 | /* Descripter flags bits */ 25 | 26 | /* Type of interrupt gate 32bit/16bit */ 27 | #define I86_IDT_DESC_BIT16 0x06 // 00000110 28 | #define I86_IDT_DESC_BIT32 0x0E // 00001110 29 | 30 | /* Priviledge level */ 31 | #define I86_IDT_DESC_RING1 0x40 // 01000000 32 | #define I86_IDT_DESC_RING2 0x20 // 00100000 33 | #define I86_IDT_DESC_RING3 0x60 // 01100000 34 | 35 | /* Present bit (Virtual Memory) */ 36 | #define I86_IDT_DESC_PRESENT 0x80 // 10000000 37 | 38 | 39 | /* Descripter for IDT */ 40 | // IDT is array of GDTDescripter 41 | // selector - 16 bits 42 | // base - 32 bits 43 | struct IDTDescripter 44 | { 45 | uint16 baseLow; // 0-15 bits of Interrupt Routine address 46 | uint16 selector; // Code selector in GDT (index of GDT array) 47 | uint8 reserve; // Reserved (0) 48 | uint8 flags; // Bit mask for flags 49 | uint16 baseHigh; // 16-32 bits of Interrupt Routine address 50 | }__attribute__((__packed__)); 51 | 52 | 53 | /* Interrupt handler function type */ 54 | typedef void (*InterruptHandler)(void); 55 | 56 | 57 | /* Public function */ 58 | 59 | /* Return pointer to the IDTDescripter indexed by given index */ 60 | struct IDTDescripter* idtGetDescripter(uint32 index); 61 | 62 | /* Register own interrupt handler for specific interrupts */ 63 | // If not registered default handler will be called 64 | int32 putInterruptHandler(uint32 index, uint16 flags, uint16 selector, InterruptHandler handler); 65 | 66 | /* Setup IDT */ 67 | // called from cpu initialization function 68 | int32 initializeIdt(uint16 selector); 69 | 70 | 71 | #endif /* IDT_H */ -------------------------------------------------------------------------------- /core/hal/include/reg.h: -------------------------------------------------------------------------------- 1 | #ifndef REG_H 2 | #define REG_H 3 | 4 | 5 | #ifndef ARCH_x86 6 | #error "[reg.h] platform not implimented. Define ARCH_X86 for HAL" 7 | #endif /* ARCH_x86 */ 8 | 9 | 10 | #include 11 | 12 | 13 | // 32 bit Registers 14 | struct R32Bit 15 | { 16 | uint32 eax; 17 | uint32 ebx; 18 | uint32 ecx; 19 | uint32 edx; 20 | uint32 esi; 21 | uint32 edi; 22 | uint32 ebp; 23 | uint32 esp; 24 | uint32 eflags; 25 | uint8 cflags; 26 | }; 27 | 28 | 29 | // 16 bit Registers 30 | struct R16Bit 31 | { 32 | uint16 ax; 33 | uint16 bx; 34 | uint16 cx; 35 | uint16 dx; 36 | uint16 si; 37 | uint16 di; 38 | uint16 bp; 39 | uint16 sp; 40 | uint16 es; 41 | uint16 cs; 42 | uint16 ss; 43 | uint16 ds; 44 | uint16 flags; 45 | uint8 cflags; 46 | }; 47 | 48 | 49 | // 16 bit Registers expressed as 32 bit Registers 50 | struct R16Bit32 51 | { 52 | uint16 ax; 53 | uint16 axh; 54 | uint16 bx; 55 | uint16 bxh; 56 | uint16 cx; 57 | uint16 cxh; 58 | uint16 dx; 59 | uint16 dxh; 60 | 61 | uint16 si; 62 | uint16 di; 63 | uint16 bp; 64 | uint16 sp; 65 | uint16 es; 66 | uint16 cs; 67 | uint16 ss; 68 | uint16 ds; 69 | uint16 flags; 70 | uint8 cflags; 71 | }; 72 | 73 | 74 | // 8 bit Registers 75 | struct R8Bit 76 | { 77 | uint8 al; 78 | uint8 ah; 79 | uint8 bl; 80 | uint8 bh; 81 | uint8 cl; 82 | uint8 ch; 83 | uint8 dl; 84 | uint8 dh; 85 | }; 86 | 87 | 88 | // 8 bit Registers expressed as 32 bit Registers 89 | struct R8Bit32 90 | { 91 | uint8 al, ah; 92 | uint16 axh; 93 | uint8 bl, bh; 94 | uint16 bxh; 95 | uint8 cl, ch; 96 | uint16 cxh; 97 | uint8 dl, dh; 98 | uint16 dxh; 99 | }; 100 | 101 | 102 | union IntR16 103 | { 104 | struct R16Bit x; 105 | struct R8Bit h; 106 | }; 107 | 108 | union IntR32 109 | { 110 | struct R32Bit x; 111 | struct R16Bit32 l; 112 | struct R8Bit32 h; 113 | }; 114 | #endif /* REG_H */ -------------------------------------------------------------------------------- /core/hal/libhal.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kapilks/Basic-Kernel/e672cfcaa81df053856f7ace7399bb8ce21a3eba/core/hal/libhal.a -------------------------------------------------------------------------------- /core/hal/source/cpu.c: -------------------------------------------------------------------------------- 1 | #define ARCH_x86 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | int32 initializeProcessor() 10 | { 11 | initializeGdt(); 12 | initializeIdt(0x8); // selector of gdt 1 index (code selector) 13 | 14 | return 0; 15 | } 16 | 17 | 18 | void shutdownProcessor() 19 | { 20 | 21 | } -------------------------------------------------------------------------------- /core/hal/source/gdt.c: -------------------------------------------------------------------------------- 1 | #define ARCH_x86 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | /* Extracting bit (All 1) */ 9 | #define LEAST_32_BITS 0xffffffff 10 | #define LEAST_16_BITS 0xffff 11 | #define LEAST_8_BITS 0xff 12 | 13 | /* Content of GDTR register */ 14 | struct GDTR 15 | { 16 | uint16 limit; // Size of GDT - 1 bytes 17 | uint32 base; // Linear address of first entry of GDT 18 | }__attribute__((__packed__)); 19 | 20 | 21 | 22 | //==================================================================================== 23 | 24 | 25 | /* Private */ 26 | 27 | // Global Destriptor Table as array of descriptor entries 28 | static struct GDTDescriptor gdt[I86_MAX_GDT_DESCRIPTOR]; 29 | 30 | // GDT Register value 31 | static struct GDTR gdtr; 32 | 33 | 34 | /* Load GDTR register */ 35 | static void loadGdt() 36 | { 37 | asm 38 | ( 39 | "lgdt %0" 40 | : 41 | : [input] "g" (gdtr) 42 | : 43 | ); 44 | } 45 | 46 | 47 | 48 | //===================================================================================== 49 | 50 | 51 | 52 | void gdtPutDescriptor(uint32 index, uint32 base, uint32 limit, uint16 flags) 53 | { 54 | if(index >= I86_MAX_GDT_DESCRIPTOR) 55 | { 56 | return; 57 | } 58 | 59 | memset((void*)&gdt[index], 0, sizeof(struct GDTDescriptor)); 60 | 61 | // Set limit and base address 62 | gdt[index].baseLow = (uint16)(base & LEAST_16_BITS); 63 | gdt[index].baseMid = (uint8)((base >> 16) & LEAST_8_BITS); 64 | gdt[index].baseHigh = (uint8)((base >> 24) & LEAST_8_BITS); 65 | gdt[index].limit = (uint16)(limit & LEAST_16_BITS); 66 | 67 | // Add limit first 4 bits to flag starting at 5th bit 68 | flags |= (uint16)((limit >> 16) << 8); 69 | 70 | // Set flag 71 | gdt[index].flags = flags; 72 | } 73 | 74 | 75 | struct GDTDescriptor* gdtGetDesciptor(uint32 index) 76 | { 77 | if(index >= I86_MAX_GDT_DESCRIPTOR) 78 | { 79 | return NULL; 80 | } 81 | 82 | return &gdt[index]; 83 | } 84 | 85 | 86 | int32 initializeGdt() 87 | { 88 | // Set up gdtr 89 | gdtr.limit = sizeof(struct GDTDescriptor) * I86_MAX_GDT_DESCRIPTOR - 1; 90 | gdtr.base = (uint32)(&gdt[0]); 91 | 92 | // Set null descriptor 93 | gdtPutDescriptor(0, 0, 0, 0); 94 | 95 | // Set default code descriptor 96 | gdtPutDescriptor(1, 0, LEAST_32_BITS, 97 | I86_GDT_DESC_READWRITE | 98 | I86_GDT_DESC_EXEC_CODE | 99 | I86_GDT_DESC_CODEDATA | 100 | I86_GDT_DESC_MEMORY | 101 | I86_GDT_DESC_PAGE_4KB | 102 | I86_GDT_DESC_SEG_TYPE | 103 | I86_GDT_DESC_LIMITHI_MASK); 104 | 105 | // Set default data descriptor 106 | gdtPutDescriptor(2, 0, LEAST_32_BITS, 107 | I86_GDT_DESC_READWRITE | 108 | I86_GDT_DESC_CODEDATA | 109 | I86_GDT_DESC_MEMORY | 110 | I86_GDT_DESC_PAGE_4KB | 111 | I86_GDT_DESC_SEG_TYPE | 112 | I86_GDT_DESC_LIMITHI_MASK); 113 | 114 | loadGdt(); 115 | 116 | return 0; 117 | } -------------------------------------------------------------------------------- /core/hal/source/hal.c: -------------------------------------------------------------------------------- 1 | #define ARCH_x86 2 | 3 | #ifndef ARCH_x86 4 | #error "[hal.c] platform not implimented. Define ARCH_X86 for HAL" 5 | #endif /* ARCH_x86 */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | void zero_int() 15 | { 16 | //__asm__("pushad"); 17 | 18 | perror("Error: divide by zero\n"); 19 | 20 | //__asm__("popad; leave; iret;"); 21 | } 22 | 23 | int initializeHal() 24 | { 25 | initializeProcessor(); 26 | 27 | putInterruptHandler(0, I86_IDT_DESC_PRESENT | I86_IDT_DESC_BIT32, 0x8, (InterruptHandler)zero_int); 28 | return 0; 29 | } 30 | 31 | 32 | int shutdownHal() 33 | { 34 | shutdownProcessor(); 35 | return 0; 36 | } 37 | 38 | 39 | void genInterrupt(uint32 interrupt) 40 | { 41 | uint16 opcode = 0; 42 | asm 43 | ( 44 | "movb %0, %%al\n\t" 45 | "movb %%al, genInt + 1\n\t" 46 | "jmp genInt\n\t" 47 | "genInt:\n\t" 48 | "int $0\n\t" 49 | : 50 | : [input] "g" (interrupt) 51 | : "%al" 52 | ); 53 | } -------------------------------------------------------------------------------- /core/hal/source/idt.c: -------------------------------------------------------------------------------- 1 | #define ARCH_x86 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* Content of IDTR register */ 11 | struct IDTR 12 | { 13 | uint16 limit; 14 | uint32 base; 15 | }__attribute__((__packed__)); 16 | 17 | 18 | //==================================================================================== 19 | 20 | 21 | 22 | /* Private */ 23 | 24 | /* Interrupt Descripter Table as array of IDTDescripter */ 25 | static struct IDTDescripter idt[I86_MAX_INTERRUPTS]; 26 | 27 | /* IDT Register value */ 28 | static struct IDTR idtr; 29 | 30 | 31 | /* Load IDTR register */ 32 | static void loadIdtr() 33 | { 34 | asm 35 | ( 36 | "lidt %0" 37 | : 38 | : [input] "g" (idtr) 39 | : 40 | ); 41 | } 42 | 43 | 44 | /* Default interrupt handler */ 45 | // This handler is used for interrupts whose handler is 46 | // not defined 47 | static void defaultInterruptHandler() 48 | { 49 | perror("I86 Default interrupt handler\n"); 50 | 51 | for(;;); 52 | } 53 | 54 | 55 | 56 | //==================================================================================== 57 | 58 | 59 | 60 | struct IDTDescripter* idtGetDescripter(uint32 index) 61 | { 62 | if(index >= I86_MAX_INTERRUPTS) 63 | { 64 | return NULL; 65 | } 66 | 67 | return &idt[index]; 68 | } 69 | 70 | 71 | int32 putInterruptHandler(uint32 index, uint16 flags, uint16 selector, InterruptHandler handler) 72 | { 73 | if(index >= I86_MAX_INTERRUPTS) 74 | { 75 | return 0; 76 | } 77 | 78 | if(!handler) 79 | { 80 | return 0; 81 | } 82 | 83 | uint32 ibase = (uint32)(&(*handler)); 84 | 85 | idt[index].baseLow = (uint16)(ibase & 0xffff); 86 | idt[index].baseHigh = (uint16)((ibase >> 16) & 0xffff); 87 | idt[index].reserve = 0; 88 | idt[index].flags = (uint8)(flags); 89 | idt[index].selector = selector; 90 | 91 | return 0; 92 | } 93 | 94 | 95 | int32 initializeIdt(uint16 selector) 96 | { 97 | // Setup idtr 98 | idtr.limit = sizeof(struct IDTDescripter) * I86_MAX_INTERRUPTS -1; 99 | idtr.base = (uint32)&idt[0]; 100 | 101 | // Null idtdescripter 102 | memset((void*)&idt[0], 0, sizeof(struct IDTDescripter) * I86_MAX_INTERRUPTS - 1); 103 | 104 | // Register default handler 105 | for(int i = 0; i < I86_MAX_INTERRUPTS; ++i) 106 | { 107 | putInterruptHandler(i, I86_IDT_DESC_PRESENT | I86_IDT_DESC_BIT32, selector, (InterruptHandler)defaultInterruptHandler); 108 | } 109 | 110 | loadIdtr(); 111 | 112 | return 0; 113 | } -------------------------------------------------------------------------------- /core/include/ctype: -------------------------------------------------------------------------------- 1 | #ifndef CTYPE_CPP_H 2 | #define CTYPE_CPP_H 3 | 4 | /* Will be used in C++ include */ 5 | #include 6 | 7 | 8 | #endif /* CTYPE_CPP_H */ -------------------------------------------------------------------------------- /core/include/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef CTYPE_H 2 | #define CTYPE_H 3 | 4 | 5 | //************************ 6 | // Header for determining type and their details 7 | // of the character of string 8 | // File: ctype.h 9 | //************************ 10 | 11 | 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | 17 | extern char _ctype[]; 18 | 19 | /* Character type Constants */ 20 | 21 | #define CTYPE_UP 0x01 /* upper case */ 22 | #define CTYPE_LOW 0x02 /* lower case */ 23 | #define CTYPE_DIG 0x04 /* digit */ 24 | #define CTYPE_CTL 0x08 /* control */ 25 | #define CTYPE_PUN 0x10 /* punctuation */ 26 | #define CTYPE_WHT 0x20 /* white space (space/cr/lf/tab) */ 27 | #define CTYPE_HEX 0x40 /* hex digit */ 28 | #define CTYPE_SP 0x80 /* hard space (0x20) */ 29 | 30 | /* Basic macros for getting details of character */ 31 | 32 | #define isAlnum(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_UP | CTYPE_LOW | CTYPE_DIG)) 33 | #define isAlpha(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_UP | CTYPE_LOW)) 34 | #define isCntrl(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_CTL)) 35 | #define isDigit(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_DIG)) 36 | #define isGraph(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_PUN | CTYPE_UP | CTYPE_LOW | CTYPE_DIG)) 37 | #define isLower(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_LOW)) 38 | #define isPrint(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_PUN | CTYPE_UP | CTYPE_LOW | CTYPE_DIG | CTYPE_SP)) 39 | #define isPunct(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_PUN)) 40 | #define isSpace(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_WHT)) 41 | #define isUpper(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_UP)) 42 | #define isXdigit(c) ((_ctype + 1)[(unsigned int)(c)] & (CTYPE_DIG | CTYPE_HEX)) 43 | #define isAscii(c) ((unsigned int)(c) <= 0x7F) 44 | 45 | #define toAscii(c) ((unsigned int)(c) & 0x7F) 46 | #define toLower(c) (isupper(c) ? c + 'a' - 'A' : c) 47 | #define toUpper(c) (islower(c) ? c + 'A' - 'a' : c) 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | 54 | #endif /* CTYPE_H */ -------------------------------------------------------------------------------- /core/include/hal.h: -------------------------------------------------------------------------------- 1 | #ifndef HAL_H 2 | #define HAL_H 3 | 4 | 5 | //************************ 6 | /* HAL: Hardware Abstraction Layer */ 7 | // 8 | // The Hardware Abstraction Layer provide interface for controlling 9 | // motherboard hardware device 10 | // Specific HAL inplimentation is provided in for of library for 11 | // specific hardware 12 | // File: hal.h 13 | //************************ 14 | 15 | 16 | #ifndef ARCH_x86 17 | #error "HAL is not implimented" 18 | #endif /* ARCH_x86 */ 19 | 20 | 21 | #include 22 | 23 | 24 | /* Public Function */ 25 | 26 | /* Initialize HAL specific implimentation */ 27 | int initializeHal(); 28 | 29 | /* Shutdown HAL */ 30 | int shutdownHal(); 31 | 32 | /* Generate Software interrupt */ 33 | // interrupt is index in IDT 34 | void genInterrupt(uint32 interrupt); 35 | 36 | 37 | #endif /* HAL_H */ -------------------------------------------------------------------------------- /core/include/null.h: -------------------------------------------------------------------------------- 1 | #ifndef NULL_H 2 | #define NULL_H 3 | 4 | 5 | //************************ 6 | // Standard NULL declaration 7 | // File: null.h 8 | //************************ 9 | 10 | 11 | /* Undefine NULL if it is already defined by stdlib */ 12 | #ifdef NULL 13 | #undef NULL 14 | #endif 15 | 16 | 17 | #ifdef __cplusplus 18 | extern "C" 19 | { 20 | /* Standard NULL declaraton for C++*/ 21 | #define NULL 0 22 | /* Written #endif so that redefinition does not occur */ 23 | #endif 24 | 25 | #ifdef __cplusplus 26 | } 27 | #else 28 | /* Standard NULL declaration for C*/ 29 | #define NULL (void*)0 30 | #endif 31 | 32 | 33 | #endif /* NULL_H */ -------------------------------------------------------------------------------- /core/include/size.h: -------------------------------------------------------------------------------- 1 | #ifndef SIZE_H 2 | #define SIZE_H 3 | 4 | 5 | //************************ 6 | // Standard size declaration 7 | // File: size.h 8 | //************************ 9 | 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" 15 | { 16 | #endif 17 | 18 | /* size declaration 32-bit*/ 19 | typedef uint32 size; 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | 26 | #endif /* SIZE_H */ -------------------------------------------------------------------------------- /core/include/stdarg: -------------------------------------------------------------------------------- 1 | #ifndef STDARG_CPP_H 2 | #define STDARG_CPP_H 3 | 4 | /* Will be used in C++ include */ 5 | #include 6 | 7 | 8 | #endif /* STDARG_CPP_H */ -------------------------------------------------------------------------------- /core/include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef STDARG_H 2 | #define STDARG_H 3 | 4 | 5 | //************************ 6 | // Defines macros for using in variable lenght arguments 7 | // File: stdarg.h 8 | //************************ 9 | 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" 15 | { 16 | #endif 17 | 18 | /* Stack width = Int width */ 19 | #define STACKITEM int 20 | 21 | /* Round up width of objects pushed on stack. The expression before the & 22 | * ensures that we get 0 for objects of size 0. 23 | */ 24 | #define VA_SIZE(TYPE) ((sizeof(TYPE) + sizeof(STACKITEM) - 1) & ~(sizeof(STACKITEM) - 1)) 25 | 26 | /* &(LASTARG) Points to the LEFTMOST argument of the function call (before the ...) */ 27 | /* AP - argument pointer */ 28 | /* LASTARG - last argument */ 29 | #define va_start(AP, LASTARG) (AP=((va_list) &(LASTARG) + VA_SIZE(LASTARG))) 30 | 31 | /* nothing for vaEnd */ 32 | #define va_end(AP) 33 | 34 | #define va_arg(AP, TYPE) (AP += VA_SIZE(TYPE), *((TYPE *)(AP - VA_SIZE(TYPE)))) 35 | 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | 42 | #endif /* STDARG_H */ -------------------------------------------------------------------------------- /core/include/stdint: -------------------------------------------------------------------------------- 1 | #ifndef STDINT_CPP_H 2 | #define STDINT_CPP_H 3 | 4 | /* Will be used in C++ include */ 5 | #include 6 | 7 | 8 | #endif /* STDINT_CPP_H */ -------------------------------------------------------------------------------- /core/include/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef STDINT_H 2 | #define STDINT_H 3 | 4 | 5 | //************************ 6 | // Standard integer data-type 7 | // File: stdint.h 8 | //************************ 9 | 10 | 11 | /* Exact width integer type */ 12 | typedef signed char int8; 13 | typedef unsigned char uint8; 14 | typedef signed short int16; 15 | typedef unsigned short uint16; 16 | typedef signed int int32; 17 | typedef unsigned int uint32; 18 | typedef signed long long int64; 19 | typedef unsigned long long uint64; 20 | 21 | 22 | /* Integer capable of holding pointers */ 23 | typedef signed int intp; 24 | typedef unsigned int uintp; 25 | 26 | 27 | /* Min and Max values for integer data-type */ 28 | #define INT8_MIN (-128) 29 | #define INT16_MIN (-32768) 30 | #define INT32_MIN (-2147483647 - 1) 31 | #define INT64_MIN (-9223372036854775807LL - 1) 32 | 33 | #define INT8_MAX 127 34 | #define INT16_MAX 32767 35 | #define INT32_MAX 2147483647 36 | #define INT64_MAX 9223372036854775807LL 37 | 38 | // Unsigned integer Min all 0 39 | #define UINT8_MAX 0xff /* 255U */ 40 | #define UINT16_MAX 0xffff /* 65535U */ 41 | #define UINT32_MAX 0xffffffff /* 4294967295U */ 42 | #define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ 43 | 44 | /* Min and Max values for integer pointer data-type */ 45 | #define INTP_MIN INT32_MIN 46 | #define INTP_MAX INT32_MAX 47 | #define UINTP_MAX UINT32_MAX 48 | 49 | 50 | #endif /* STDINT_H */ -------------------------------------------------------------------------------- /core/include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef STDIO_H 2 | #define STDIO_H 3 | 4 | 5 | 6 | //************************ 7 | // Constain function related to input and output to console 8 | // File: stdio.h 9 | //************************ 10 | 11 | 12 | 13 | /* String of this size can be printed on console at a time */ 14 | #define BUFFER_SIZE 255 15 | 16 | 17 | ////////////////////// 18 | /* Public Function */ 19 | ////////////////////// 20 | 21 | 22 | /* Print formatted output to console */ 23 | void printf(const char* format, ...); 24 | 25 | /* Print formatted error on console with red color */ 26 | void perror(const char* format, ...); 27 | 28 | 29 | #endif /* STDIO_H */ -------------------------------------------------------------------------------- /core/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H 2 | #define STRING_H 3 | 4 | 5 | 6 | //************************ 7 | // Conatain function related to string - character array 8 | // File: string.h 9 | //************************ 10 | 11 | 12 | 13 | #include 14 | 15 | 16 | /* Conversion base for integers */ 17 | enum BASE 18 | { 19 | BASE_HEX = 16, 20 | BASE_DEC = 10, 21 | BASE_OCT = 8, 22 | BASE_BIN = 2, 23 | }; 24 | 25 | 26 | ////////////////////// 27 | /* Public Function */ 28 | ////////////////////// 29 | 30 | 31 | /* Return the length of the string (excluding NULL character) */ 32 | size strlen(const char*); 33 | 34 | /* Copy source to destination */ 35 | // Return pointer to destination string 36 | char* strcpy(char* destination, const char* source); 37 | 38 | /* Copy value to each byte of destination till count */ 39 | void* memset(void* destination, char value, size count); 40 | 41 | /* Copy source to destination till count */ 42 | void* memcpy(void* destination, const void* source, size count); 43 | 44 | /* Convert positive integer to string */ 45 | // base is for string(output value) 46 | void inttostr(uint32 value, enum BASE base, char* destination); 47 | 48 | /* Convert string to positive integer */ 49 | // base is for string(source value) 50 | void strtoint(char* source, enum BASE base, uint32* destination); 51 | 52 | /* Reverse the string inplace */ 53 | void strrev(char* source); 54 | 55 | 56 | #endif /* STRING_H */ -------------------------------------------------------------------------------- /core/include/va_list.h: -------------------------------------------------------------------------------- 1 | #ifndef VA_LIST_H 2 | #define VA_LIST_H 3 | 4 | 5 | //************************ 6 | // Define the data-type used for variable list argument in function 7 | // File: va_list.h 8 | //************************ 9 | 10 | 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" 15 | { 16 | #endif 17 | 18 | typedef uint8* va_list; 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | 25 | #endif /* VA_LIST_H */ -------------------------------------------------------------------------------- /core/kernel/Makefile: -------------------------------------------------------------------------------- 1 | # Usefull directories 2 | INC_DIR = ../include 3 | INC_KER_DIR = ./include 4 | SRC_DIR = ./source 5 | D_OBJ_DIR = ./obj/debug 6 | R_OBJ_DIR = ./obj/release 7 | 8 | 9 | # Tools for building 10 | CCOM = ../../compiler/bin/i686-elf-gcc 11 | CPPCOM = ../../compiler/bin/i686-elf-g++ 12 | ASM = ../../compiler/bin/i686-elf-as 13 | ARCH = ../../compiler/bin/i686-elf-ar 14 | MAKEDEPEND = makedepend 15 | 16 | 17 | # Flags for building tools 18 | CFLAG = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -I$(INC_DIR) -I$(INC_KER_DIR) 19 | CPPFLAG = -c -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti -I$(INC_DIR) -I$(INC_KER_DIR) 20 | ARFLAG = -vrcs 21 | 22 | 23 | _SOURCE = console.c kernel.c 24 | 25 | # Contain path to source files 26 | SRC_FILE = $(_SOURCE:%.c=$(SRC_DIR)/%.c) 27 | 28 | # Output debug object file 29 | D_OBJ = $(_SOURCE:%.c=$(D_OBJ_DIR)/%.o) 30 | 31 | # Output release object file 32 | R_OBJ = $(_SOURCE:%.c=$(R_OBJ_DIR)/%.o) 33 | 34 | # Output dependency file 35 | DEP = .depend 36 | 37 | #------------------------------------------------------------------------- 38 | 39 | all: $(D_OBJ) loader.o 40 | 41 | 42 | $(D_OBJ_DIR)/%.o: $(SRC_DIR)/%.c 43 | $(CCOM) $< -o $@ $(CFLAG) 44 | 45 | %.o: %.s 46 | $(ASM) $< -o $(D_OBJ_DIR)/$@ 47 | 48 | # Include dependency files for object files 49 | include $(DEP) 50 | 51 | # Clean object files 52 | clean: 53 | rm $(D_OBJ_DIR)/* 54 | 55 | # Generate dependency for course and output to DEP file 56 | depend: 57 | $(MAKEDEPEND) -v -f$(DEP) -Y$(INC_DIR) -I$(INC_KER_DIR) $(SRC_FILE) 58 | rm $(DEP).bak -------------------------------------------------------------------------------- /core/kernel/include/console.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSOLE_H 2 | #define CONSOLE_H 3 | 4 | 5 | 6 | //************************ 7 | // Initialize console for inputing and outputing 8 | // data on screen 9 | // File: console.h 10 | //************************ 11 | 12 | 13 | 14 | #include 15 | #include 16 | 17 | 18 | /* color data-type, include Foreground and background color */ 19 | // first 4-bit are background color 20 | // last 4-bit are foreground color 21 | typedef uint8 color; 22 | 23 | 24 | /* vga_entry data-type, for using in VGA buffer */ 25 | // first 8-bit are color data-type 26 | // last 8-bit are character 27 | typedef uint16 vga_entry; 28 | 29 | 30 | /* Hardware text mode color constants. */ 31 | enum VGA_COLOR 32 | { 33 | COLOR_BLACK = 0, 34 | COLOR_BLUE = 1, 35 | COLOR_GREEN = 2, 36 | COLOR_CYAN = 3, 37 | COLOR_RED = 4, 38 | COLOR_MAGENTA = 5, 39 | COLOR_BROWN = 6, 40 | COLOR_LIGHT_GREY = 7, 41 | COLOR_DARK_GREY = 8, 42 | COLOR_LIGHT_BLUE = 9, 43 | COLOR_LIGHT_GREEN = 10, 44 | COLOR_LIGHT_CYAN = 11, 45 | COLOR_LIGHT_RED = 12, 46 | COLOR_LIGHT_MAGENTA = 13, 47 | COLOR_LIGHT_BROWN = 14, 48 | COLOR_WHITE = 15, 49 | }; 50 | 51 | 52 | /* VGA console dimension - 80 * 25 characters */ 53 | #define VGA_WIDTH 80 54 | #define VGA_HEIGHT 25 55 | 56 | 57 | /* Color bits */ 58 | #define FOREGROUND_COLOR 0x0F // 00001111 59 | #define BACKGROUND_COLOR 0xF0 // 11110000 60 | 61 | 62 | ////////////////////// 63 | /* Public function */ 64 | ////////////////////// 65 | 66 | 67 | /* Print the string to console */ 68 | void printConsole(const char*); 69 | 70 | /* Clear VGA memory and move cursor to starting position*/ 71 | void clearConsole(); 72 | 73 | /* Initialize console for printing data */ 74 | void initializeConsole(color defaultColor); 75 | 76 | /* Set color used to display in console */ 77 | void consoleSetColor(color c); 78 | 79 | /* Return the current color used in console */ 80 | color consoleGetColor(); 81 | 82 | /* Make color from foreground and background colors */ 83 | color makeColor(enum VGA_COLOR fg, enum VGA_COLOR bg); 84 | 85 | 86 | #endif /* CONSOLE_H */ -------------------------------------------------------------------------------- /core/kernel/linker.ld: -------------------------------------------------------------------------------- 1 | /* The bootloader will look at this image and start execution at the symbol 2 | designated as the entry point. */ 3 | ENTRY(_start) 4 | 5 | /* Tell where the various sections of the object files will be put in the final 6 | kernel image. */ 7 | SECTIONS 8 | { 9 | /* Begin putting sections at 1 MiB, a conventional place for kernels to be 10 | loaded at by the bootloader. */ 11 | . = 1M; 12 | 13 | /* First put the multiboot header, as it is required to be put very early 14 | early in the image or the bootloader won't recognize the file format. 15 | Next we'll put the .text section. */ 16 | .text BLOCK(4K) : ALIGN(4K) 17 | { 18 | *(.multiboot) 19 | *(.text) 20 | } 21 | 22 | /* Read-only data. */ 23 | .rodata BLOCK(4K) : ALIGN(4K) 24 | { 25 | *(.rodata) 26 | } 27 | 28 | /* Read-write data (initialized) */ 29 | .data BLOCK(4K) : ALIGN(4K) 30 | { 31 | *(.data) 32 | } 33 | 34 | /* Read-write data (uninitialized) and stack */ 35 | .bss BLOCK(4K) : ALIGN(4K) 36 | { 37 | *(COMMON) 38 | *(.bss) 39 | *(.bootstrap_stack) 40 | } 41 | 42 | /* The compiler may produce other sections, by default it will put them in 43 | a segment with the same name. Simply add stuff here as needed. */ 44 | } -------------------------------------------------------------------------------- /core/kernel/loader.s: -------------------------------------------------------------------------------- 1 | # Declare constants used for creating a multiboot header. 2 | .set ALIGN, 1<<0 # align loaded modules on page boundaries 3 | .set MEMINFO, 1<<1 # provide memory map 4 | .set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field 5 | .set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header 6 | .set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot 7 | 8 | # Declare a header as in the Multiboot Standard. We put this into a special 9 | # section so we can force the header to be in the start of the final program. 10 | # You don't need to understand all these details as it is just magic values that 11 | # is documented in the multiboot standard. The bootloader will search for this 12 | # magic sequence and recognize us as a multiboot kernel. 13 | .section .multiboot 14 | .align 4 15 | .long MAGIC 16 | .long FLAGS 17 | .long CHECKSUM 18 | 19 | # Currently the stack pointer register (esp) points at anything and using it may 20 | # cause massive harm. Instead, we'll provide our own stack. We will allocate 21 | # room for a small temporary stack by creating a symbol at the bottom of it, 22 | # then allocating 16384 bytes for it, and finally creating a symbol at the top. 23 | .section .bootstrap_stack, "aw", @nobits 24 | stack_bottom: 25 | .skip 16384 # 16 KiB 26 | stack_top: 27 | 28 | # The linker script specifies _start as the entry point to the kernel and the 29 | # bootloader will jump to this position once the kernel has been loaded. It 30 | # doesn't make sense to return from this function as the bootloader is gone. 31 | .section .text 32 | .global _start 33 | .type _start, @function 34 | _start: 35 | # Welcome to kernel mode! We now have sufficient code for the bootloader to 36 | # load and run our operating system. It doesn't do anything interesting yet. 37 | # Perhaps we would like to call printf("Hello, World\n"). You should now 38 | # realize one of the profound truths about kernel mode: There is nothing 39 | # there unless you provide it yourself. There is no printf function. There 40 | # is no header. If you want a function, you will have to code it 41 | # yourself. And that is one of the best things about kernel development: 42 | # you get to make the entire system yourself. You have absolute and complete 43 | # power over the machine, there are no security restrictions, no safe 44 | # guards, no debugging mechanisms, there is nothing but what you build. 45 | 46 | # By now, you are perhaps tired of assembly language. You realize some 47 | # things simply cannot be done in C, such as making the multiboot header in 48 | # the right section and setting up the stack. However, you would like to 49 | # write the operating system in a higher level language, such as C or C++. 50 | # To that end, the next task is preparing the processor for execution of 51 | # such code. C doesn't expect much at this point and we only need to set up 52 | # a stack. Note that the processor is not fully initialized yet and stuff 53 | # such as floating point instructions are not available yet. 54 | 55 | # To set up a stack, we simply set the esp register to point to the top of 56 | # our stack (as it grows downwards). 57 | movl $stack_top, %esp 58 | 59 | # We are now ready to actually execute C code. We cannot embed that in an 60 | # assembly file, so we'll create a kernel.c file in a moment. In that file, 61 | # we'll create a C entry point called kernel and call it here. 62 | call kernel 63 | 64 | # In case the function returns, we'll want to put the computer into an 65 | # infinite loop. To do that, we use the clear interrupt ('cli') instruction 66 | # to disable interrupts, the halt instruction ('hlt') to stop the CPU until 67 | # the next interrupt arrives, and jumping to the halt instruction if it ever 68 | # continues execution, just to be safe. We will create a local label rather 69 | # than real symbol and jump to there endlessly. 70 | cli 71 | hlt 72 | .Lhang: 73 | jmp .Lhang 74 | 75 | # Set the size of the _start symbol to the current location '.' minus its start. 76 | # This is useful when debugging or when you implement call tracing. 77 | .size _start, . - _start 78 | -------------------------------------------------------------------------------- /core/kernel/source/console.c: -------------------------------------------------------------------------------- 1 | #include "console.h" 2 | #include 3 | 4 | 5 | ////////////// 6 | /* Private */ 7 | ////////////// 8 | 9 | 10 | static size consoleRow; 11 | static size consoleColumn; 12 | static color consoleColor; 13 | static vga_entry* consoleBuffer; 14 | 15 | 16 | /* Make single vga_entry for given chracter and color */ 17 | static vga_entry makeVGAEntry(char ch, color c); 18 | 19 | /* Put a character in VGA text memory at specific location */ 20 | static void consolePutVGAEntryAt(char ch, color c, size x, size y); 21 | 22 | /* Put a character in VGA text moemory at current cursor location */ 23 | static void consolePutChar(char ch); 24 | 25 | /* Change the cursor position in console as character are printed*/ 26 | static void moveCursor(); 27 | 28 | 29 | ////////////////////// 30 | /* Private funtion */ 31 | ////////////////////// 32 | 33 | 34 | vga_entry makeVGAEntry(char ch, color c) 35 | { 36 | uint16 ch16 = ch; 37 | uint16 color16 = c; 38 | 39 | return ch16 | color16 << 8; 40 | } 41 | 42 | void consolePutVGAEntryAt(char ch, color c, size x, size y) 43 | { 44 | const size index = y * VGA_WIDTH + x; 45 | consoleBuffer[index] = makeVGAEntry(ch, c); 46 | } 47 | 48 | void consolePutChar(char ch) 49 | { 50 | if(consoleRow == VGA_HEIGHT - 1) 51 | { 52 | // Scroll 53 | size limit = VGA_WIDTH * VGA_HEIGHT - VGA_WIDTH; 54 | for(size i = 0; i < limit; ++i) 55 | { 56 | consoleBuffer[i] = consoleBuffer[i + VGA_WIDTH]; 57 | } 58 | 59 | consoleRow--; 60 | } 61 | 62 | 63 | if(ch == '\n') 64 | { 65 | consoleColumn = 0; 66 | consoleRow++; 67 | 68 | return; 69 | } 70 | 71 | consolePutVGAEntryAt(ch, consoleColor, consoleColumn, consoleRow); 72 | 73 | if ( ++consoleColumn == VGA_WIDTH ) 74 | { 75 | consoleColumn = 0; 76 | consoleRow++; 77 | } 78 | } 79 | 80 | void moveCursor() 81 | { 82 | uint16 location = consoleRow * VGA_WIDTH + consoleColumn; 83 | 84 | /* out ins. write second operand to port in first operand */ 85 | asm 86 | ( 87 | "mov %0, %%bx\n\t" /*Copy location to bx register*/ 88 | 89 | /*Setting Low byte of cursor position*/ 90 | 91 | "mov $0x0f, %%al\n\t" /*Cursor location low byte index*/ 92 | "mov $0x03D4, %%dx\n\t" /*Write it to the CRT index register*/ 93 | "out %%al, %%dx\n\t" 94 | 95 | "mov %%bl, %%al\n\t" /*The current location is in EBX. BL contains the low byte, BH high byte*/ 96 | "mov $0x03D5, %%dx\n\t" /*Write it to the data register*/ 97 | "out %%al, %%dx\n\t" /*low byte*/ 98 | 99 | 100 | /*Setting High byte of cursor position*/ 101 | 102 | "mov $0x0e, %%al\n\t" /*Cursor location high byte index*/ 103 | "mov $0x03D4, %%dx\n\t" /*Write to the CRT index register*/ 104 | "out %%al, %%dx\n\t" 105 | 106 | "mov %%bh, %%al\n\t" /*the current location is in EBX. BL contains low byte, BH high byte*/ 107 | "mov $0x03D5, %%dx\n\t" /*Write it to the data register*/ 108 | "out %%al, %%dx\n\t" 109 | : 110 | : [input] "g" (location) 111 | : "%bx" 112 | ); 113 | } 114 | 115 | 116 | ////////////////////// 117 | /* Public Function */ 118 | ////////////////////// 119 | 120 | 121 | color makeColor(enum VGA_COLOR fg, enum VGA_COLOR bg) 122 | { 123 | return fg | bg << 4; 124 | } 125 | 126 | void initializeConsole(color defaultColor) 127 | { 128 | consoleColor = defaultColor; 129 | consoleBuffer = (uint16*) 0xB8000; 130 | 131 | clearConsole(); 132 | } 133 | 134 | void printConsole(const char* data) 135 | { 136 | size datalen = strlen(data); 137 | for (size i = 0; i < datalen; i++) 138 | { 139 | consolePutChar(data[i]); 140 | } 141 | 142 | moveCursor(); 143 | } 144 | 145 | void consoleSetColor(color c) 146 | { 147 | consoleColor = c; 148 | } 149 | 150 | color consoleGetColor() 151 | { 152 | return consoleColor; 153 | } 154 | 155 | void clearConsole() 156 | { 157 | for ( size y = 0; y < VGA_HEIGHT; y++ ) 158 | { 159 | for ( size x = 0; x < VGA_WIDTH; x++ ) 160 | { 161 | const size index = y * VGA_WIDTH + x; 162 | consoleBuffer[index] = makeVGAEntry(' ', consoleColor); 163 | } 164 | } 165 | 166 | consoleRow = 0; 167 | consoleColumn = 0; 168 | 169 | moveCursor(); 170 | } -------------------------------------------------------------------------------- /core/kernel/source/kernel.c: -------------------------------------------------------------------------------- 1 | /* Check if the compiler thinks if we are targeting the wrong operating system. */ 2 | #if defined(__linux__) 3 | #error "You are not using a cross-compiler, you will most certainly run into trouble" 4 | #endif 5 | 6 | /* This tutorial will only work for the 32-bit ix86 targets. */ 7 | #if !defined(__i386__) 8 | #error "This tutorial needs to be compiled with a ix86-elf compiler" 9 | #endif 10 | 11 | #define ARCH_x86 12 | 13 | #include "console.h" /* Included here so no other file include it, directly use print */ 14 | #include 15 | #include 16 | #include // For generating interrupts 17 | 18 | void usefullStuff() 19 | { 20 | initializeHal(); 21 | 22 | //genInterrupt(0); 23 | //genInterrupt(7); 24 | 25 | initializeHal(); 26 | 27 | printf("Hello World\n"); 28 | } 29 | 30 | 31 | #if defined(__cplusplus) 32 | extern "C" /* Use C linkage for kernel. */ 33 | #endif 34 | void kernel() 35 | { 36 | /* Initialize console so that print start working */ 37 | initializeConsole(makeColor(COLOR_WHITE, COLOR_BLUE)); 38 | 39 | usefullStuff(); 40 | } -------------------------------------------------------------------------------- /core/lib/Makefile: -------------------------------------------------------------------------------- 1 | # Output librabry file 2 | LIB_ARCH = libstd.a 3 | 4 | 5 | # Usefull directories 6 | INC_DIR = ../include 7 | SRC_DIR = ./source 8 | D_OBJ_DIR = ./obj/debug 9 | R_OBJ_DIR = ./obj/release 10 | 11 | 12 | # Tools for building 13 | CCOM = ../../compiler/bin/i686-elf-gcc 14 | CPPCOM = ../../compiler/bin/i686-elf-g++ 15 | ASM = ../../compiler/bin/i686-elf-as 16 | ARCH = ../../compiler/bin/i686-elf-ar 17 | MAKEDEPEND = makedepend 18 | 19 | 20 | # Flags for building tools 21 | CFLAG = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -I$(INC_DIR) 22 | CPPFLAG = -c -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti -I$(INC_DIR) 23 | ARFLAG = -vrcs 24 | 25 | 26 | _SOURCE = string.c stdio.c 27 | 28 | # Contain path to source files 29 | SRC_FILE = $(_SOURCE:%.c=$(SRC_DIR)/%.c) 30 | 31 | # Output debug object file 32 | D_OBJ = $(_SOURCE:%.c=$(D_OBJ_DIR)/%.o) 33 | 34 | # Output release object file 35 | R_OBJ = $(_SOURCE:%.c=$(R_OBJ_DIR)/%.o) 36 | 37 | # Output dependency file 38 | DEP = .depend 39 | 40 | #------------------------------------------------------------------------- 41 | 42 | lib: $(LIB_ARCH) 43 | 44 | $(LIB_ARCH): $(D_OBJ) 45 | $(ARCH) $(ARFLAG) $(LIB_ARCH) $(D_OBJ) 46 | 47 | $(D_OBJ_DIR)/%.o: $(SRC_DIR)/%.c 48 | $(CCOM) $< -o $@ $(CFLAG) 49 | 50 | # Include dependency files for object files 51 | include $(DEP) 52 | 53 | # Clean object file 54 | clean: 55 | rm $(D_OBJ_DIR)/* 56 | rm $(LIB_ARCH) 57 | 58 | # Generate dependency for course and output to DEP file 59 | depend: 60 | $(MAKEDEPEND) -v -f$(DEP) -Y$(INC_DIR) $(SRC_FILE) 61 | rm $(DEP).bak -------------------------------------------------------------------------------- /core/lib/libhal.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kapilks/Basic-Kernel/e672cfcaa81df053856f7ace7399bb8ce21a3eba/core/lib/libhal.a -------------------------------------------------------------------------------- /core/lib/libstd.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kapilks/Basic-Kernel/e672cfcaa81df053856f7ace7399bb8ce21a3eba/core/lib/libstd.a -------------------------------------------------------------------------------- /core/lib/source/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include <../kernel/include/console.h> 8 | 9 | 10 | ///////////// 11 | /* Private */ 12 | ///////////// 13 | 14 | 15 | static size bprintf(char* buffer, const char* format, va_list arguments); 16 | 17 | 18 | ////////////////////// 19 | /* Private Function */ 20 | ////////////////////// 21 | 22 | 23 | static size bprintf(char* buffer, const char* format, va_list arguments) 24 | { 25 | if(!format || !arguments) 26 | { 27 | return 0; 28 | } 29 | 30 | size formatLength = strlen(format); 31 | size index = 0; 32 | 33 | for(size i = 0; i < formatLength; ++i) 34 | { 35 | if(format[i] == '%') 36 | { 37 | i++; 38 | 39 | switch(format[i]) 40 | { 41 | case 'c': // Characters 42 | { 43 | buffer[index] = va_arg(arguments, char); 44 | index++; 45 | 46 | break; 47 | } 48 | case 's': // String 49 | { 50 | const char* str = va_arg(arguments, char*); 51 | strcpy(&buffer[index], str); 52 | index += strlen(str); 53 | 54 | break; 55 | } 56 | default: 57 | { 58 | // Default decimal base 59 | enum BASE base = BASE_DEC; 60 | 61 | switch(format[i]) 62 | { 63 | case 'x': // Hex 64 | { 65 | base = BASE_HEX; break; 66 | } 67 | case 'b': // Binary 68 | { 69 | base = BASE_BIN; break; 70 | } 71 | case 'o': // Octal 72 | { 73 | base = BASE_OCT; break; 74 | } 75 | case 'd': // Integers 76 | { 77 | base = BASE_DEC; break; 78 | } 79 | } 80 | 81 | uint32 num = va_arg(arguments, uint32); 82 | 83 | // 32 bits integer 84 | char str[32] = {0}; 85 | 86 | inttostr(num, base, str); 87 | strcpy(&buffer[index], str); 88 | index += strlen(str); 89 | } 90 | } 91 | } 92 | else 93 | { 94 | buffer[index++] = format[i]; 95 | } 96 | } 97 | 98 | buffer[index] = (char)0; 99 | 100 | // index id the length of buffer string 101 | return index; 102 | } 103 | 104 | 105 | ////////////////////// 106 | /* Public Function */ 107 | ////////////////////// 108 | 109 | 110 | void printf(const char* format, ...) 111 | { 112 | char buffer[BUFFER_SIZE]; 113 | 114 | va_list arguments; 115 | va_start(arguments, format); 116 | 117 | bprintf(buffer, format, arguments); 118 | 119 | va_end(arguments); 120 | 121 | printConsole(buffer); 122 | } 123 | 124 | void perror(const char* format, ...) 125 | { 126 | color consoleColor = consoleGetColor(); 127 | // Using bg of consoleColor and fg as red 128 | 129 | consoleSetColor(makeColor(COLOR_LIGHT_RED, (consoleColor & BACKGROUND_COLOR) >> 4)); 130 | 131 | // Same as printf 132 | char buffer[BUFFER_SIZE]; 133 | 134 | va_list arguments; 135 | va_start(arguments, format); 136 | 137 | bprintf(buffer, format, arguments); 138 | 139 | va_end(arguments); 140 | 141 | printConsole(buffer); 142 | 143 | 144 | consoleSetColor(consoleColor); 145 | } -------------------------------------------------------------------------------- /core/lib/source/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | ////////////// 5 | /* Private */ 6 | ////////////// 7 | 8 | 9 | // Integers characters in different base 10 | static char characters[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 11 | 12 | 13 | ////////////////////// 14 | /* Public Function */ 15 | ////////////////////// 16 | 17 | 18 | size strlen(const char* str) 19 | { 20 | size length = 0; 21 | 22 | while(str[length] != 0) 23 | { 24 | length++; 25 | } 26 | 27 | /* This length exclude NULL character */ 28 | return length; 29 | } 30 | 31 | char* strcpy(char* destination, const char* source) 32 | { 33 | char* destinationTmp = destination; 34 | 35 | while(*source) 36 | { 37 | *destination = *source; 38 | destination++; 39 | source++; 40 | } 41 | 42 | // Copy null character 43 | *destination = *source; 44 | 45 | return destinationTmp; 46 | } 47 | 48 | void* memset(void* destination, char value, size count) 49 | { 50 | // Converting for valid pointer ++ 51 | uint8* destinationTmp = (uint8*)destination; 52 | 53 | for(; count > 0; --count, ++destinationTmp) 54 | { 55 | *destinationTmp = value; 56 | } 57 | 58 | return destination; 59 | } 60 | 61 | void* memcpy(void* destination, const void* source, size count) 62 | { 63 | uint8* destinationTmp = (uint8*)destination; 64 | const uint8* sourceTmp = (const uint8*)source; 65 | 66 | for(; count > 0; --count, ++destinationTmp, ++sourceTmp) 67 | { 68 | *destinationTmp = *sourceTmp; 69 | } 70 | 71 | return destination; 72 | } 73 | 74 | void inttostr(uint32 value, enum BASE base, char* destination) 75 | { 76 | char* destinationTmp = destination; 77 | uint8 ch; 78 | 79 | if(value == 0) 80 | { 81 | *destination++ = '0'; 82 | *destination = '\0'; 83 | 84 | return; 85 | } 86 | 87 | while(value > 0) 88 | { 89 | ch = (uint8)(value % base); 90 | 91 | *destination++ = characters[ch]; 92 | 93 | value /= base; 94 | } 95 | 96 | // NULL character 97 | *destination = '\0'; 98 | 99 | strrev(destinationTmp); 100 | } 101 | 102 | void strtoint(char* source, enum BASE base, uint32* destination) 103 | { 104 | uint32 output = 0; 105 | 106 | size length = strlen(source); 107 | 108 | for(; length > 0; --length, source++) 109 | { 110 | uint8 ch = (uint8)*source; 111 | 112 | if(ch >= 'a' && ch <= 'f') 113 | { 114 | ch = ch - (uint8)'a' + 10; 115 | } 116 | else if(ch >= 'A' && ch <= 'F') 117 | { 118 | ch = ch - (uint8)'A' + 10; 119 | } 120 | else 121 | { 122 | ch -= (uint8)'0'; 123 | } 124 | 125 | output = output * base + ch; 126 | } 127 | 128 | *destination = output; 129 | } 130 | 131 | void strrev(char* source) 132 | { 133 | size length = strlen(source); 134 | uint8 tmp; 135 | 136 | size high = length - 1; 137 | size low = 0; 138 | 139 | while(low < high) 140 | { 141 | tmp = source[low]; 142 | source[low] = source[high]; 143 | source[high] = tmp; 144 | 145 | low++; 146 | high--; 147 | } 148 | } 149 | 150 | uint8 strcmp(const char* str1, const char* str2) 151 | { 152 | size len1 = strlen(str1); 153 | size len2 = strlen(str2); 154 | 155 | if(len1 != len2) 156 | { 157 | return 0; 158 | } 159 | 160 | for(size i = 0; i < len1; ++i) 161 | { 162 | if(*str1++ != *str2++) 163 | { 164 | return 0; 165 | } 166 | } 167 | 168 | return 1; 169 | } -------------------------------------------------------------------------------- /grub/stage2_eltorito: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kapilks/Basic-Kernel/e672cfcaa81df053856f7ace7399bb8ce21a3eba/grub/stage2_eltorito -------------------------------------------------------------------------------- /initialise.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create diretories structure for binaries 4 | mkdir -p core/hal/obj/debug 5 | mkdir -p core/kernel/bin 6 | mkdir -p core/kernel/obj 7 | mkdir -p core/lib/obj 8 | 9 | # Dependencies files 10 | touch core/hal/.depend 11 | touch core/kernel/.depend 12 | touch core/lib/.depend -------------------------------------------------------------------------------- /screenshots/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kapilks/Basic-Kernel/e672cfcaa81df053856f7ace7399bb8ce21a3eba/screenshots/home.png --------------------------------------------------------------------------------