diff --git a/.gitignore b/.gitignore index 738c016..e1f69f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ *.out iso/ *.elf +*.bin *.o *.iso stage2_eltorito log/ +built_file_system +TODO +NOTES diff --git a/Makefile b/Makefile index 2cb825d..5699530 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ NASM=nasm # https://en.wikipedia.org/wiki/GNU_linker -LD=~/.local/binutils/bin/i386-unkown-linux-gnu-ld +LD=~/.local/binutils/bin/i386-unknown-linux-gnu-ld # https://en.wikipedia.org/wiki/QEMU # Virtual machine @@ -19,30 +19,61 @@ CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \ ASFLAGS = -f elf OBJECTS = loader.o \ +asm_interrupts.o \ +assembly_interface.o \ +data_structures/global_descriptor_table.o \ +data_structures/interrupt_descriptor_table.o \ +data_structures/page_table.o \ +data_structures/symbol_table.o \ drivers/frame_buffer.o \ +drivers/keyboard.o \ +drivers/pic.o \ drivers/serial_port.o \ -assembly_interface.o \ interrupts.o \ -kmain.o +kernel_filesystem.o \ +kernel_stdio.o \ +kernel_syscalls.o \ +kmain.o \ +multiboot_utils.o \ +process.o \ +stdlib.o + +STDLIB = stdlib/stdio.o \ +stdlib/string.o \ +stdlib/syscalls.o all: os.iso %.o: %.c # Compile c files with gcc - $(GCC) $(CFLAGS) $< -o $@ + $(GCC) $(CFLAGS) $< -o $@ %.o: %.s # assemble s files with nasm $(NASM) $(ASFLAGS) $< -o $@ -kernel.elf: $(OBJECTS) - $(LD) -T link.ld -melf_i386 $(OBJECTS) -o kernel.elf # Link to make an executable for the kernel. +kernel.elf: $(OBJECTS) $(STDLIB) + $(LD) -T link.ld -melf_i386 $^ -o kernel.elf # Link to make an executable for the kernel. + +start_user_program.o: start_user_program.s + $(NASM) $(ASFLAGS) $< -o $@ + +shell.o: shell.c + $(GCC) $(CFLAGS) $< -o $@ + +shell.bin: shell.o start_user_program.o $(STDLIB) + $(LD) -T link_user_program.ld -melf_i386 $^ -o $@ + +built_file_system: file_system_root/* shell.bin + script/build_file_system -os.iso: kernel.elf +os.iso: kernel.elf shell.bin menu.lst built_file_system mkdir -p iso/boot/grub # create the folder structure + mkdir -p iso/modules cp stage2_eltorito iso/boot/grub/ # copy the bootloader cp kernel.elf iso/boot/ # copy the kernel - cp menu.lst iso/boot/grub # copy the configuration file + cp built_file_system iso/modules # copy the 'user' program + cp menu.lst iso/boot/grub # copy the grub configuration file mkisofs -R \ -b boot/grub/stage2_eltorito \ -no-emul-boot \ @@ -59,8 +90,10 @@ run: os.iso $(QEMU) -monitor stdio -cdrom $< -serial file:log/log.txt clean: - rm *.iso - rm $(OBJECTS) - rm *.elf - rm *.out + rm -f *.iso + rm -f $(OBJECTS) + rm -f *.elf # elf executables + rm -f *.bin # flat binary executables + rm -f *.out rm -rf iso/ + rm -f built_file_system diff --git a/README.md b/README.md index 6cf39ae..95adcc3 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Following the tutorial: https://littleosbook.github.io # Setup ## OSX ``` -$ brew install nasm # virtual machine -$ brew install qemu # assembler +$ brew install nasm # assembler +$ brew install qemu # virtual machine $ brew install cdrtools # includes a utility for making disk images ``` diff --git a/asm_interrupts.h b/asm_interrupts.h new file mode 100644 index 0000000..3974009 --- /dev/null +++ b/asm_interrupts.h @@ -0,0 +1,256 @@ +void interrupt_handler_0(); +void interrupt_handler_1(); +void interrupt_handler_2(); +void interrupt_handler_3(); +void interrupt_handler_4(); +void interrupt_handler_5(); +void interrupt_handler_6(); +void interrupt_handler_7(); +void interrupt_handler_8(); +void interrupt_handler_9(); +void interrupt_handler_10(); +void interrupt_handler_11(); +void interrupt_handler_12(); +void interrupt_handler_13(); +void interrupt_handler_14(); +void interrupt_handler_15(); +void interrupt_handler_16(); +void interrupt_handler_17(); +void interrupt_handler_18(); +void interrupt_handler_19(); +void interrupt_handler_20(); +void interrupt_handler_21(); +void interrupt_handler_22(); +void interrupt_handler_23(); +void interrupt_handler_24(); +void interrupt_handler_25(); +void interrupt_handler_26(); +void interrupt_handler_27(); +void interrupt_handler_28(); +void interrupt_handler_29(); +void interrupt_handler_30(); +void interrupt_handler_31(); +void interrupt_handler_32(); +void interrupt_handler_33(); +void interrupt_handler_34(); +void interrupt_handler_35(); +void interrupt_handler_36(); +void interrupt_handler_37(); +void interrupt_handler_38(); +void interrupt_handler_39(); +void interrupt_handler_40(); +void interrupt_handler_41(); +void interrupt_handler_42(); +void interrupt_handler_43(); +void interrupt_handler_44(); +void interrupt_handler_45(); +void interrupt_handler_46(); +void interrupt_handler_47(); +void interrupt_handler_48(); +void interrupt_handler_49(); +void interrupt_handler_50(); +void interrupt_handler_51(); +void interrupt_handler_52(); +void interrupt_handler_53(); +void interrupt_handler_54(); +void interrupt_handler_55(); +void interrupt_handler_56(); +void interrupt_handler_57(); +void interrupt_handler_58(); +void interrupt_handler_59(); +void interrupt_handler_60(); +void interrupt_handler_61(); +void interrupt_handler_62(); +void interrupt_handler_63(); +void interrupt_handler_64(); +void interrupt_handler_65(); +void interrupt_handler_66(); +void interrupt_handler_67(); +void interrupt_handler_68(); +void interrupt_handler_69(); +void interrupt_handler_70(); +void interrupt_handler_71(); +void interrupt_handler_72(); +void interrupt_handler_73(); +void interrupt_handler_74(); +void interrupt_handler_75(); +void interrupt_handler_76(); +void interrupt_handler_77(); +void interrupt_handler_78(); +void interrupt_handler_79(); +void interrupt_handler_80(); +void interrupt_handler_81(); +void interrupt_handler_82(); +void interrupt_handler_83(); +void interrupt_handler_84(); +void interrupt_handler_85(); +void interrupt_handler_86(); +void interrupt_handler_87(); +void interrupt_handler_88(); +void interrupt_handler_89(); +void interrupt_handler_90(); +void interrupt_handler_91(); +void interrupt_handler_92(); +void interrupt_handler_93(); +void interrupt_handler_94(); +void interrupt_handler_95(); +void interrupt_handler_96(); +void interrupt_handler_97(); +void interrupt_handler_98(); +void interrupt_handler_99(); +void interrupt_handler_100(); +void interrupt_handler_101(); +void interrupt_handler_102(); +void interrupt_handler_103(); +void interrupt_handler_104(); +void interrupt_handler_105(); +void interrupt_handler_106(); +void interrupt_handler_107(); +void interrupt_handler_108(); +void interrupt_handler_109(); +void interrupt_handler_110(); +void interrupt_handler_111(); +void interrupt_handler_112(); +void interrupt_handler_113(); +void interrupt_handler_114(); +void interrupt_handler_115(); +void interrupt_handler_116(); +void interrupt_handler_117(); +void interrupt_handler_118(); +void interrupt_handler_119(); +void interrupt_handler_120(); +void interrupt_handler_121(); +void interrupt_handler_122(); +void interrupt_handler_123(); +void interrupt_handler_124(); +void interrupt_handler_125(); +void interrupt_handler_126(); +void interrupt_handler_127(); +void interrupt_handler_128(); +void interrupt_handler_129(); +void interrupt_handler_130(); +void interrupt_handler_131(); +void interrupt_handler_132(); +void interrupt_handler_133(); +void interrupt_handler_134(); +void interrupt_handler_135(); +void interrupt_handler_136(); +void interrupt_handler_137(); +void interrupt_handler_138(); +void interrupt_handler_139(); +void interrupt_handler_140(); +void interrupt_handler_141(); +void interrupt_handler_142(); +void interrupt_handler_143(); +void interrupt_handler_144(); +void interrupt_handler_145(); +void interrupt_handler_146(); +void interrupt_handler_147(); +void interrupt_handler_148(); +void interrupt_handler_149(); +void interrupt_handler_150(); +void interrupt_handler_151(); +void interrupt_handler_152(); +void interrupt_handler_153(); +void interrupt_handler_154(); +void interrupt_handler_155(); +void interrupt_handler_156(); +void interrupt_handler_157(); +void interrupt_handler_158(); +void interrupt_handler_159(); +void interrupt_handler_160(); +void interrupt_handler_161(); +void interrupt_handler_162(); +void interrupt_handler_163(); +void interrupt_handler_164(); +void interrupt_handler_165(); +void interrupt_handler_166(); +void interrupt_handler_167(); +void interrupt_handler_168(); +void interrupt_handler_169(); +void interrupt_handler_170(); +void interrupt_handler_171(); +void interrupt_handler_172(); +void interrupt_handler_173(); +void interrupt_handler_174(); +void interrupt_handler_175(); +void interrupt_handler_176(); +void interrupt_handler_177(); +void interrupt_handler_178(); +void interrupt_handler_179(); +void interrupt_handler_180(); +void interrupt_handler_181(); +void interrupt_handler_182(); +void interrupt_handler_183(); +void interrupt_handler_184(); +void interrupt_handler_185(); +void interrupt_handler_186(); +void interrupt_handler_187(); +void interrupt_handler_188(); +void interrupt_handler_189(); +void interrupt_handler_190(); +void interrupt_handler_191(); +void interrupt_handler_192(); +void interrupt_handler_193(); +void interrupt_handler_194(); +void interrupt_handler_195(); +void interrupt_handler_196(); +void interrupt_handler_197(); +void interrupt_handler_198(); +void interrupt_handler_199(); +void interrupt_handler_200(); +void interrupt_handler_201(); +void interrupt_handler_202(); +void interrupt_handler_203(); +void interrupt_handler_204(); +void interrupt_handler_205(); +void interrupt_handler_206(); +void interrupt_handler_207(); +void interrupt_handler_208(); +void interrupt_handler_209(); +void interrupt_handler_210(); +void interrupt_handler_211(); +void interrupt_handler_212(); +void interrupt_handler_213(); +void interrupt_handler_214(); +void interrupt_handler_215(); +void interrupt_handler_216(); +void interrupt_handler_217(); +void interrupt_handler_218(); +void interrupt_handler_219(); +void interrupt_handler_220(); +void interrupt_handler_221(); +void interrupt_handler_222(); +void interrupt_handler_223(); +void interrupt_handler_224(); +void interrupt_handler_225(); +void interrupt_handler_226(); +void interrupt_handler_227(); +void interrupt_handler_228(); +void interrupt_handler_229(); +void interrupt_handler_230(); +void interrupt_handler_231(); +void interrupt_handler_232(); +void interrupt_handler_233(); +void interrupt_handler_234(); +void interrupt_handler_235(); +void interrupt_handler_236(); +void interrupt_handler_237(); +void interrupt_handler_238(); +void interrupt_handler_239(); +void interrupt_handler_240(); +void interrupt_handler_241(); +void interrupt_handler_242(); +void interrupt_handler_243(); +void interrupt_handler_244(); +void interrupt_handler_245(); +void interrupt_handler_246(); +void interrupt_handler_247(); +void interrupt_handler_248(); +void interrupt_handler_249(); +void interrupt_handler_250(); +void interrupt_handler_251(); +void interrupt_handler_252(); +void interrupt_handler_253(); +void interrupt_handler_254(); +void interrupt_handler_255(); \ No newline at end of file diff --git a/asm_interrupts.s b/asm_interrupts.s new file mode 100644 index 0000000..4d1a749 --- /dev/null +++ b/asm_interrupts.s @@ -0,0 +1,1598 @@ +extern interrupt_handler ; the C interrupt handler + +global interrupt_handler_0 +interrupt_handler_0: + push dword 0 + push dword 0 + jmp common_interrupt_handler + +global interrupt_handler_1 +interrupt_handler_1: + push dword 0 + push dword 1 + jmp common_interrupt_handler + +global interrupt_handler_2 +interrupt_handler_2: + push dword 0 + push dword 2 + jmp common_interrupt_handler + +global interrupt_handler_3 +interrupt_handler_3: + push dword 0 + push dword 3 + jmp common_interrupt_handler + +global interrupt_handler_4 +interrupt_handler_4: + push dword 0 + push dword 4 + jmp common_interrupt_handler + +global interrupt_handler_5 +interrupt_handler_5: + push dword 0 + push dword 5 + jmp common_interrupt_handler + +global interrupt_handler_6 +interrupt_handler_6: + push dword 0 + push dword 6 + jmp common_interrupt_handler + +global interrupt_handler_7 +interrupt_handler_7: + push dword 0 + push dword 7 + jmp common_interrupt_handler + +global interrupt_handler_8 +interrupt_handler_8: + push dword 0 + push dword 8 + jmp common_interrupt_handler + +global interrupt_handler_9 +interrupt_handler_9: + push dword 0 + push dword 9 + jmp common_interrupt_handler + +global interrupt_handler_10 +interrupt_handler_10: + push dword 0 + push dword 10 + jmp common_interrupt_handler + +global interrupt_handler_11 +interrupt_handler_11: + push dword 0 + push dword 11 + jmp common_interrupt_handler + +global interrupt_handler_12 +interrupt_handler_12: + push dword 0 + push dword 12 + jmp common_interrupt_handler + +global interrupt_handler_13 +interrupt_handler_13: + push dword 0 + push dword 13 + jmp common_interrupt_handler + +global interrupt_handler_14 +interrupt_handler_14: + ; don't push an error code, the cpu will do that + push dword 14 + jmp common_interrupt_handler + +global interrupt_handler_15 +interrupt_handler_15: + push dword 0 + push dword 15 + jmp common_interrupt_handler + +global interrupt_handler_16 +interrupt_handler_16: + push dword 0 + push dword 16 + jmp common_interrupt_handler + +global interrupt_handler_17 +interrupt_handler_17: + push dword 0 + push dword 17 + jmp common_interrupt_handler + +global interrupt_handler_18 +interrupt_handler_18: + push dword 0 + push dword 18 + jmp common_interrupt_handler + +global interrupt_handler_19 +interrupt_handler_19: + push dword 0 + push dword 19 + jmp common_interrupt_handler + +global interrupt_handler_20 +interrupt_handler_20: + push dword 0 + push dword 20 + jmp common_interrupt_handler + +global interrupt_handler_21 +interrupt_handler_21: + push dword 0 + push dword 21 + jmp common_interrupt_handler + +global interrupt_handler_22 +interrupt_handler_22: + push dword 0 + push dword 22 + jmp common_interrupt_handler + +global interrupt_handler_23 +interrupt_handler_23: + push dword 0 + push dword 23 + jmp common_interrupt_handler + +global interrupt_handler_24 +interrupt_handler_24: + push dword 0 + push dword 24 + jmp common_interrupt_handler + +global interrupt_handler_25 +interrupt_handler_25: + push dword 0 + push dword 25 + jmp common_interrupt_handler + +global interrupt_handler_26 +interrupt_handler_26: + push dword 0 + push dword 26 + jmp common_interrupt_handler + +global interrupt_handler_27 +interrupt_handler_27: + push dword 0 + push dword 27 + jmp common_interrupt_handler + +global interrupt_handler_28 +interrupt_handler_28: + push dword 0 + push dword 28 + jmp common_interrupt_handler + +global interrupt_handler_29 +interrupt_handler_29: + push dword 0 + push dword 29 + jmp common_interrupt_handler + +global interrupt_handler_30 +interrupt_handler_30: + push dword 0 + push dword 30 + jmp common_interrupt_handler + +global interrupt_handler_31 +interrupt_handler_31: + push dword 0 + push dword 31 + jmp common_interrupt_handler + +global interrupt_handler_32 +interrupt_handler_32: + push dword 0 + push dword 32 + jmp common_interrupt_handler + +global interrupt_handler_33 +interrupt_handler_33: + push dword 0 + push dword 33 + jmp common_interrupt_handler + +global interrupt_handler_34 +interrupt_handler_34: + push dword 0 + push dword 34 + jmp common_interrupt_handler + +global interrupt_handler_35 +interrupt_handler_35: + push dword 0 + push dword 35 + jmp common_interrupt_handler + +global interrupt_handler_36 +interrupt_handler_36: + push dword 0 + push dword 36 + jmp common_interrupt_handler + +global interrupt_handler_37 +interrupt_handler_37: + push dword 0 + push dword 37 + jmp common_interrupt_handler + +global interrupt_handler_38 +interrupt_handler_38: + push dword 0 + push dword 38 + jmp common_interrupt_handler + +global interrupt_handler_39 +interrupt_handler_39: + push dword 0 + push dword 39 + jmp common_interrupt_handler + +global interrupt_handler_40 +interrupt_handler_40: + push dword 0 + push dword 40 + jmp common_interrupt_handler + +global interrupt_handler_41 +interrupt_handler_41: + push dword 0 + push dword 41 + jmp common_interrupt_handler + +global interrupt_handler_42 +interrupt_handler_42: + push dword 0 + push dword 42 + jmp common_interrupt_handler + +global interrupt_handler_43 +interrupt_handler_43: + push dword 0 + push dword 43 + jmp common_interrupt_handler + +global interrupt_handler_44 +interrupt_handler_44: + push dword 0 + push dword 44 + jmp common_interrupt_handler + +global interrupt_handler_45 +interrupt_handler_45: + push dword 0 + push dword 45 + jmp common_interrupt_handler + +global interrupt_handler_46 +interrupt_handler_46: + push dword 0 + push dword 46 + jmp common_interrupt_handler + +global interrupt_handler_47 +interrupt_handler_47: + push dword 0 + push dword 47 + jmp common_interrupt_handler + +global interrupt_handler_48 +interrupt_handler_48: + push dword 0 + push dword 48 + jmp common_interrupt_handler + +global interrupt_handler_49 +interrupt_handler_49: + push dword 0 + push dword 49 + jmp common_interrupt_handler + +global interrupt_handler_50 +interrupt_handler_50: + push dword 0 + push dword 50 + jmp common_interrupt_handler + +global interrupt_handler_51 +interrupt_handler_51: + push dword 0 + push dword 51 + jmp common_interrupt_handler + +global interrupt_handler_52 +interrupt_handler_52: + push dword 0 + push dword 52 + jmp common_interrupt_handler + +global interrupt_handler_53 +interrupt_handler_53: + push dword 0 + push dword 53 + jmp common_interrupt_handler + +global interrupt_handler_54 +interrupt_handler_54: + push dword 0 + push dword 54 + jmp common_interrupt_handler + +global interrupt_handler_55 +interrupt_handler_55: + push dword 0 + push dword 55 + jmp common_interrupt_handler + +global interrupt_handler_56 +interrupt_handler_56: + push dword 0 + push dword 56 + jmp common_interrupt_handler + +global interrupt_handler_57 +interrupt_handler_57: + push dword 0 + push dword 57 + jmp common_interrupt_handler + +global interrupt_handler_58 +interrupt_handler_58: + push dword 0 + push dword 58 + jmp common_interrupt_handler + +global interrupt_handler_59 +interrupt_handler_59: + push dword 0 + push dword 59 + jmp common_interrupt_handler + +global interrupt_handler_60 +interrupt_handler_60: + push dword 0 + push dword 60 + jmp common_interrupt_handler + +global interrupt_handler_61 +interrupt_handler_61: + push dword 0 + push dword 61 + jmp common_interrupt_handler + +global interrupt_handler_62 +interrupt_handler_62: + push dword 0 + push dword 62 + jmp common_interrupt_handler + +global interrupt_handler_63 +interrupt_handler_63: + push dword 0 + push dword 63 + jmp common_interrupt_handler + +global interrupt_handler_64 +interrupt_handler_64: + push dword 0 + push dword 64 + jmp common_interrupt_handler + +global interrupt_handler_65 +interrupt_handler_65: + push dword 0 + push dword 65 + jmp common_interrupt_handler + +global interrupt_handler_66 +interrupt_handler_66: + push dword 0 + push dword 66 + jmp common_interrupt_handler + +global interrupt_handler_67 +interrupt_handler_67: + push dword 0 + push dword 67 + jmp common_interrupt_handler + +global interrupt_handler_68 +interrupt_handler_68: + push dword 0 + push dword 68 + jmp common_interrupt_handler + +global interrupt_handler_69 +interrupt_handler_69: + push dword 0 + push dword 69 + jmp common_interrupt_handler + +global interrupt_handler_70 +interrupt_handler_70: + push dword 0 + push dword 70 + jmp common_interrupt_handler + +global interrupt_handler_71 +interrupt_handler_71: + push dword 0 + push dword 71 + jmp common_interrupt_handler + +global interrupt_handler_72 +interrupt_handler_72: + push dword 0 + push dword 72 + jmp common_interrupt_handler + +global interrupt_handler_73 +interrupt_handler_73: + push dword 0 + push dword 73 + jmp common_interrupt_handler + +global interrupt_handler_74 +interrupt_handler_74: + push dword 0 + push dword 74 + jmp common_interrupt_handler + +global interrupt_handler_75 +interrupt_handler_75: + push dword 0 + push dword 75 + jmp common_interrupt_handler + +global interrupt_handler_76 +interrupt_handler_76: + push dword 0 + push dword 76 + jmp common_interrupt_handler + +global interrupt_handler_77 +interrupt_handler_77: + push dword 0 + push dword 77 + jmp common_interrupt_handler + +global interrupt_handler_78 +interrupt_handler_78: + push dword 0 + push dword 78 + jmp common_interrupt_handler + +global interrupt_handler_79 +interrupt_handler_79: + push dword 0 + push dword 79 + jmp common_interrupt_handler + +global interrupt_handler_80 +interrupt_handler_80: + push dword 0 + push dword 80 + jmp common_interrupt_handler + +global interrupt_handler_81 +interrupt_handler_81: + push dword 0 + push dword 81 + jmp common_interrupt_handler + +global interrupt_handler_82 +interrupt_handler_82: + push dword 0 + push dword 82 + jmp common_interrupt_handler + +global interrupt_handler_83 +interrupt_handler_83: + push dword 0 + push dword 83 + jmp common_interrupt_handler + +global interrupt_handler_84 +interrupt_handler_84: + push dword 0 + push dword 84 + jmp common_interrupt_handler + +global interrupt_handler_85 +interrupt_handler_85: + push dword 0 + push dword 85 + jmp common_interrupt_handler + +global interrupt_handler_86 +interrupt_handler_86: + push dword 0 + push dword 86 + jmp common_interrupt_handler + +global interrupt_handler_87 +interrupt_handler_87: + push dword 0 + push dword 87 + jmp common_interrupt_handler + +global interrupt_handler_88 +interrupt_handler_88: + push dword 0 + push dword 88 + jmp common_interrupt_handler + +global interrupt_handler_89 +interrupt_handler_89: + push dword 0 + push dword 89 + jmp common_interrupt_handler + +global interrupt_handler_90 +interrupt_handler_90: + push dword 0 + push dword 90 + jmp common_interrupt_handler + +global interrupt_handler_91 +interrupt_handler_91: + push dword 0 + push dword 91 + jmp common_interrupt_handler + +global interrupt_handler_92 +interrupt_handler_92: + push dword 0 + push dword 92 + jmp common_interrupt_handler + +global interrupt_handler_93 +interrupt_handler_93: + push dword 0 + push dword 93 + jmp common_interrupt_handler + +global interrupt_handler_94 +interrupt_handler_94: + push dword 0 + push dword 94 + jmp common_interrupt_handler + +global interrupt_handler_95 +interrupt_handler_95: + push dword 0 + push dword 95 + jmp common_interrupt_handler + +global interrupt_handler_96 +interrupt_handler_96: + push dword 0 + push dword 96 + jmp common_interrupt_handler + +global interrupt_handler_97 +interrupt_handler_97: + push dword 0 + push dword 97 + jmp common_interrupt_handler + +global interrupt_handler_98 +interrupt_handler_98: + push dword 0 + push dword 98 + jmp common_interrupt_handler + +global interrupt_handler_99 +interrupt_handler_99: + push dword 0 + push dword 99 + jmp common_interrupt_handler + +global interrupt_handler_100 +interrupt_handler_100: + push dword 0 + push dword 100 + jmp common_interrupt_handler + +global interrupt_handler_101 +interrupt_handler_101: + push dword 0 + push dword 101 + jmp common_interrupt_handler + +global interrupt_handler_102 +interrupt_handler_102: + push dword 0 + push dword 102 + jmp common_interrupt_handler + +global interrupt_handler_103 +interrupt_handler_103: + push dword 0 + push dword 103 + jmp common_interrupt_handler + +global interrupt_handler_104 +interrupt_handler_104: + push dword 0 + push dword 104 + jmp common_interrupt_handler + +global interrupt_handler_105 +interrupt_handler_105: + push dword 0 + push dword 105 + jmp common_interrupt_handler + +global interrupt_handler_106 +interrupt_handler_106: + push dword 0 + push dword 106 + jmp common_interrupt_handler + +global interrupt_handler_107 +interrupt_handler_107: + push dword 0 + push dword 107 + jmp common_interrupt_handler + +global interrupt_handler_108 +interrupt_handler_108: + push dword 0 + push dword 108 + jmp common_interrupt_handler + +global interrupt_handler_109 +interrupt_handler_109: + push dword 0 + push dword 109 + jmp common_interrupt_handler + +global interrupt_handler_110 +interrupt_handler_110: + push dword 0 + push dword 110 + jmp common_interrupt_handler + +global interrupt_handler_111 +interrupt_handler_111: + push dword 0 + push dword 111 + jmp common_interrupt_handler + +global interrupt_handler_112 +interrupt_handler_112: + push dword 0 + push dword 112 + jmp common_interrupt_handler + +global interrupt_handler_113 +interrupt_handler_113: + push dword 0 + push dword 113 + jmp common_interrupt_handler + +global interrupt_handler_114 +interrupt_handler_114: + push dword 0 + push dword 114 + jmp common_interrupt_handler + +global interrupt_handler_115 +interrupt_handler_115: + push dword 0 + push dword 115 + jmp common_interrupt_handler + +global interrupt_handler_116 +interrupt_handler_116: + push dword 0 + push dword 116 + jmp common_interrupt_handler + +global interrupt_handler_117 +interrupt_handler_117: + push dword 0 + push dword 117 + jmp common_interrupt_handler + +global interrupt_handler_118 +interrupt_handler_118: + push dword 0 + push dword 118 + jmp common_interrupt_handler + +global interrupt_handler_119 +interrupt_handler_119: + push dword 0 + push dword 119 + jmp common_interrupt_handler + +global interrupt_handler_120 +interrupt_handler_120: + push dword 0 + push dword 120 + jmp common_interrupt_handler + +global interrupt_handler_121 +interrupt_handler_121: + push dword 0 + push dword 121 + jmp common_interrupt_handler + +global interrupt_handler_122 +interrupt_handler_122: + push dword 0 + push dword 122 + jmp common_interrupt_handler + +global interrupt_handler_123 +interrupt_handler_123: + push dword 0 + push dword 123 + jmp common_interrupt_handler + +global interrupt_handler_124 +interrupt_handler_124: + push dword 0 + push dword 124 + jmp common_interrupt_handler + +global interrupt_handler_125 +interrupt_handler_125: + push dword 0 + push dword 125 + jmp common_interrupt_handler + +global interrupt_handler_126 +interrupt_handler_126: + push dword 0 + push dword 126 + jmp common_interrupt_handler + +global interrupt_handler_127 +interrupt_handler_127: + push dword 0 + push dword 127 + jmp common_interrupt_handler + +global interrupt_handler_128 +interrupt_handler_128: + push dword 0 + push dword 128 + jmp interrupt_handler_with_return_value + +global interrupt_handler_129 +interrupt_handler_129: + push dword 0 + push dword 129 + jmp common_interrupt_handler + +global interrupt_handler_130 +interrupt_handler_130: + push dword 0 + push dword 130 + jmp common_interrupt_handler + +global interrupt_handler_131 +interrupt_handler_131: + push dword 0 + push dword 131 + jmp common_interrupt_handler + +global interrupt_handler_132 +interrupt_handler_132: + push dword 0 + push dword 132 + jmp common_interrupt_handler + +global interrupt_handler_133 +interrupt_handler_133: + push dword 0 + push dword 133 + jmp common_interrupt_handler + +global interrupt_handler_134 +interrupt_handler_134: + push dword 0 + push dword 134 + jmp common_interrupt_handler + +global interrupt_handler_135 +interrupt_handler_135: + push dword 0 + push dword 135 + jmp common_interrupt_handler + +global interrupt_handler_136 +interrupt_handler_136: + push dword 0 + push dword 136 + jmp common_interrupt_handler + +global interrupt_handler_137 +interrupt_handler_137: + push dword 0 + push dword 137 + jmp common_interrupt_handler + +global interrupt_handler_138 +interrupt_handler_138: + push dword 0 + push dword 138 + jmp common_interrupt_handler + +global interrupt_handler_139 +interrupt_handler_139: + push dword 0 + push dword 139 + jmp common_interrupt_handler + +global interrupt_handler_140 +interrupt_handler_140: + push dword 0 + push dword 140 + jmp common_interrupt_handler + +global interrupt_handler_141 +interrupt_handler_141: + push dword 0 + push dword 141 + jmp common_interrupt_handler + +global interrupt_handler_142 +interrupt_handler_142: + push dword 0 + push dword 142 + jmp common_interrupt_handler + +global interrupt_handler_143 +interrupt_handler_143: + push dword 0 + push dword 143 + jmp common_interrupt_handler + +global interrupt_handler_144 +interrupt_handler_144: + push dword 0 + push dword 144 + jmp common_interrupt_handler + +global interrupt_handler_145 +interrupt_handler_145: + push dword 0 + push dword 145 + jmp common_interrupt_handler + +global interrupt_handler_146 +interrupt_handler_146: + push dword 0 + push dword 146 + jmp common_interrupt_handler + +global interrupt_handler_147 +interrupt_handler_147: + push dword 0 + push dword 147 + jmp common_interrupt_handler + +global interrupt_handler_148 +interrupt_handler_148: + push dword 0 + push dword 148 + jmp common_interrupt_handler + +global interrupt_handler_149 +interrupt_handler_149: + push dword 0 + push dword 149 + jmp common_interrupt_handler + +global interrupt_handler_150 +interrupt_handler_150: + push dword 0 + push dword 150 + jmp common_interrupt_handler + +global interrupt_handler_151 +interrupt_handler_151: + push dword 0 + push dword 151 + jmp common_interrupt_handler + +global interrupt_handler_152 +interrupt_handler_152: + push dword 0 + push dword 152 + jmp common_interrupt_handler + +global interrupt_handler_153 +interrupt_handler_153: + push dword 0 + push dword 153 + jmp common_interrupt_handler + +global interrupt_handler_154 +interrupt_handler_154: + push dword 0 + push dword 154 + jmp common_interrupt_handler + +global interrupt_handler_155 +interrupt_handler_155: + push dword 0 + push dword 155 + jmp common_interrupt_handler + +global interrupt_handler_156 +interrupt_handler_156: + push dword 0 + push dword 156 + jmp common_interrupt_handler + +global interrupt_handler_157 +interrupt_handler_157: + push dword 0 + push dword 157 + jmp common_interrupt_handler + +global interrupt_handler_158 +interrupt_handler_158: + push dword 0 + push dword 158 + jmp common_interrupt_handler + +global interrupt_handler_159 +interrupt_handler_159: + push dword 0 + push dword 159 + jmp common_interrupt_handler + +global interrupt_handler_160 +interrupt_handler_160: + push dword 0 + push dword 160 + jmp common_interrupt_handler + +global interrupt_handler_161 +interrupt_handler_161: + push dword 0 + push dword 161 + jmp common_interrupt_handler + +global interrupt_handler_162 +interrupt_handler_162: + push dword 0 + push dword 162 + jmp common_interrupt_handler + +global interrupt_handler_163 +interrupt_handler_163: + push dword 0 + push dword 163 + jmp common_interrupt_handler + +global interrupt_handler_164 +interrupt_handler_164: + push dword 0 + push dword 164 + jmp common_interrupt_handler + +global interrupt_handler_165 +interrupt_handler_165: + push dword 0 + push dword 165 + jmp common_interrupt_handler + +global interrupt_handler_166 +interrupt_handler_166: + push dword 0 + push dword 166 + jmp common_interrupt_handler + +global interrupt_handler_167 +interrupt_handler_167: + push dword 0 + push dword 167 + jmp common_interrupt_handler + +global interrupt_handler_168 +interrupt_handler_168: + push dword 0 + push dword 168 + jmp common_interrupt_handler + +global interrupt_handler_169 +interrupt_handler_169: + push dword 0 + push dword 169 + jmp common_interrupt_handler + +global interrupt_handler_170 +interrupt_handler_170: + push dword 0 + push dword 170 + jmp common_interrupt_handler + +global interrupt_handler_171 +interrupt_handler_171: + push dword 0 + push dword 171 + jmp common_interrupt_handler + +global interrupt_handler_172 +interrupt_handler_172: + push dword 0 + push dword 172 + jmp common_interrupt_handler + +global interrupt_handler_173 +interrupt_handler_173: + push dword 0 + push dword 173 + jmp common_interrupt_handler + +global interrupt_handler_174 +interrupt_handler_174: + push dword 0 + push dword 174 + jmp common_interrupt_handler + +global interrupt_handler_175 +interrupt_handler_175: + push dword 0 + push dword 175 + jmp common_interrupt_handler + +global interrupt_handler_176 +interrupt_handler_176: + push dword 0 + push dword 176 + jmp common_interrupt_handler + +global interrupt_handler_177 +interrupt_handler_177: + push dword 0 + push dword 177 + jmp common_interrupt_handler + +global interrupt_handler_178 +interrupt_handler_178: + push dword 0 + push dword 178 + jmp common_interrupt_handler + +global interrupt_handler_179 +interrupt_handler_179: + push dword 0 + push dword 179 + jmp common_interrupt_handler + +global interrupt_handler_180 +interrupt_handler_180: + push dword 0 + push dword 180 + jmp common_interrupt_handler + +global interrupt_handler_181 +interrupt_handler_181: + push dword 0 + push dword 181 + jmp common_interrupt_handler + +global interrupt_handler_182 +interrupt_handler_182: + push dword 0 + push dword 182 + jmp common_interrupt_handler + +global interrupt_handler_183 +interrupt_handler_183: + push dword 0 + push dword 183 + jmp common_interrupt_handler + +global interrupt_handler_184 +interrupt_handler_184: + push dword 0 + push dword 184 + jmp common_interrupt_handler + +global interrupt_handler_185 +interrupt_handler_185: + push dword 0 + push dword 185 + jmp common_interrupt_handler + +global interrupt_handler_186 +interrupt_handler_186: + push dword 0 + push dword 186 + jmp common_interrupt_handler + +global interrupt_handler_187 +interrupt_handler_187: + push dword 0 + push dword 187 + jmp common_interrupt_handler + +global interrupt_handler_188 +interrupt_handler_188: + push dword 0 + push dword 188 + jmp common_interrupt_handler + +global interrupt_handler_189 +interrupt_handler_189: + push dword 0 + push dword 189 + jmp common_interrupt_handler + +global interrupt_handler_190 +interrupt_handler_190: + push dword 0 + push dword 190 + jmp common_interrupt_handler + +global interrupt_handler_191 +interrupt_handler_191: + push dword 0 + push dword 191 + jmp common_interrupt_handler + +global interrupt_handler_192 +interrupt_handler_192: + push dword 0 + push dword 192 + jmp common_interrupt_handler + +global interrupt_handler_193 +interrupt_handler_193: + push dword 0 + push dword 193 + jmp common_interrupt_handler + +global interrupt_handler_194 +interrupt_handler_194: + push dword 0 + push dword 194 + jmp common_interrupt_handler + +global interrupt_handler_195 +interrupt_handler_195: + push dword 0 + push dword 195 + jmp common_interrupt_handler + +global interrupt_handler_196 +interrupt_handler_196: + push dword 0 + push dword 196 + jmp common_interrupt_handler + +global interrupt_handler_197 +interrupt_handler_197: + push dword 0 + push dword 197 + jmp common_interrupt_handler + +global interrupt_handler_198 +interrupt_handler_198: + push dword 0 + push dword 198 + jmp common_interrupt_handler + +global interrupt_handler_199 +interrupt_handler_199: + push dword 0 + push dword 199 + jmp common_interrupt_handler + +global interrupt_handler_200 +interrupt_handler_200: + push dword 0 + push dword 200 + jmp common_interrupt_handler + +global interrupt_handler_201 +interrupt_handler_201: + push dword 0 + push dword 201 + jmp common_interrupt_handler + +global interrupt_handler_202 +interrupt_handler_202: + push dword 0 + push dword 202 + jmp common_interrupt_handler + +global interrupt_handler_203 +interrupt_handler_203: + push dword 0 + push dword 203 + jmp common_interrupt_handler + +global interrupt_handler_204 +interrupt_handler_204: + push dword 0 + push dword 204 + jmp common_interrupt_handler + +global interrupt_handler_205 +interrupt_handler_205: + push dword 0 + push dword 205 + jmp common_interrupt_handler + +global interrupt_handler_206 +interrupt_handler_206: + push dword 0 + push dword 206 + jmp common_interrupt_handler + +global interrupt_handler_207 +interrupt_handler_207: + push dword 0 + push dword 207 + jmp common_interrupt_handler + +global interrupt_handler_208 +interrupt_handler_208: + push dword 0 + push dword 208 + jmp common_interrupt_handler + +global interrupt_handler_209 +interrupt_handler_209: + push dword 0 + push dword 209 + jmp common_interrupt_handler + +global interrupt_handler_210 +interrupt_handler_210: + push dword 0 + push dword 210 + jmp common_interrupt_handler + +global interrupt_handler_211 +interrupt_handler_211: + push dword 0 + push dword 211 + jmp common_interrupt_handler + +global interrupt_handler_212 +interrupt_handler_212: + push dword 0 + push dword 212 + jmp common_interrupt_handler + +global interrupt_handler_213 +interrupt_handler_213: + push dword 0 + push dword 213 + jmp common_interrupt_handler + +global interrupt_handler_214 +interrupt_handler_214: + push dword 0 + push dword 214 + jmp common_interrupt_handler + +global interrupt_handler_215 +interrupt_handler_215: + push dword 0 + push dword 215 + jmp common_interrupt_handler + +global interrupt_handler_216 +interrupt_handler_216: + push dword 0 + push dword 216 + jmp common_interrupt_handler + +global interrupt_handler_217 +interrupt_handler_217: + push dword 0 + push dword 217 + jmp common_interrupt_handler + +global interrupt_handler_218 +interrupt_handler_218: + push dword 0 + push dword 218 + jmp common_interrupt_handler + +global interrupt_handler_219 +interrupt_handler_219: + push dword 0 + push dword 219 + jmp common_interrupt_handler + +global interrupt_handler_220 +interrupt_handler_220: + push dword 0 + push dword 220 + jmp common_interrupt_handler + +global interrupt_handler_221 +interrupt_handler_221: + push dword 0 + push dword 221 + jmp common_interrupt_handler + +global interrupt_handler_222 +interrupt_handler_222: + push dword 0 + push dword 222 + jmp common_interrupt_handler + +global interrupt_handler_223 +interrupt_handler_223: + push dword 0 + push dword 223 + jmp common_interrupt_handler + +global interrupt_handler_224 +interrupt_handler_224: + push dword 0 + push dword 224 + jmp common_interrupt_handler + +global interrupt_handler_225 +interrupt_handler_225: + push dword 0 + push dword 225 + jmp common_interrupt_handler + +global interrupt_handler_226 +interrupt_handler_226: + push dword 0 + push dword 226 + jmp common_interrupt_handler + +global interrupt_handler_227 +interrupt_handler_227: + push dword 0 + push dword 227 + jmp common_interrupt_handler + +global interrupt_handler_228 +interrupt_handler_228: + push dword 0 + push dword 228 + jmp common_interrupt_handler + +global interrupt_handler_229 +interrupt_handler_229: + push dword 0 + push dword 229 + jmp common_interrupt_handler + +global interrupt_handler_230 +interrupt_handler_230: + push dword 0 + push dword 230 + jmp common_interrupt_handler + +global interrupt_handler_231 +interrupt_handler_231: + push dword 0 + push dword 231 + jmp common_interrupt_handler + +global interrupt_handler_232 +interrupt_handler_232: + push dword 0 + push dword 232 + jmp common_interrupt_handler + +global interrupt_handler_233 +interrupt_handler_233: + push dword 0 + push dword 233 + jmp common_interrupt_handler + +global interrupt_handler_234 +interrupt_handler_234: + push dword 0 + push dword 234 + jmp common_interrupt_handler + +global interrupt_handler_235 +interrupt_handler_235: + push dword 0 + push dword 235 + jmp common_interrupt_handler + +global interrupt_handler_236 +interrupt_handler_236: + push dword 0 + push dword 236 + jmp common_interrupt_handler + +global interrupt_handler_237 +interrupt_handler_237: + push dword 0 + push dword 237 + jmp common_interrupt_handler + +global interrupt_handler_238 +interrupt_handler_238: + push dword 0 + push dword 238 + jmp common_interrupt_handler + +global interrupt_handler_239 +interrupt_handler_239: + push dword 0 + push dword 239 + jmp common_interrupt_handler + +global interrupt_handler_240 +interrupt_handler_240: + push dword 0 + push dword 240 + jmp common_interrupt_handler + +global interrupt_handler_241 +interrupt_handler_241: + push dword 0 + push dword 241 + jmp common_interrupt_handler + +global interrupt_handler_242 +interrupt_handler_242: + push dword 0 + push dword 242 + jmp common_interrupt_handler + +global interrupt_handler_243 +interrupt_handler_243: + push dword 0 + push dword 243 + jmp common_interrupt_handler + +global interrupt_handler_244 +interrupt_handler_244: + push dword 0 + push dword 244 + jmp common_interrupt_handler + +global interrupt_handler_245 +interrupt_handler_245: + push dword 0 + push dword 245 + jmp common_interrupt_handler + +global interrupt_handler_246 +interrupt_handler_246: + push dword 0 + push dword 246 + jmp common_interrupt_handler + +global interrupt_handler_247 +interrupt_handler_247: + push dword 0 + push dword 247 + jmp common_interrupt_handler + +global interrupt_handler_248 +interrupt_handler_248: + push dword 0 + push dword 248 + jmp common_interrupt_handler + +global interrupt_handler_249 +interrupt_handler_249: + push dword 0 + push dword 249 + jmp common_interrupt_handler + +global interrupt_handler_250 +interrupt_handler_250: + push dword 0 + push dword 250 + jmp common_interrupt_handler + +global interrupt_handler_251 +interrupt_handler_251: + push dword 0 + push dword 251 + jmp common_interrupt_handler + +global interrupt_handler_252 +interrupt_handler_252: + push dword 0 + push dword 252 + jmp common_interrupt_handler + +global interrupt_handler_253 +interrupt_handler_253: + push dword 0 + push dword 253 + jmp common_interrupt_handler + +global interrupt_handler_254 +interrupt_handler_254: + push dword 0 + push dword 254 + jmp common_interrupt_handler + +global interrupt_handler_255 +interrupt_handler_255: + push dword 0 + push dword 255 + jmp common_interrupt_handler + +common_interrupt_handler: ; the common parts of the generic interrupt handler + ; save the registers + push eax + push ebx + push ecx + push edx + push esi + push edi + push ebp + mov eax, cr2 + push eax + + ; call the C function + call interrupt_handler + + ; restore the registers + add esp, 4 ; cr2 + pop ebp + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + + ; pop error_code and interrupt_number off the stack + add esp, 8 + + ; return to the code that got interrupted + iret + +interrupt_handler_with_return_value: + push eax + push ebx + push ecx + push edx + push esi + push edi + push ebp + mov eax, cr2 + push eax + + ; call the C function + call interrupt_handler + + ; restore the registers + add esp, 4 ; cr2 + pop ebp + pop edi + pop esi + pop edx + pop ecx + pop ebx + ; don't pop eax. It contains the return value + + ; pop eax, error_code and interrupt_number off the stack + add esp, 12 + + ; return to the code that got interrupted + iret diff --git a/assembly_interface.h b/assembly_interface.h index 89d82b4..e133914 100644 --- a/assembly_interface.h +++ b/assembly_interface.h @@ -19,13 +19,15 @@ void outb(unsigned short port, unsigned char data); */ unsigned char inb(unsigned short port); -/** lgdt: +/** asm_lgdt: * Loads the global descriptor table * * @param gdt The address of a gdt description structure * http://wiki.osdev.org/Global_Descriptor_Table#Structure */ -void lgdt(void * gdt); +void asm_lgdt(void * gdt); + +void tss_flush(); /** load_idt: * Loads the interrupt descriptor table @@ -36,9 +38,31 @@ void load_idt(void * idt); /** interrupt: * Generates a software interrupt - * - * @param interrupt_number The number of the interrupt of generate */ -void interrupt(uint32_t interrupt_number); +void interrupt(); +void interrupt_out_of_memory(); + +/** enable_hardware_interrupts: + * Sets the Interrupt bit in the FLAGS + * register, enabling maskable + * hardware interrupts + */ +void enable_hardware_interrupts(); + +void disable_hardware_interrupts(); + +/** set_page_directory: + * Sets control register 3 to the physical address of a page directory + */ +void set_page_directory(); + +/** enable_paging: + * Sets the paging bit on control register 0 + */ +void enable_paging(); + +void* current_stack_pointer(); + +void enter_user_mode(); #endif /* INCLUDE_ASSEMBLY_INTERFACE_H */ \ No newline at end of file diff --git a/assembly_interface.s b/assembly_interface.s index 79d7a67..e5079c5 100644 --- a/assembly_interface.s +++ b/assembly_interface.s @@ -1,3 +1,6 @@ +extern USER_DATA_SEGMENT_SELECTOR +extern USER_CODE_SEGMENT_SELECTOR + global outb ; make the label outb visible outside this file ; outb - send a byte to an I/O port @@ -20,16 +23,25 @@ inb: in al, dx ; read a byte from the I/O port and store it in the al register ret -global lgdt +global asm_lgdt -; lgdt - load global descriptor table +; asm_lgdt - load global descriptor table ; stack: [esp + 4] the address of the gdt description structure ; [esp ] return address -lgdt: +asm_lgdt: mov edx, [esp + 4] lgdt [edx] ret +GLOBAL tss_flush ; Allows our C code to call tss_flush(). +tss_flush: + mov ax, 0x2B ; Load the index of our TSS structure - The index is + ; 0x28, as it is the 5th selector and each is 8 bytes + ; long, but we set the bottom two bits (making 0x2B) + ; so that it has an RPL of 3, not zero. + ltr ax ; Load 0x2B into the task state register. + ret + global load_idt ; load_idt - Loads the interrupt descriptor table (IDT). @@ -42,8 +54,66 @@ load_idt: global interrupt ; interrupt - Generates a software interrupt -; stack: [esp + 4] the software interrupt that should be generated (0-255) -; [esp ] the return address interrupt: - mov eax, [esp+4] + push ebp ; make the caller show up in the stack trace + mov ebp, esp int 49 + pop ebp + ret + +global interrupt_out_of_memory +interrupt_out_of_memory: + push ebp ; make the caller show up in the stack trace + mov ebp, esp + int 50 + pop ebp + ret + +global enable_hardware_interrupts +; enable_hardware_interrupts +enable_hardware_interrupts: + sti + ret + +global disable_hardware_interrupts +; disable_hardware_interrupts +disable_hardware_interrupts: + cli + ret + +global set_page_directory +; sets cr3 to the physical address of a page directory +; page_directory: [esp + 4] the physical address of the page directory +; [esp ] the return address +set_page_directory: + mov eax, [esp+4] + mov cr3, eax + ret + +global enable_paging +; sets the paging bit on control register 0 +enable_paging: + mov eax, cr0 + or eax, 0x80000000 + mov cr0, eax + ret + +global current_stack_pointer +current_stack_pointer: + mov eax, esp + ret + +global enter_user_mode +enter_user_mode: + mov ax,0x23 ;user data segment with bottom 2 bits set for ring 3 + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax ;we don't need to worry about SS. it's handled by iret + + push 0x23 ;user data segment with bottom 2 bits set for ring 3 + push 0xBFFFFFFB ; the user mode stack pointer + pushf ; push current eflags + push 0x1B ; user code segment with bottom 2 bits set for ring 3 + push 0x0 ; the instruction pointer of user mode code to execute + iret ; this copies values from the stack into the appropriate registers diff --git a/data_structures/global_descriptor_table.c b/data_structures/global_descriptor_table.c new file mode 100644 index 0000000..4c531af --- /dev/null +++ b/data_structures/global_descriptor_table.c @@ -0,0 +1,129 @@ +#include "global_descriptor_table.h" + +#include "../assembly_interface.h" +#include "../loader.h" +#include "../kernel_stdio.h" +#include "../memory.h" + +// A struct describing a Task State Segment. +struct tss_entry_struct +{ + uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list. + uint32_t esp0; // The stack pointer to load when we change to kernel mode. + uint32_t ss0; // The stack segment to load when we change to kernel mode. + uint32_t esp1; // everything below here is unusued now.. + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap_base; +} __packed; +typedef struct tss_entry_struct tss_entry_t; +tss_entry_t tss; + +// As described here: http://wiki.osdev.org/Global_Descriptor_Table#Structure +struct segment_descriptor_t { + uint16_t limit_0_15; // bits 0-15 of limit + uint16_t base_0_15; + uint8_t base_16_23; + uint8_t access_byte; + uint8_t flags_and_limit_16_19; + uint8_t base_24_31; +} __attribute__((packed)); + +enum segment_selector_t { + NULL_DESCRIPTOR, // Not used but has to be here + KERNAL_CODE_SEGMENT_INDEX, // Offset 0x8 + KERNAL_DATA_SEGMENT_INDEX, // Offset 0x10 + USER_CODE_SEGMENT_INDEX, // Offset 0x18 + USER_DATA_SEGMENT_INDEX, // Offset 0x20 + TASK_STATE_SEGMENT_INDEX // Offset 0x28 +}; + +const uint16_t NULL_SEGMENT_SELECTOR = 0x0; +const uint16_t KERNAL_CODE_SEGMENT_SELECTOR = sizeof(struct segment_descriptor_t) * KERNAL_CODE_SEGMENT_INDEX; +const uint16_t KERNAL_DATA_SEGMENT_SELECTOR = sizeof(struct segment_descriptor_t) * KERNAL_DATA_SEGMENT_INDEX; +const uint16_t USER_CODE_SEGMENT_SELECTOR = sizeof(struct segment_descriptor_t) * USER_CODE_SEGMENT_INDEX; +const uint16_t USER_DATA_SEGMENT_SELECTOR = sizeof(struct segment_descriptor_t) * USER_DATA_SEGMENT_INDEX; +const uint16_t TASK_STATE_SEGMENT_SELECTOR = sizeof(struct segment_descriptor_t) * TASK_STATE_SEGMENT_INDEX; + +struct segment_descriptor_t gdt[6]; + +// a pointer to the global descriptor table +// passed by reference to the LGDT instruction +struct gdt_description_structure_t { + uint16_t size; // in bytes + uint32_t offset; +} __attribute__((packed)) gdt_description_structure; + +void initialize_tss() { + uint32_t tss_base = (uint32_t) &tss; + uint32_t tss_limit = sizeof(tss); + gdt[TASK_STATE_SEGMENT_INDEX].limit_0_15 = tss_limit & 0xFFFF; + gdt[TASK_STATE_SEGMENT_INDEX].base_0_15 = tss_base & 0xFFFF; + gdt[TASK_STATE_SEGMENT_INDEX].base_16_23 = (tss_base & 0xFF0000) >> 16; + gdt[TASK_STATE_SEGMENT_INDEX].access_byte = 0b11101001; + gdt[TASK_STATE_SEGMENT_INDEX].flags_and_limit_16_19 = tss_limit & 0xF0000; + gdt[TASK_STATE_SEGMENT_INDEX].base_24_31 = (tss_base & 0xFF000000) >> 24; + + tss.ss0 = KERNAL_DATA_SEGMENT_SELECTOR; + tss.esp0 = ((uint32_t) &kernel_stack_lowest_address + KERNEL_STACK_SIZE) - 4; + + tss_flush(); +} + +void initialize_gdt() { + gdt_description_structure.size = sizeof(gdt) - 1; + gdt_description_structure.offset = (uint32_t) gdt; + + gdt[KERNAL_CODE_SEGMENT_INDEX].limit_0_15 = 0xFFFF; + gdt[KERNAL_CODE_SEGMENT_INDEX].base_0_15 = 0x0000; + gdt[KERNAL_CODE_SEGMENT_INDEX].base_16_23 = 0x00; + gdt[KERNAL_CODE_SEGMENT_INDEX].access_byte = 0b10011010; + gdt[KERNAL_CODE_SEGMENT_INDEX].flags_and_limit_16_19 = 0xCF; + gdt[KERNAL_CODE_SEGMENT_INDEX].base_24_31 = 0x00; + + gdt[KERNAL_DATA_SEGMENT_INDEX].limit_0_15 = 0xFFFF; + gdt[KERNAL_DATA_SEGMENT_INDEX].base_0_15 = 0x0000; + gdt[KERNAL_DATA_SEGMENT_INDEX].base_16_23 = 0x00; + gdt[KERNAL_DATA_SEGMENT_INDEX].access_byte = 0b10010010; + gdt[KERNAL_DATA_SEGMENT_INDEX].flags_and_limit_16_19 = 0xCF; + gdt[KERNAL_DATA_SEGMENT_INDEX].base_24_31 = 0x00; + + gdt[USER_CODE_SEGMENT_INDEX].limit_0_15 = 0xFFFF; + gdt[USER_CODE_SEGMENT_INDEX].base_0_15 = 0x0000; + gdt[USER_CODE_SEGMENT_INDEX].base_16_23 = 0x00; + gdt[USER_CODE_SEGMENT_INDEX].access_byte = 0b11111010; + gdt[USER_CODE_SEGMENT_INDEX].flags_and_limit_16_19 = 0xCF; + gdt[USER_CODE_SEGMENT_INDEX].base_24_31 = 0x00; + + gdt[USER_DATA_SEGMENT_INDEX].limit_0_15 = 0xFFFF; + gdt[USER_DATA_SEGMENT_INDEX].base_0_15 = 0x0000; + gdt[USER_DATA_SEGMENT_INDEX].base_16_23 = 0x00; + gdt[USER_DATA_SEGMENT_INDEX].access_byte = 0b11110010; + gdt[USER_DATA_SEGMENT_INDEX].flags_and_limit_16_19 = 0xCF; + gdt[USER_DATA_SEGMENT_INDEX].base_24_31 = 0x00; + + asm_lgdt(&gdt_description_structure); + + // Grub has already loaded the segment registers + // with the correct values (0x8 for cs, 0x10 for the others) +} \ No newline at end of file diff --git a/data_structures/global_descriptor_table.h b/data_structures/global_descriptor_table.h new file mode 100644 index 0000000..6cf4f73 --- /dev/null +++ b/data_structures/global_descriptor_table.h @@ -0,0 +1,13 @@ +#ifndef INCLUDE_GLOBAL_DESCRIPTOR_TABLE_H +#define INCLUDE_GLOBAL_DESCRIPTOR_TABLE_H + +#include "../types.h" + +const uint16_t NULL_SEGMENT_SELECTOR; +const uint16_t KERNAL_CODE_SEGMENT_SELECTOR; +const uint16_t KERNAL_DATA_SEGMENT_SELECTOR; + +void initialize_gdt(); +void initialize_tss(); + +#endif /* INCLUDE_GLOBAL_DESCRIPTOR_TABLE_H */ \ No newline at end of file diff --git a/data_structures/interrupt_descriptor_table.c b/data_structures/interrupt_descriptor_table.c new file mode 100644 index 0000000..66a752f --- /dev/null +++ b/data_structures/interrupt_descriptor_table.c @@ -0,0 +1,310 @@ +#include "interrupt_descriptor_table.h" + +#include "../asm_interrupts.h" +#include "../assembly_interface.h" +#include "../types.h" +#include "global_descriptor_table.h" +#include "../interrupts.h" + +// a pointer to the interrupt descriptor table +// passed by reference to the LIDT instruction +struct idt_description_structure_t { + uint16_t size; // in bytes + uint32_t offset; +} __attribute__((packed)) idt_description_structure; + +// See http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure_IA-32 +struct interrupt_descriptor_t { + uint16_t offset_0_15; + uint16_t selector; + uint8_t zero; + uint8_t type_attr; + uint16_t offset_16_31; +} __attribute__((packed)); + +struct interrupt_descriptor_t idt[256]; + +uint32_t interrupt_handler_addresses[] = { + (uint32_t) interrupt_handler_0, + (uint32_t) interrupt_handler_1, + (uint32_t) interrupt_handler_2, + (uint32_t) interrupt_handler_3, + (uint32_t) interrupt_handler_4, + (uint32_t) interrupt_handler_5, + (uint32_t) interrupt_handler_6, + (uint32_t) interrupt_handler_7, + (uint32_t) interrupt_handler_8, + (uint32_t) interrupt_handler_9, + (uint32_t) interrupt_handler_10, + (uint32_t) interrupt_handler_11, + (uint32_t) interrupt_handler_12, + (uint32_t) interrupt_handler_13, + (uint32_t) interrupt_handler_14, + (uint32_t) interrupt_handler_15, + (uint32_t) interrupt_handler_16, + (uint32_t) interrupt_handler_17, + (uint32_t) interrupt_handler_18, + (uint32_t) interrupt_handler_19, + (uint32_t) interrupt_handler_20, + (uint32_t) interrupt_handler_21, + (uint32_t) interrupt_handler_22, + (uint32_t) interrupt_handler_23, + (uint32_t) interrupt_handler_24, + (uint32_t) interrupt_handler_25, + (uint32_t) interrupt_handler_26, + (uint32_t) interrupt_handler_27, + (uint32_t) interrupt_handler_28, + (uint32_t) interrupt_handler_29, + (uint32_t) interrupt_handler_30, + (uint32_t) interrupt_handler_31, + (uint32_t) interrupt_handler_32, + (uint32_t) interrupt_handler_33, + (uint32_t) interrupt_handler_34, + (uint32_t) interrupt_handler_35, + (uint32_t) interrupt_handler_36, + (uint32_t) interrupt_handler_37, + (uint32_t) interrupt_handler_38, + (uint32_t) interrupt_handler_39, + (uint32_t) interrupt_handler_40, + (uint32_t) interrupt_handler_41, + (uint32_t) interrupt_handler_42, + (uint32_t) interrupt_handler_43, + (uint32_t) interrupt_handler_44, + (uint32_t) interrupt_handler_45, + (uint32_t) interrupt_handler_46, + (uint32_t) interrupt_handler_47, + (uint32_t) interrupt_handler_48, + (uint32_t) interrupt_handler_49, + (uint32_t) interrupt_handler_50, + (uint32_t) interrupt_handler_51, + (uint32_t) interrupt_handler_52, + (uint32_t) interrupt_handler_53, + (uint32_t) interrupt_handler_54, + (uint32_t) interrupt_handler_55, + (uint32_t) interrupt_handler_56, + (uint32_t) interrupt_handler_57, + (uint32_t) interrupt_handler_58, + (uint32_t) interrupt_handler_59, + (uint32_t) interrupt_handler_60, + (uint32_t) interrupt_handler_61, + (uint32_t) interrupt_handler_62, + (uint32_t) interrupt_handler_63, + (uint32_t) interrupt_handler_64, + (uint32_t) interrupt_handler_65, + (uint32_t) interrupt_handler_66, + (uint32_t) interrupt_handler_67, + (uint32_t) interrupt_handler_68, + (uint32_t) interrupt_handler_69, + (uint32_t) interrupt_handler_70, + (uint32_t) interrupt_handler_71, + (uint32_t) interrupt_handler_72, + (uint32_t) interrupt_handler_73, + (uint32_t) interrupt_handler_74, + (uint32_t) interrupt_handler_75, + (uint32_t) interrupt_handler_76, + (uint32_t) interrupt_handler_77, + (uint32_t) interrupt_handler_78, + (uint32_t) interrupt_handler_79, + (uint32_t) interrupt_handler_80, + (uint32_t) interrupt_handler_81, + (uint32_t) interrupt_handler_82, + (uint32_t) interrupt_handler_83, + (uint32_t) interrupt_handler_84, + (uint32_t) interrupt_handler_85, + (uint32_t) interrupt_handler_86, + (uint32_t) interrupt_handler_87, + (uint32_t) interrupt_handler_88, + (uint32_t) interrupt_handler_89, + (uint32_t) interrupt_handler_90, + (uint32_t) interrupt_handler_91, + (uint32_t) interrupt_handler_92, + (uint32_t) interrupt_handler_93, + (uint32_t) interrupt_handler_94, + (uint32_t) interrupt_handler_95, + (uint32_t) interrupt_handler_96, + (uint32_t) interrupt_handler_97, + (uint32_t) interrupt_handler_98, + (uint32_t) interrupt_handler_99, + (uint32_t) interrupt_handler_100, + (uint32_t) interrupt_handler_101, + (uint32_t) interrupt_handler_102, + (uint32_t) interrupt_handler_103, + (uint32_t) interrupt_handler_104, + (uint32_t) interrupt_handler_105, + (uint32_t) interrupt_handler_106, + (uint32_t) interrupt_handler_107, + (uint32_t) interrupt_handler_108, + (uint32_t) interrupt_handler_109, + (uint32_t) interrupt_handler_110, + (uint32_t) interrupt_handler_111, + (uint32_t) interrupt_handler_112, + (uint32_t) interrupt_handler_113, + (uint32_t) interrupt_handler_114, + (uint32_t) interrupt_handler_115, + (uint32_t) interrupt_handler_116, + (uint32_t) interrupt_handler_117, + (uint32_t) interrupt_handler_118, + (uint32_t) interrupt_handler_119, + (uint32_t) interrupt_handler_120, + (uint32_t) interrupt_handler_121, + (uint32_t) interrupt_handler_122, + (uint32_t) interrupt_handler_123, + (uint32_t) interrupt_handler_124, + (uint32_t) interrupt_handler_125, + (uint32_t) interrupt_handler_126, + (uint32_t) interrupt_handler_127, + (uint32_t) interrupt_handler_128, + (uint32_t) interrupt_handler_129, + (uint32_t) interrupt_handler_130, + (uint32_t) interrupt_handler_131, + (uint32_t) interrupt_handler_132, + (uint32_t) interrupt_handler_133, + (uint32_t) interrupt_handler_134, + (uint32_t) interrupt_handler_135, + (uint32_t) interrupt_handler_136, + (uint32_t) interrupt_handler_137, + (uint32_t) interrupt_handler_138, + (uint32_t) interrupt_handler_139, + (uint32_t) interrupt_handler_140, + (uint32_t) interrupt_handler_141, + (uint32_t) interrupt_handler_142, + (uint32_t) interrupt_handler_143, + (uint32_t) interrupt_handler_144, + (uint32_t) interrupt_handler_145, + (uint32_t) interrupt_handler_146, + (uint32_t) interrupt_handler_147, + (uint32_t) interrupt_handler_148, + (uint32_t) interrupt_handler_149, + (uint32_t) interrupt_handler_150, + (uint32_t) interrupt_handler_151, + (uint32_t) interrupt_handler_152, + (uint32_t) interrupt_handler_153, + (uint32_t) interrupt_handler_154, + (uint32_t) interrupt_handler_155, + (uint32_t) interrupt_handler_156, + (uint32_t) interrupt_handler_157, + (uint32_t) interrupt_handler_158, + (uint32_t) interrupt_handler_159, + (uint32_t) interrupt_handler_160, + (uint32_t) interrupt_handler_161, + (uint32_t) interrupt_handler_162, + (uint32_t) interrupt_handler_163, + (uint32_t) interrupt_handler_164, + (uint32_t) interrupt_handler_165, + (uint32_t) interrupt_handler_166, + (uint32_t) interrupt_handler_167, + (uint32_t) interrupt_handler_168, + (uint32_t) interrupt_handler_169, + (uint32_t) interrupt_handler_170, + (uint32_t) interrupt_handler_171, + (uint32_t) interrupt_handler_172, + (uint32_t) interrupt_handler_173, + (uint32_t) interrupt_handler_174, + (uint32_t) interrupt_handler_175, + (uint32_t) interrupt_handler_176, + (uint32_t) interrupt_handler_177, + (uint32_t) interrupt_handler_178, + (uint32_t) interrupt_handler_179, + (uint32_t) interrupt_handler_180, + (uint32_t) interrupt_handler_181, + (uint32_t) interrupt_handler_182, + (uint32_t) interrupt_handler_183, + (uint32_t) interrupt_handler_184, + (uint32_t) interrupt_handler_185, + (uint32_t) interrupt_handler_186, + (uint32_t) interrupt_handler_187, + (uint32_t) interrupt_handler_188, + (uint32_t) interrupt_handler_189, + (uint32_t) interrupt_handler_190, + (uint32_t) interrupt_handler_191, + (uint32_t) interrupt_handler_192, + (uint32_t) interrupt_handler_193, + (uint32_t) interrupt_handler_194, + (uint32_t) interrupt_handler_195, + (uint32_t) interrupt_handler_196, + (uint32_t) interrupt_handler_197, + (uint32_t) interrupt_handler_198, + (uint32_t) interrupt_handler_199, + (uint32_t) interrupt_handler_200, + (uint32_t) interrupt_handler_201, + (uint32_t) interrupt_handler_202, + (uint32_t) interrupt_handler_203, + (uint32_t) interrupt_handler_204, + (uint32_t) interrupt_handler_205, + (uint32_t) interrupt_handler_206, + (uint32_t) interrupt_handler_207, + (uint32_t) interrupt_handler_208, + (uint32_t) interrupt_handler_209, + (uint32_t) interrupt_handler_210, + (uint32_t) interrupt_handler_211, + (uint32_t) interrupt_handler_212, + (uint32_t) interrupt_handler_213, + (uint32_t) interrupt_handler_214, + (uint32_t) interrupt_handler_215, + (uint32_t) interrupt_handler_216, + (uint32_t) interrupt_handler_217, + (uint32_t) interrupt_handler_218, + (uint32_t) interrupt_handler_219, + (uint32_t) interrupt_handler_220, + (uint32_t) interrupt_handler_221, + (uint32_t) interrupt_handler_222, + (uint32_t) interrupt_handler_223, + (uint32_t) interrupt_handler_224, + (uint32_t) interrupt_handler_225, + (uint32_t) interrupt_handler_226, + (uint32_t) interrupt_handler_227, + (uint32_t) interrupt_handler_228, + (uint32_t) interrupt_handler_229, + (uint32_t) interrupt_handler_230, + (uint32_t) interrupt_handler_231, + (uint32_t) interrupt_handler_232, + (uint32_t) interrupt_handler_233, + (uint32_t) interrupt_handler_234, + (uint32_t) interrupt_handler_235, + (uint32_t) interrupt_handler_236, + (uint32_t) interrupt_handler_237, + (uint32_t) interrupt_handler_238, + (uint32_t) interrupt_handler_239, + (uint32_t) interrupt_handler_240, + (uint32_t) interrupt_handler_241, + (uint32_t) interrupt_handler_242, + (uint32_t) interrupt_handler_243, + (uint32_t) interrupt_handler_244, + (uint32_t) interrupt_handler_245, + (uint32_t) interrupt_handler_246, + (uint32_t) interrupt_handler_247, + (uint32_t) interrupt_handler_248, + (uint32_t) interrupt_handler_249, + (uint32_t) interrupt_handler_250, + (uint32_t) interrupt_handler_251, + (uint32_t) interrupt_handler_252, + (uint32_t) interrupt_handler_253, + (uint32_t) interrupt_handler_254, + (uint32_t) interrupt_handler_255, +}; + +void initialize_idt() { + idt_description_structure.size = sizeof(idt) - 1; + idt_description_structure.offset = (uint32_t) idt; + + uint16_t selector = KERNAL_CODE_SEGMENT_SELECTOR; + uint8_t zero = 0x00; + uint8_t type_attr = 0b10001110; + uint8_t user_type_attr = 0b11101110; + + for (int i = 0; i < 256; i++) { + uint32_t interrupt_handler_address = interrupt_handler_addresses[i]; + uint16_t offset_0_15 = interrupt_handler_address & 0x0000FFFF; + uint16_t offset_16_31 = interrupt_handler_address >> 16; + + idt[i].offset_0_15 = offset_0_15; + idt[i].selector = selector; + idt[i].zero = zero; + idt[i].type_attr = type_attr; + idt[i].offset_16_31 = offset_16_31; + } + + idt[INT_SYSCALL].type_attr = user_type_attr; + + load_idt(&idt_description_structure); +} \ No newline at end of file diff --git a/data_structures/interrupt_descriptor_table.h b/data_structures/interrupt_descriptor_table.h new file mode 100644 index 0000000..f096b6a --- /dev/null +++ b/data_structures/interrupt_descriptor_table.h @@ -0,0 +1,6 @@ +#ifndef INCLUDE_INTERRUPT_DESCRIPTOR_TABLE_H +#define INCLUDE_INTERRUPT_DESCRIPTOR_TABLE_H + +void initialize_idt(); + +#endif /* INCLUDE_INTERRUPT_DESCRIPTOR_TABLE_H */ \ No newline at end of file diff --git a/data_structures/page_table.c b/data_structures/page_table.c new file mode 100644 index 0000000..73797d8 --- /dev/null +++ b/data_structures/page_table.c @@ -0,0 +1,335 @@ +#include "page_table.h" + +#include "../loader.h" +#include "../memory.h" +#include "../multiboot_utils.h" + +#define PAGE_DIRECTORY_OFFSET_BITS 10 +#define PAGE_TABLE_OFFSET_BITS 10 +#define PAGE_OFFSET_BITS 12 + +#define PAGE_SIZE_BYTES 4096 +#define PAGE_SIZE_DWORDS 1024 + +#define KERNEL_PAGE_TABLE_NUMBER 768 + +// #define BITMAP_SIZE 32768 +// Enough room for 512 MB of RAM +// TODO: Find a more efficient way to initialize page allocator +#define BITMAP_SIZE 4096 + +uint32_t free_pages; +uint32_t free_page_bitmap[BITMAP_SIZE]; + +void mark_free(uint32_t page_number); +void mark_unavailable(uint32_t page_number); +uint32_t page_number(uint32_t address); + +uint32_t make_page_directory_entry( + void* page_table_physical_address, + enum page_size_t page_size, + bool cache_disabled, + bool write_through, + enum page_privilege_t privelage, + enum page_permissions_t permissions, + bool present +) { + uint32_t entry = (uint32_t) page_table_physical_address; + entry |= page_size << 7; + entry |= cache_disabled << 4; + entry |= write_through << 3; + entry |= privelage << 2; + entry |= permissions << 1; + entry |= present; + + return entry; +} + +bool get_present_from_pde(uint32_t pde) { + return (pde & 0b1); +} + +uint32_t make_page_table_entry( + void* page_frame_address, + bool global, + bool cache_disabled, + bool write_through, + enum page_privilege_t privelage, + enum page_permissions_t permissions, + bool present +) { + uint32_t entry = (uint32_t) page_frame_address; + entry |= global << 8; + entry |= cache_disabled << 6; + entry |= write_through << 3; + entry |= privelage << 2; + entry |= permissions << 1; + entry |= present; + + return entry; +} + +bool get_present_from_pte(uint32_t pte) { + return (pte & 0b1); +} + +// 1 page = 1024 * 4 bytes = 4 kB +// 1 page table = 1024 pages = 4 mB +// 1 page directory = 1024 page tables = 4 gB + +// Find a free physical page and return it's physical address +// This does NOT zero out the page +void* allocate_physical_page() { + for (uint32_t index = 0; index < BITMAP_SIZE; index++) { + if (free_page_bitmap[index] != 0) { + // There is at least one free page in this chunk + for (uint8_t bit = 0; bit < 32; bit++) { + if ((free_page_bitmap[index] & (1 << bit)) != 0) { + uint32_t page_number = index * 32 + bit; + mark_unavailable(page_number); + void* page_start = (void*) (page_number << PAGE_OFFSET_BITS); + return page_start; + } + } + } + } + + // Out of physical memory + // TODO: Evict a page + return 0; +} + +// Assumes we are using recursive page tables. +// Last entry in page directory points to itself +void* page_table_virtual_address(uint16_t page_table_number) { + // First 10 bits are set to 1 + uint32_t virtual_address = 0xFFC00000; + + // Next 10 bits index index into page directory + virtual_address |= (page_table_number << PAGE_OFFSET_BITS); + + return (void*) virtual_address; +} + +page_directory_t initialize_kernel_page_directory() { + page_directory_t pd = (page_directory_t) &PageDirectoryVirtualAddress; + + // Make the last entry in the pd a pointer to itself + uint32_t pde = make_page_directory_entry( + (void*) &PageDirectoryPhysicalAddress, + FOUR_KB, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + pd[1023] = pde; + + // dedicate one page table for memory for the kernel + void* page_table_physical_address = allocate_physical_page(); + pd[KERNEL_PAGE_TABLE_NUMBER] = make_page_directory_entry( + page_table_physical_address, + FOUR_KB, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + + // From here on out, we can access page tables with `page_table_virtual_address()` + // Fill in the kernel page table entirely. + // Map the kernel's 4MB to the first 4MB of physical memory + page_table_t pt = (page_table_t) page_table_virtual_address(KERNEL_PAGE_TABLE_NUMBER); + for (uint16_t i = 0; i < 1024; i++) { + void* page_physical_address = (void*) (i * PAGE_SIZE_BYTES); + pt[i] = make_page_table_entry( + page_physical_address, + false, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + } + + return pd; +} + +uint32_t num_present_pages(page_directory_t pd) { + uint32_t num = 0; + for (int i = 0; i < 1024; i++) { + uint32_t entry = pd[i]; + bool present = entry & 0x1; + + if (present) { + num += 1; + } + } + return num; +} + +uint32_t round_up_to_nearest_page_start(uint32_t address) { + if ((address & 0xFFFFF000) != address) { + address &= 0xFFFFF000; + address += 0x00001000; + } + + return address; +} + +uint32_t round_down_to_nearest_page_start(uint32_t address) { + return address & 0xFFFFF000; +} + +uint32_t page_number(uint32_t address) { + return address >> PAGE_OFFSET_BITS; +} + +void mark_free(uint32_t page_number) { + uint32_t index = page_number >> 5; + uint32_t bit = page_number & 0b11111; + uint32_t value = free_page_bitmap[index]; + + if ((value & (1 << bit)) == 0) { + // Page was not free before. Update statistics. + free_pages++; + } + + value |= (1 << bit); + free_page_bitmap[index] = value; +} + +void mark_unavailable(uint32_t physical_page_number) { + uint32_t index = physical_page_number >> 5; + uint32_t bit = physical_page_number & 0b11111; + + uint32_t value = free_page_bitmap[index]; + + if ((value & (1 << bit)) == 1) { + // Page was free. Update statistics. + free_pages--; + } + + value &= ~(1 << bit); + free_page_bitmap[index] = value; +} + +uint32_t initialize_page_allocator(struct kernel_memory_descriptor_t kernel_memory, multiboot_info_t* mbinfo) { + memory_map_t * memory_map = (memory_map_t *) p_to_v(mbinfo->mmap_addr); + uint32_t num_entries = mbinfo->mmap_length / sizeof(memory_map_t); + + // Mark physical pages as free according to memory map passed by GRUB + for (uint32_t i = 0; i < num_entries; i++) { + if (memory_map[i].type == 1) { + // Available + uint32_t first_addr = memory_map[i].base_addr_low; + uint32_t one_past_last_addr = first_addr + memory_map[i].length_low; + uint32_t first_full_page = page_number(round_up_to_nearest_page_start(first_addr)); + uint32_t one_past_last_full_page = page_number(round_down_to_nearest_page_start(one_past_last_addr)); + + for(uint32_t i = first_full_page; i < one_past_last_full_page; i++) { + if (i > PAGE_SIZE_DWORDS) { // First 4MB are where the kernel lives + mark_free(i); + } + } + } else { + // Unavailable + // Not currently keeping track of these regions + } + } + + // Mark physical pages as unavailable where kernel code is loaded + uint32_t first_partial_page = page_number(round_down_to_nearest_page_start(kernel_memory.kernel_physical_start)); + uint32_t one_past_last_partial_page = page_number(round_up_to_nearest_page_start(kernel_memory.kernel_physical_end)); + + for(uint32_t i = first_partial_page; i < one_past_last_partial_page; i++) { + mark_unavailable(i); + } + + return free_pages; +} + +void page_in(const void* virtual_address) { + uint32_t pd_offset = page_directory_offset(virtual_address); + page_directory_t pd = (page_directory_t) PAGE_DIRECTORY_ADDRESS; + uint32_t pde = pd[pd_offset]; + + if (!get_present_from_pde(pde)) { + // Allocate a physical page to hold the page table + void* page_table_physical_address = allocate_physical_page(); + + pde = make_page_directory_entry( + page_table_physical_address, + FOUR_KB, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + pd[pd_offset] = pde; + } + + page_table_t pt = (page_table_t) page_table_virtual_address(pd_offset); + uint32_t pt_offset = page_table_offset(virtual_address); + uint32_t pte = pt[pt_offset]; + + if (!get_present_from_pte(pte)) { + // Allocate a physical page to hold the virtual page + void* page_physical_address = allocate_physical_page(); + + pte = make_page_table_entry( + page_physical_address, + false, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + pt[pt_offset] = pte; + } +} + +uint32_t page_directory_offset(const void* virtual_address) { + return ((uint32_t) virtual_address) >> PAGE_OFFSET_BITS >> PAGE_TABLE_OFFSET_BITS; +} + +uint32_t page_table_offset(const void* virtual_address) { + return (((uint32_t) virtual_address) >> PAGE_OFFSET_BITS) & 0x3FF; +} + +uint32_t page_offset(const void* addr) { + return ((uint32_t) addr & 0x00000FFF); +} + +void* virtual_to_physical(const void* addr) { + uint32_t pd_offset = page_directory_offset(addr); + uint32_t pt_offset = page_table_offset(addr); + uint32_t p_offset = page_offset(addr); + + uint32_t* page_table_addr = (uint32_t*) (FIRST_PAGE_TABLE_ADDRESS + (PAGE_SIZE_BYTES * pd_offset)); + uint32_t page_table_entry = page_table_addr[pt_offset]; + + uint32_t physical_address = ((page_table_entry >> 12) << 12) | p_offset; + + return (void*) physical_address; +} + +void print_page_table(FILE file, const uint32_t* pt) { + fprintf(file, "---\n"); + for (uint32_t i = 0; i < PAGE_SIZE_DWORDS; i++) { + if (get_present_from_pte(pt[i])) { + fprintf(file, "%x -> %x\n", i, pt[i] & (uint32_t) PAGE_DIRECTORY_ADDRESS); + } + } + fprintf(file, "---\n"); +} + +void map_kernel_into_page_directory(page_directory_t new_pd) { + page_directory_t pd = (page_directory_t) PAGE_DIRECTORY_ADDRESS; + new_pd[KERNEL_PAGE_TABLE_NUMBER] = pd[KERNEL_PAGE_TABLE_NUMBER]; +} diff --git a/data_structures/page_table.h b/data_structures/page_table.h new file mode 100644 index 0000000..91f760f --- /dev/null +++ b/data_structures/page_table.h @@ -0,0 +1,53 @@ +#ifndef INCLUDE_PAGE_TABLE_H +#define INCLUDE_PAGE_TABLE_H + +#include "../multiboot.h" +#include "../kernel_stdio.h" +#include "../types.h" + +struct kernel_memory_descriptor_t { + uint32_t kernel_virtual_start; + uint32_t kernel_virtual_end; + uint32_t kernel_physical_start; + uint32_t kernel_physical_end; +}; + +typedef uint32_t * page_directory_t; +typedef uint32_t * page_table_t; + +enum page_permissions_t {READ_ONLY, READ_WRITE}; +enum page_privilege_t {SUPERVISOR, USER}; +enum page_size_t {FOUR_KB, FOUR_MB}; + +void map_kernel_into_page_directory(page_directory_t new_pd); +page_directory_t initialize_kernel_page_directory(); +uint32_t initialize_page_allocator( + struct kernel_memory_descriptor_t kernel_memory, + multiboot_info_t* mbinfo + ); +uint32_t make_page_directory_entry( + void* page_table_physical_address, + enum page_size_t page_size, + bool cache_disabled, + bool write_through, + enum page_privilege_t privelage, + enum page_permissions_t permissions, + bool present + ); +uint32_t make_page_table_entry( + void* page_frame_address, + bool global, + bool cache_disabled, + bool write_through, + enum page_privilege_t privelage, + enum page_permissions_t permissions, + bool present + ); +uint32_t num_present_pages(page_directory_t pd); +uint32_t page_directory_offset(const void* virtual_address); +void page_in(const void* virtual_address); +uint32_t page_table_offset(const void* virtual_address); +void print_page_table(FILE file, const uint32_t*); +void* virtual_to_physical(const void* addr); + +#endif /* INCLUDE_PAGE_TABLE_H */ \ No newline at end of file diff --git a/data_structures/symbol_table.c b/data_structures/symbol_table.c new file mode 100644 index 0000000..ce6ef27 --- /dev/null +++ b/data_structures/symbol_table.c @@ -0,0 +1,51 @@ +#include "symbol_table.h" + +#include "../loader.h" +#include "../multiboot_utils.h" +#include "../kernel_stdio.h" + +struct symbol_table_descriptor_t { + bool present; + uint32_t num_symbols; + Elf32_Sym * symbols; + char * string_table_addr; +}; + +struct symbol_table_descriptor_t symbol_table_descriptor; + +bool load_symbol_table(struct elf_section_header_t * symbol_table_section, struct elf_section_header_t * string_table_section) { + if (symbol_table_section == 0) { + symbol_table_descriptor.present = false; + return false; + } else { + symbol_table_descriptor.present = true; + symbol_table_descriptor.num_symbols = symbol_table_section->sh_size / sizeof(Elf32_Sym); + symbol_table_descriptor.symbols = (Elf32_Sym *) p_to_v(symbol_table_section->sh_addr); + symbol_table_descriptor.string_table_addr = (char*) p_to_v(string_table_section->sh_addr); + return true; + } +} + +char * address_to_symbol_name(uint32_t address) { + // Algorithm : Find symbol with greatest value <= address + + Elf32_Sym * symbol = 0; + uint32_t symbol_value = 0; + + if (symbol_table_descriptor.present) { + for (uint32_t i = 0; i < symbol_table_descriptor.num_symbols; i++) { + Elf32_Sym * candidate = symbol_table_descriptor.symbols + i; + if (candidate->st_value > symbol_value && candidate->st_value <= address) { + symbol = candidate; + symbol_value = candidate->st_value; + } + } + + uint32_t string_index = symbol->st_name; + char * name = symbol_table_descriptor.string_table_addr + string_index; + + return name; + } + + return 0; +} \ No newline at end of file diff --git a/data_structures/symbol_table.h b/data_structures/symbol_table.h new file mode 100644 index 0000000..a82904d --- /dev/null +++ b/data_structures/symbol_table.h @@ -0,0 +1,12 @@ +#ifndef INCLUDE_SYMBOL_TABLE_H +#define INCLUDE_SYMBOL_TABLE_H + +#include "../types.h" +#include "../elf.h" + +struct symbol_table_descriptor_t; + +bool load_symbol_table(struct elf_section_header_t * symbol_table_section, struct elf_section_header_t * string_table_section); +char * address_to_symbol_name(uint32_t address); + +#endif /* INCLUDE_SYMBOL_TABLE_H */ \ No newline at end of file diff --git a/drivers/frame_buffer.c b/drivers/frame_buffer.c index c23bc53..457b8a8 100644 --- a/drivers/frame_buffer.c +++ b/drivers/frame_buffer.c @@ -3,6 +3,7 @@ #include "frame_buffer.h" #include "../assembly_interface.h" +#include "../kernel_stdio.h" /* The I/O ports */ #define FB_COMMAND_PORT 0x3D4 @@ -13,7 +14,11 @@ #define FB_LOW_BYTE_COMMAND 15 // Start of memory that maps to the frame buffer -char *fb = (char *) 0x000B8000; +char *fb = (char *) 0xC00B8000; + +uint16_t cursor_pos = 0; + +uint8_t buffer[FB_CELLS*2]; /** fb_write_cell: * Writes a character with the given foreground and background to position i @@ -27,22 +32,30 @@ char *fb = (char *) 0x000B8000; void fb_write_cell(unsigned int cell, char c, unsigned char fg, unsigned char bg) { int i = cell*2; - fb[i] = c; - fb[i + 1] = ((bg & 0x0F) << 4) | (fg & 0x0F); + buffer[i] = fb[i] = c; + + buffer[i+1] = fb[i + 1] = ((bg & 0x0F) << 4) | (fg & 0x0F); } -void clear_screen() +void scroll() { - for (int i = 0; i < FB_CELLS; i++) { - fb_write_cell(i, ' ', FB_BLACK, FB_BLACK); + uint32_t num_cells_to_copy = FB_CELLS - FB_COLS; + for (uint32_t cell = 0; cell < num_cells_to_copy; cell++) { + int i = cell*2; + buffer[i] = fb[i] = buffer[i+FB_COLS*2]; + buffer[i+1] = fb[i+1] = buffer[i+1+FB_COLS*2]; + } + uint32_t bytes_per_row = FB_COLS*2; + uint32_t last_byte_index = FB_CELLS*2 - 1; + for (uint32_t i = 0; i < bytes_per_row; i++) { + buffer[last_byte_index - i] = fb[last_byte_index - i] = 0; } } -void fb_write(char * s) { - int i = 0; - while (s[i]) { - fb_write_cell(i, s[i], FB_WHITE, FB_BLACK); - i++; +void clear_screen() +{ + for (int i = 0; i < FB_CELLS; i++) { + fb_write_cell(i, ' ', FB_BLACK, FB_BLACK); } } @@ -59,6 +72,35 @@ void move_cursor_to_pos(unsigned short pos) outb(FB_DATA_PORT, pos & 0x00FF); } -void move_cursor(unsigned short row, unsigned short col) { - move_cursor_to_pos(row*FB_COLS + col); -} \ No newline at end of file +uint16_t beginning_of_line(uint16_t pos) { + return pos / FB_COLS * FB_COLS; +} + +uint16_t beginning_of_next_line(uint16_t pos) { + return beginning_of_line(pos + FB_COLS); +} + +void fb_write_byte(uint8_t b) { + if (b == '\n') { + cursor_pos = beginning_of_next_line(cursor_pos); + while (cursor_pos >= FB_CELLS) { + scroll(); + cursor_pos -= FB_COLS; + } + move_cursor_to_pos(cursor_pos); + } else { + fb_write_cell(cursor_pos, b, FB_WHITE, FB_BLACK); + cursor_pos++; + if (cursor_pos == FB_CELLS) { + scroll(); + cursor_pos -= FB_COLS; + } + } + move_cursor_to_pos(cursor_pos); +} + +void fb_backspace() { + cursor_pos--; + fb_write_cell(cursor_pos, ' ', FB_WHITE, FB_BLACK); + move_cursor_to_pos(cursor_pos); +} diff --git a/drivers/frame_buffer.h b/drivers/frame_buffer.h index c98f5d9..1920dc2 100644 --- a/drivers/frame_buffer.h +++ b/drivers/frame_buffer.h @@ -1,6 +1,8 @@ #ifndef INCLUDE_FRAME_BUFFER_H #define INCLUDE_FRAME_BUFFER_H +#include "../types.h" + #define FB_COLS 80 #define FB_ROWS 25 #define FB_CELLS FB_COLS * FB_ROWS @@ -23,7 +25,7 @@ #define FB_WHITE 15 void clear_screen(); -void fb_write(char * s); -void move_cursor(unsigned short row, unsigned short col); +void fb_backspace(); +void fb_write_byte(uint8_t b); #endif /* INCLUDE_FRAME_BUFFER_H */ \ No newline at end of file diff --git a/drivers/keyboard.c b/drivers/keyboard.c new file mode 100644 index 0000000..4caecc7 --- /dev/null +++ b/drivers/keyboard.c @@ -0,0 +1,352 @@ +#include "keyboard.h" + +#include "frame_buffer.h" +#include "../assembly_interface.h" +#include "../kernel_stdio.h" +#include "../types.h" + +#define KBD_DATA_PORT 0x60 + +#define BACKSPACE 0x0E +#define LSHIFT 0x2A +#define RSHIFT 0x36 + +char normal_scan_code_table[128] = { + 0, // 0x00 + 0, // 0x01 + '1', // 0x02 + '2', // 0x03 + '3', // 0x04 + '4', // 0x05 + '5', // 0x06 + '6', // 0x07 + '7', // 0x08 + '8', // 0x09 + '9', // 0x0a + '0', // 0x0b + '-', // 0x0c + '=', // 0x0d + 0, // 0x0e + 0, // 0x0f + 'q', // 0x10 + 'w', // 0x11 + 'e', // 0x12 + 'r', // 0x13 + 't', // 0x14 + 'y', // 0x15 + 'u', // 0x16 + 'i', // 0x17 + 'o', // 0x18 + 'p', // 0x19 + '[', // 0x1a + ']', // 0x1b + '\n', // 0x1c + 0, // 0x1d + 'a', // 0x1e + 's', // 0x1f + 'd', // 0x20 + 'f', // 0x21 + 'g', // 0x22 + 'h', // 0x23 + 'j', // 0x24 + 'k', // 0x25 + 'l', // 0x26 + ';', // 0x27 + '\'', // 0x28 + '`', // 0x29 + 0, // 0x2a + '\\', // 0x2b + 'z', // 0x2c + 'x', // 0x2d + 'c', // 0x2e + 'v', // 0x2f + 'b', // 0x30 + 'n', // 0x31 + 'm', // 0x32 + ',', // 0x33 + '.', // 0x34 + '/', // 0x35 + 0, // 0x36 + 0, // 0x37 + 0, // 0x38 + ' ', // 0x39 + 0, // 0x3a + 0, // 0x3b + 0, // 0x3c + 0, // 0x3d + 0, // 0x3e + 0, // 0x3f + 0, // 0x40 + 0, // 0x41 + 0, // 0x42 + 0, // 0x43 + 0, // 0x44 + 0, // 0x45 + 0, // 0x46 + 0, // 0x47 + 0, // 0x48 + 0, // 0x49 + 0, // 0x4a + 0, // 0x4b + 0, // 0x4c + 0, // 0x4d + 0, // 0x4e + 0, // 0x4f + 0, // 0x50 + 0, // 0x51 + 0, // 0x52 + 0, // 0x53 + 0, // 0x54 + 0, // 0x55 + 0, // 0x56 + 0, // 0x57 + 0, // 0x58 + 0, // 0x59 + 0, // 0x5a + 0, // 0x5b + 0, // 0x5c + 0, // 0x5d + 0, // 0x5e + 0, // 0x5f + 0, // 0x60 + 0, // 0x61 + 0, // 0x62 + 0, // 0x63 + 0, // 0x64 + 0, // 0x65 + 0, // 0x66 + 0, // 0x67 + 0, // 0x68 + 0, // 0x69 + 0, // 0x6a + 0, // 0x6b + 0, // 0x6c + 0, // 0x6d + 0, // 0x6e + 0, // 0x6f + 0, // 0x70 + 0, // 0x71 + 0, // 0x72 + 0, // 0x73 + 0, // 0x74 + 0, // 0x75 + 0, // 0x76 + 0, // 0x77 + 0, // 0x78 + 0, // 0x79 + 0, // 0x7a + 0, // 0x7b + 0, // 0x7c + 0, // 0x7d + 0, // 0x7e + 0, // 0x7f +}; + +char shift_scan_code_table[128] = { + 0, // 0x00 + 0, // 0x01 + '!', // 0x02 + '@', // 0x03 + '#', // 0x04 + '$', // 0x05 + '%', // 0x06 + '^', // 0x07 + '&', // 0x08 + '*', // 0x09 + '(', // 0x0a + ')', // 0x0b + '_', // 0x0c + '+', // 0x0d + 0, // 0x0e + 0, // 0x0f + 'Q', // 0x10 + 'W', // 0x11 + 'E', // 0x12 + 'R', // 0x13 + 'T', // 0x14 + 'Y', // 0x15 + 'U', // 0x16 + 'I', // 0x17 + 'O', // 0x18 + 'P', // 0x19 + '{', // 0x1a + '}', // 0x1b + '\n', // 0x1c + 0, // 0x1d + 'A', // 0x1e + 'S', // 0x1f + 'D', // 0x20 + 'F', // 0x21 + 'G', // 0x22 + 'H', // 0x23 + 'J', // 0x24 + 'K', // 0x25 + 'L', // 0x26 + ':', // 0x27 + '"', // 0x28 + '~', // 0x29 + 0, // 0x2a + '|', // 0x2b + 'Z', // 0x2c + 'X', // 0x2d + 'C', // 0x2e + 'V', // 0x2f + 'B', // 0x30 + 'N', // 0x31 + 'M', // 0x32 + '<', // 0x33 + '>', // 0x34 + '?', // 0x35 + 0, // 0x36 + 0, // 0x37 + 0, // 0x38 + ' ', // 0x39 + 0, // 0x3a + 0, // 0x3b + 0, // 0x3c + 0, // 0x3d + 0, // 0x3e + 0, // 0x3f + 0, // 0x40 + 0, // 0x41 + 0, // 0x42 + 0, // 0x43 + 0, // 0x44 + 0, // 0x45 + 0, // 0x46 + 0, // 0x47 + 0, // 0x48 + 0, // 0x49 + 0, // 0x4a + 0, // 0x4b + 0, // 0x4c + 0, // 0x4d + 0, // 0x4e + 0, // 0x4f + 0, // 0x50 + 0, // 0x51 + 0, // 0x52 + 0, // 0x53 + 0, // 0x54 + 0, // 0x55 + 0, // 0x56 + 0, // 0x57 + 0, // 0x58 + 0, // 0x59 + 0, // 0x5a + 0, // 0x5b + 0, // 0x5c + 0, // 0x5d + 0, // 0x5e + 0, // 0x5f + 0, // 0x60 + 0, // 0x61 + 0, // 0x62 + 0, // 0x63 + 0, // 0x64 + 0, // 0x65 + 0, // 0x66 + 0, // 0x67 + 0, // 0x68 + 0, // 0x69 + 0, // 0x6a + 0, // 0x6b + 0, // 0x6c + 0, // 0x6d + 0, // 0x6e + 0, // 0x6f + 0, // 0x70 + 0, // 0x71 + 0, // 0x72 + 0, // 0x73 + 0, // 0x74 + 0, // 0x75 + 0, // 0x76 + 0, // 0x77 + 0, // 0x78 + 0, // 0x79 + 0, // 0x7a + 0, // 0x7b + 0, // 0x7c + 0, // 0x7d + 0, // 0x7e + 0, // 0x7f +}; + +bool key_pressed[128]; + +bool lshift_pressed; +bool rshift_pressed; +bool extended_scan_code; + +#define INPUT_BUFFER_SIZE 80 +uint8_t input_buffer_occupancy = 0; +char input_buffer[INPUT_BUFFER_SIZE+1]; + +void input_buffer_backspace() { + if (input_buffer_occupancy > 0) { + input_buffer_occupancy -= 1; + input_buffer[input_buffer_occupancy] = 0; + } +} + +InputHandler input_handler = 0; + +void set_input_handler(InputHandler handler) { + input_handler = handler; +} + +void append_to_input_buffer(char c) { + if (c == '\n') { + fprintf(LOG, "flush input buffer: %s\n", input_buffer); + if (input_handler != 0) { + input_handler(input_buffer); + } + input_buffer_occupancy = 0; + input_buffer[0] = 0; + } else if (input_buffer_occupancy < INPUT_BUFFER_SIZE) { + input_buffer[input_buffer_occupancy] = c; + input_buffer_occupancy += 1; + input_buffer[input_buffer_occupancy] = 0; + } else { + fprintf(LOG, "Error: dropped input because input buffer is full.\n"); + } +} + +uint8_t read_scan_code() +{ + return inb(KBD_DATA_PORT); +} + +void keyboard_interrupt_handler() { + uint8_t scan_code = read_scan_code(); + bool pressed = 1; + if (scan_code >= 128) { + pressed = false; + scan_code -= 128; + } + key_pressed[scan_code] = pressed; + + if (!pressed) { + return; + } + + if (scan_code == BACKSPACE) { + input_buffer_backspace(); + fb_backspace(); + return; + } + + char c; + if (key_pressed[LSHIFT] || key_pressed[RSHIFT]) { + c = shift_scan_code_table[scan_code]; + } else { + c = normal_scan_code_table[scan_code]; + } + + if (c != 0) { + fprintf(LOG, "%c", c); + fprintf(SCREEN, "%c", c); + append_to_input_buffer(c); + } +} diff --git a/drivers/keyboard.h b/drivers/keyboard.h new file mode 100644 index 0000000..d64ac68 --- /dev/null +++ b/drivers/keyboard.h @@ -0,0 +1,11 @@ +#ifndef INCLUDE_KEYBOARD_H +#define INCLUDE_KEYBOARD_H + +#include "../types.h" +#include "../stdlib/syscalls.h" + +void keyboard_interrupt_handler(); +void set_input_handler(InputHandler handler); +uint8_t read_scan_code(); + +#endif /* INCLUDE_KEYBOARD_H */ \ No newline at end of file diff --git a/drivers/pic.c b/drivers/pic.c new file mode 100644 index 0000000..3ee19f8 --- /dev/null +++ b/drivers/pic.c @@ -0,0 +1,23 @@ +#include "pic.h" +#include "../assembly_interface.h" +#include "../kernel_stdio.h" + +#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) + +#define PIC_EOI 0x20 /* End-of-interrupt command code */ + +void pic_init() { + outb(PIC1_DATA, 0b11111101); // Only enable keyboard (irc 1) + outb(PIC2_DATA, 0b11111111); // Don't enable any interrupts on slave pic (irc 8-15) + enable_hardware_interrupts(); +} + +void pic_acknowledge() +{ + outb(PIC1_COMMAND, PIC_EOI); +} \ No newline at end of file diff --git a/drivers/pic.h b/drivers/pic.h new file mode 100644 index 0000000..4bcba10 --- /dev/null +++ b/drivers/pic.h @@ -0,0 +1,9 @@ +#ifndef INCLUDE_PIC_H +#define INCLUDE_PIC_H + +#include "../types.h" + +void pic_acknowledge(); +void pic_init(); + +#endif /* INCLUDE_PIC_H */ \ No newline at end of file diff --git a/drivers/serial_port.c b/drivers/serial_port.c index 036436c..557cd38 100644 --- a/drivers/serial_port.c +++ b/drivers/serial_port.c @@ -4,6 +4,8 @@ #include "../assembly_interface.h" #include "../types.h" +#define SERIAL_COM1_BASE 0x3F8 /* COM1 base port */ + /* The I/O ports */ /* All the I/O ports are calculated relative to the data port. This is because @@ -77,11 +79,11 @@ void serial_configure_modem(int16 com) outb(SERIAL_MODEM_COMMAND_PORT(com), 0x03); } -void serial_init(int16 com) { - serial_configure_baud_rate(com, 2); - serial_configure_line(com); - serial_configure_fifo(com); - serial_configure_modem(com); +void serial_init() { + serial_configure_baud_rate(SERIAL_COM1_BASE, 2); + serial_configure_line(SERIAL_COM1_BASE); + serial_configure_fifo(SERIAL_COM1_BASE); + serial_configure_modem(SERIAL_COM1_BASE); } /** serial_is_transmit_fifo_empty: @@ -98,23 +100,15 @@ int serial_is_transmit_fifo_empty(int16 com) return inb(SERIAL_LINE_STATUS_PORT(com)) & 0x20; } -void serial_write(int16 com, char * s) { - int i = 0; - while (s[i]) { - serial_write_byte(com, s[i]); - i++; - } -} - -void serial_write_byte(int16 com, char c) { +void serial_write_byte(uint8_t b) { // Block until buffer is not full - while (!serial_is_transmit_fifo_empty(com)) {} + while (!serial_is_transmit_fifo_empty(SERIAL_COM1_BASE)) {} - outb(SERIAL_DATA_PORT(com), c); + outb(SERIAL_DATA_PORT(SERIAL_COM1_BASE), b); } -void serial_write_bytes(int16 com, char * c, int n) { +void serial_write_bytes(char * c, int n) { for (int i = 0; i < n; i++) { - serial_write_byte(com, c[i]); + serial_write_byte(c[i]); } } \ No newline at end of file diff --git a/drivers/serial_port.h b/drivers/serial_port.h index 09a6ede..2980a58 100644 --- a/drivers/serial_port.h +++ b/drivers/serial_port.h @@ -1,6 +1,9 @@ -#define SERIAL_COM1_BASE 0x3F8 /* COM1 base port */ +#ifndef INCLUSERIAL_PORTFER_H +#define INCLUSERIAL_PORTFER_H -void serial_init(unsigned short com); -void serial_write(unsigned short com, char * s); -void serial_write_byte(unsigned short com, char c); -void serial_write_bytes(unsigned short com, char * c, int n); \ No newline at end of file +#include "../types.h" + +void serial_init(); +void serial_write_byte(uint8_t b); + +#endif /* INCLUDE_SERIAL_PORT_H */ \ No newline at end of file diff --git a/elf.h b/elf.h new file mode 100644 index 0000000..5c75b5d --- /dev/null +++ b/elf.h @@ -0,0 +1,28 @@ +#ifndef INCLUDE_ELF_H +#define INCLUDE_ELF_H + +#include "types.h" + +struct elf_section_header_t { + uint32_t sh_name; + uint32_t attr1; + uint32_t attr2; + uint32_t sh_addr; + uint32_t attr4; + uint32_t sh_size; + uint32_t attr6; + uint32_t attr7; + uint32_t attr8; + uint32_t attr9; +}; + +typedef struct { + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + uint8_t st_info; + uint8_t st_other; + uint16_t st_shndx; +} Elf32_Sym; + +#endif /* INCLUDE_ELF_H */ \ No newline at end of file diff --git a/file_system_root/test.txt b/file_system_root/test.txt new file mode 100644 index 0000000..3245b20 --- /dev/null +++ b/file_system_root/test.txt @@ -0,0 +1 @@ +Hello World. \ No newline at end of file diff --git a/interrupts.c b/interrupts.c new file mode 100644 index 0000000..c079888 --- /dev/null +++ b/interrupts.c @@ -0,0 +1,100 @@ +#include "interrupts.h" + +#include "assembly_interface.h" +#include "data_structures/page_table.h" +#include "data_structures/symbol_table.h" +#include "drivers/keyboard.h" +#include "drivers/pic.h" +#include "loader.h" +#include "memory.h" +#include "kernel_stdio.h" +#include "kernel_syscalls.h" + +void log_stack_trace_line(uint32_t eip) { + char * symbol_name = address_to_symbol_name(eip); + fprintf(LOG, "%x : %s\n", eip, symbol_name); +} + +void log_interrupt_details(char* int_name, uint32_t error_code, uint32_t eip, struct cpu_state* cpu) { + if(cpu->ebp){} + fprintf(LOG, "--------------------\n"); + + fprintf(LOG, "Interrupt: %s\n", int_name); + fprintf(LOG, "error_code: %x\n", error_code); + + fprintf(LOG, "\nStack trace:\n"); + eip -= 4; // eip actually points one past the instruction that triggered interrupt + log_stack_trace_line(eip); + uint32_t ebp = cpu->ebp; + uint32_t kernel_stack_highest_address = ((uint32_t) &kernel_stack_lowest_address + KERNEL_STACK_SIZE - 4); + while (ebp <= kernel_stack_highest_address && ebp >= ((uint32_t) &kernel_stack_lowest_address)) { + eip = ((uint32_t*) ebp)[1]; + log_stack_trace_line(eip); + + ebp = *((uint32_t*)ebp); + } + + fprintf(LOG, "--------------------\n"); +} + +uint32_t interrupt_handler(struct cpu_state cpu, uint32_t interrupt_number, uint32_t error_code, uint32_t eip) { + switch(interrupt_number) { + case(INT_KEYBOARD): + keyboard_interrupt_handler(); + break; + case(INT_PAGE_FAULT): + if ((error_code & 0b1) == 0) { + // Caused by page-not-present + page_in((void*) cpu.cr2); + break; + } + log_interrupt_details("INT_PAGE_FAULT", error_code, eip, &cpu); + fprintf(LOG, "Interrupt was a page fault. Here's what I know:\n"); + fprintf(LOG, "- Tried to access virtual address %x\n", cpu.cr2); + if (error_code & 0b1) { + fprintf(LOG, "- Couldn't complete because of page-protection violation\n"); + } else { + fprintf(LOG, "- Couldn't complete because page was not present\n"); + } + if (error_code & 0b10) { + fprintf(LOG, "- This was an attempt to WRITE to this address.\n"); + } else { + fprintf(LOG, "- This was an attempt to READ from this address.\n"); + } + if (error_code & 0b100) { + fprintf(LOG, "- Memory access came from user.\n"); + } else { + fprintf(LOG, "- Memory access came from kernel.\n"); + } + if (error_code & 0b1000) { + fprintf(LOG, "- caused by reading a 1 in a reserved field.\n"); + } + if (error_code & 0b10000) { + fprintf(LOG, "- caused by an instruction fetch.\n"); + } + while(1){} + break; + + case(INT_SOFTWARE): + log_interrupt_details("INT_SOFTWARE", error_code, eip, &cpu); + break; + + case(INT_SYSCALL): + return handle_syscall(&cpu); + + case(INT_OUT_OF_MEMORY): + log_interrupt_details("INT_OUT_OF_MEMORY", error_code, eip, &cpu); + while(true){} + break; + + default: + fprintf(LOG, "ERROR: Unable to handle interrupt: %x\n", interrupt_number); + log_interrupt_details("INT_UNKNOWN", error_code, eip, &cpu); + while(1){} + break; + } + + pic_acknowledge(); + + return 0; +} diff --git a/interrupts.h b/interrupts.h index 5afe96f..5bdca99 100644 --- a/interrupts.h +++ b/interrupts.h @@ -1 +1,27 @@ -void interrupt_handler(); \ No newline at end of file +#ifndef INCLUDE_INTERRUPTS_H +#define INCLUDE_INTERRUPTS_H + +#include "types.h" + +#define INT_KEYBOARD 0x00000009 +#define INT_GENERAL_PROTECTION_FAULT 0x0000000D +#define INT_PAGE_FAULT 0x0000000E +#define INT_SOFTWARE 0x00000031 +#define INT_OUT_OF_MEMORY 0x00000032 +#define INT_SYSCALL 0x00000080 + +struct cpu_state { + uint32_t cr2; + uint32_t ebp; + uint32_t edi; + uint32_t esi; + uint32_t edx; + uint32_t ecx; + uint32_t ebx; + uint32_t eax; +} __attribute__((packed)); + +void enable_keyboard_interrupts(); +uint32_t interrupt_handler(struct cpu_state cpu, uint32_t interrupt_number, uint32_t error_code, uint32_t eip); + +#endif /* INCLUDE_INTERRUPTS_H */ \ No newline at end of file diff --git a/interrupts.s b/interrupts.s deleted file mode 100644 index c6926dc..0000000 --- a/interrupts.s +++ /dev/null @@ -1,4 +0,0 @@ -global interrupt_handler -interrupt_handler: - mov eax, 0xDEADBEEF - jmp $ diff --git a/kernel_filesystem.c b/kernel_filesystem.c new file mode 100644 index 0000000..95b9e27 --- /dev/null +++ b/kernel_filesystem.c @@ -0,0 +1,80 @@ +#include "kernel_filesystem.h" + +#include "memory.h" +#include "kernel_stdio.h" +#include "stdlib.h" +#include "stdlib/string.h" + +struct file_t* first_file; +struct file_t* last_file; + +struct file_t* parse_file(char** cursor) { + if (strncmp(*cursor, "FILE ", 5) != 0) { + fprintf(LOG, "ERROR: First bytes of metadata should be `FILE ` but were `"); + for (int i = 0; i < 5; i++) { + fprintf(LOG, "%c", (*cursor)[i]); + } + fprintf(LOG, "`\n"); + fprintf(LOG, "strncmp returned %i\n", strncmp(*cursor, "FILE ", 5)); + fprintf(LOG, "cursor: %s", cursor); + while(1){} + } + (*cursor) += 5; + + struct file_t* file = malloc(sizeof(struct file_t)); + + uint32_t file_name_length = 0; + while (*(*cursor) != ' ' && file_name_length < FILE_NAME_MAX_LENGTH) { + file->name[file_name_length] = *(*cursor); + (*cursor)++; + file_name_length++; + } + (*cursor)++; + + uint32_t file_size = atoi(*cursor); + file->size = file_size; + while (*(*cursor) != '\n') { + (*cursor)++; + } + (*cursor)++; + file->bytes = (*cursor); + + (*cursor) += file->size + 1; + + return file; +} + +void initialize_filesystem(struct module* mod) { + void* mod_virtual_start = (void*) (mod->mod_start + UPPER_GB_START); + char* mod_virtual_end = (mod->mod_end + UPPER_GB_START); + char* cursor = (char*) mod_virtual_start; + + while (cursor < mod_virtual_end) { + struct file_t* new_file = parse_file(&cursor); + if (!first_file) { + first_file = new_file; + } + if (last_file) { + last_file->next_sibling = new_file; + } else { + last_file = new_file; + } + } +} + +struct file_t* get_file(char* name) { + struct file_t* file = first_file; + + while (file) { + if (strcmp(file->name, name) == 0) { + return file; + } + file = file->next_sibling; + } + + return 0; +} + +struct file_t* get_first_file() { + return first_file; +} diff --git a/kernel_filesystem.h b/kernel_filesystem.h new file mode 100644 index 0000000..2847986 --- /dev/null +++ b/kernel_filesystem.h @@ -0,0 +1,12 @@ +#ifndef INCLUDE_KERNEL_FILESYSTEM_H +#define INCLUDE_KERNEL_FILESYSTEM_H + +#include "types.h" +#include "multiboot.h" +#include "stdlib/filesystem.h" + +void initialize_filesystem(struct module* mbinfo); +struct file_t* get_file(char* name); +struct file_t* get_first_file(); + +#endif /* INCLUDE_KERNEL_FILESYSTEM_H */ \ No newline at end of file diff --git a/kernel_stdio.c b/kernel_stdio.c new file mode 100644 index 0000000..55151ce --- /dev/null +++ b/kernel_stdio.c @@ -0,0 +1,188 @@ +#include "kernel_stdio.h" + +#include "drivers/frame_buffer.h" +#include "drivers/serial_port.h" + +#include "stdarg.h" + +typedef void (*write_byte_t)(uint8_t); + +write_byte_t write_byte_function(FILE stream) { + switch (stream) { + case (SCREEN): + return fb_write_byte; + case (LOG): + return serial_write_byte; + } +} + +void kernel_write_half_byte(write_byte_t write_byte, uint8_t half_byte, bool upcase) { + switch (half_byte) { + case 0x0: + write_byte('0'); + break; + case 0x1: + write_byte('1'); + break; + case 0x2: + write_byte('2'); + break; + case 0x3: + write_byte('3'); + break; + case 0x4: + write_byte('4'); + break; + case 0x5: + write_byte('5'); + break; + case 0x6: + write_byte('6'); + break; + case 0x7: + write_byte('7'); + break; + case 0x8: + write_byte('8'); + break; + case 0x9: + write_byte('9'); + break; + case 0xA: + write_byte(upcase ? 'A' : 'a'); + break; + case 0xB: + write_byte(upcase ? 'B' : 'b'); + break; + case 0xC: + write_byte(upcase ? 'C' : 'c'); + break; + case 0xD: + write_byte(upcase ? 'D' : 'd'); + break; + case 0xE: + write_byte(upcase ? 'E' : 'e'); + break; + case 0xF: + write_byte(upcase ? 'F' : 'f'); + break; + } +} + +void kernel_write_string(write_byte_t write_byte, char* s) { + while(*s) { + write_byte(*s); + s++; + } +} + +void kernel_write_uint(write_byte_t write_byte, uint32_t value) { + if (value == 0) { + write_byte('0'); + return; + } + + char output[10]; + for (int place = 0; place < 10; place++) { + output[place] = value % 10; + value = value / 10; + } + + bool past_leading_zeroes = false; + for (int place = 9; place >= 0; place--) { + if (output[place] > 0) { + past_leading_zeroes = true; + } + + if (past_leading_zeroes) { + write_byte(output[place] + '0'); + } + } +} + +void kernel_write_int(write_byte_t write_byte, int value) { + if (value < 0) { + write_byte('-'); + value *= -1; + } + kernel_write_uint(write_byte, value); +} + +void kernel_write_octal(write_byte_t write_byte, uint32_t value) { + write_byte('0'); + write_byte('o'); + bool past_leading_zeroes = false; + uint8_t part = (value >> 30) & 0b11; + if (part > 0) { + kernel_write_half_byte(write_byte, part, true); + past_leading_zeroes = true; + } + for (int i = 10; i >=0; i--) { + part = (value >> (3*i)) & 0b111; + if (part > 0) { + past_leading_zeroes = true; + } + + if (past_leading_zeroes) { + kernel_write_half_byte(write_byte, part, true); + } + } +} + +enum format_string_mode {NORMAL, COMMAND}; +int fprintf (FILE stream, const char * format, ...) { + write_byte_t write_byte = write_byte_function(stream); + + va_list vl; + va_start(vl,format); + + int i = 0; + enum format_string_mode mode = NORMAL; + uint32_t vararg; + while (format[i]) { + switch (mode) { + case (NORMAL): + if (format[i] == '%') { + mode = COMMAND; + } else { + write_byte(format[i]); + } + break; + case (COMMAND): + if (format[i] == '%') { + write_byte('%'); + } else if (format[i] == 'c') { + write_byte((uint32_t) va_arg(vl,uint32_t)); + } else if (format[i] == 'i' || format[i] == 'd') { + kernel_write_int(write_byte, va_arg(vl, int)); + } else if (format[i] == 'o') { + kernel_write_octal(write_byte, va_arg(vl, int)); + } else if (format[i] == 's') { + kernel_write_string(write_byte, (char*) va_arg(vl,char*)); + } else if (format[i] == 'u') { + kernel_write_uint(write_byte, va_arg(vl, uint32_t)); + } else if (format[i] == 'x') { + write_byte('0'); + write_byte('x'); + vararg = va_arg(vl,uint32_t); + for (int i = 7; i >=0; i--) { + kernel_write_half_byte(write_byte, (vararg >> (4*i)) & 0x0F, false); + } + } else if (format[i] == 'X') { + write_byte('0'); + write_byte('x'); + vararg = va_arg(vl,uint32_t); + for (int i = 7; i >=0; i--) { + kernel_write_half_byte(write_byte, (vararg >> (4*i)) & 0x0F, true); + } + } else { + write_byte('?'); + mode = NORMAL; + } + mode = NORMAL; + break; + } + i++; + } + return i; +} \ No newline at end of file diff --git a/kernel_stdio.h b/kernel_stdio.h new file mode 100644 index 0000000..9ec19a0 --- /dev/null +++ b/kernel_stdio.h @@ -0,0 +1,10 @@ +#ifndef STDIO_H +#define STDIO_H + +#include "types.h" + +typedef enum output_t {SCREEN, LOG} FILE; + +int fprintf (FILE stream, const char * format, ...); + +#endif /* STDIO_H */ \ No newline at end of file diff --git a/kernel_syscalls.c b/kernel_syscalls.c new file mode 100644 index 0000000..3e9908f --- /dev/null +++ b/kernel_syscalls.c @@ -0,0 +1,73 @@ +#include "kernel_syscalls.h" + +#include "drivers/keyboard.h" +#include "kernel_filesystem.h" +#include "kernel_stdio.h" +#include "stdlib/syscalls.h" + +uint32_t sys_write_to_screen(char* s) { + fprintf(SCREEN, s); + return 0; +} + +uint32_t sys_count_files() { + struct file_t* file = get_first_file(); + uint32_t count = 0; + while (file) { + count++; + file = file->next_sibling; + } + + return count; +} + +uint32_t sys_list_files(struct file_t* buffer) { + struct file_t* file = get_first_file(); + while (file) { + *buffer = *file; + buffer++; + file = file->next_sibling; + } + + return 0; +} + +uint32_t sys_register_input_handler(InputHandler handler) { + set_input_handler(handler); + return 0; +} + +char* syscall_name(Syscall syscall) { + switch (syscall) { + case (WRITE_TO_SCREEN): + return "WRITE_TO_SCREEN"; + case (COUNT_FILES): + return "COUNT_FILES"; + case (LIST_FILES): + return "LIST_FILES"; + case (REGISTER_INPUT_HANDLER): + return "REGISTER_INPUT_HANDLER"; + } +} + +uint32_t handle_syscall(struct cpu_state* cpu) { + Syscall syscall = (Syscall) cpu->eax; + + fprintf(LOG, "--------------------\nSYSCALL (%i - %s)\n", syscall, syscall_name(syscall)); + + switch (syscall) { + case (WRITE_TO_SCREEN): + return sys_write_to_screen((char*) cpu->ebx); + case (COUNT_FILES): + return sys_count_files(); + case (LIST_FILES): + return sys_list_files((struct file_t *) cpu->ebx); + case (REGISTER_INPUT_HANDLER): + return sys_register_input_handler((InputHandler) cpu->ebx); + default: + fprintf(LOG, "Unknown syscall: %x\n", syscall); + while(1){} + } + + fprintf(LOG, "--------------------\n"); +} \ No newline at end of file diff --git a/kernel_syscalls.h b/kernel_syscalls.h new file mode 100644 index 0000000..0682b99 --- /dev/null +++ b/kernel_syscalls.h @@ -0,0 +1,8 @@ +#ifndef INCLUDE_KERNEL_SYSCALLS_H +#define INCLUDE_KERNEL_SYSCALLS_H + +#include "interrupts.h" + +uint32_t handle_syscall(struct cpu_state* cpu); + +#endif /* INCLUDE_KERNEL_SYSCALLS_H */ \ No newline at end of file diff --git a/kmain.c b/kmain.c index 4bcd44a..3f30f68 100644 --- a/kmain.c +++ b/kmain.c @@ -1,121 +1,18 @@ #include "assembly_interface.h" +#include "data_structures/global_descriptor_table.h" +#include "data_structures/interrupt_descriptor_table.h" +#include "data_structures/page_table.h" +#include "data_structures/symbol_table.h" #include "drivers/frame_buffer.h" +#include "drivers/pic.h" #include "drivers/serial_port.h" -#include "interrupts.h" +#include "kernel_filesystem.h" +#include "multiboot_utils.h" +#include "process.h" +#include "kernel_stdio.h" +#include "stdlib.h" #include "types.h" -enum output_t {SCREEN, LOG}; - -// a pointer to the global descriptor table -// passed by reference to the LGDT instruction -struct gdt_description_structure_t { - uint16_t size; // in bytes - uint32_t offset; -} __attribute__((packed)) gdt_description_structure; - -// a pointer to the interrupt descriptor table -// passed by reference to the LIDT instruction -struct idt_description_structure_t { - uint16_t size; // in bytes - uint32_t offset; -} __attribute__((packed)) idt_description_structure; - -// See http://wiki.osdev.org/Global_Descriptor_Table#Structure -struct segment_descriptor_t { - uint16_t limit_0_15; // bits o-15 of limit - uint16_t base_0_15; - uint8_t base_16_23; - uint8_t access_byte; - uint8_t flags_and_limit_16_19; - uint8_t base_24_31; -} __attribute__((packed)); - -// See http://wiki.osdev.org/Interrupt_Descriptor_Table#Structure_IA-32 -struct interrupt_descriptor_t { - uint16_t offset_0_15; - uint16_t selector; - uint8_t zero; - uint8_t type_attr; - uint16_t offset_16_31; -} __attribute__((packed)); - -enum segment_selector_t { - NULL_DESCRIPTOR, // Not used but has to be here - KERNAL_CODE_SEGMENT_INDEX, // Offset 0x8 - KERNAL_DATA_SEGMENT_INDEX // Offset 0x10 -}; -struct segment_descriptor_t gdt[3]; -const uint16_t NULL_SEGMENT_SELECTOR = 0x0; -const uint16_t KERNAL_CODE_SEGMENT_SELECTOR = sizeof(struct segment_descriptor_t) * 1; -const uint16_t KERNAL_DATA_SEGMENT_SELECTOR = sizeof(struct segment_descriptor_t) * 2; - -struct interrupt_descriptor_t idt[256]; - -void initialize_gdt() { - gdt_description_structure.size = sizeof(gdt) - 1; - gdt_description_structure.offset = (uint32_t) gdt; - - gdt[KERNAL_CODE_SEGMENT_INDEX].limit_0_15 = 0xFFFF; - gdt[KERNAL_CODE_SEGMENT_INDEX].base_0_15 = 0x0000; - gdt[KERNAL_CODE_SEGMENT_INDEX].base_16_23 = 0x00; - gdt[KERNAL_CODE_SEGMENT_INDEX].access_byte = 0b10011010; - gdt[KERNAL_CODE_SEGMENT_INDEX].flags_and_limit_16_19 = 0xCF; - gdt[KERNAL_CODE_SEGMENT_INDEX].base_24_31 = 0x00; - - gdt[KERNAL_DATA_SEGMENT_INDEX].limit_0_15 = 0xFFFF; - gdt[KERNAL_DATA_SEGMENT_INDEX].base_0_15 = 0x0000; - gdt[KERNAL_DATA_SEGMENT_INDEX].base_16_23 = 0x00; - gdt[KERNAL_DATA_SEGMENT_INDEX].access_byte = 0b10010010; - gdt[KERNAL_DATA_SEGMENT_INDEX].flags_and_limit_16_19 = 0xCF; - gdt[KERNAL_DATA_SEGMENT_INDEX].base_24_31 = 0x00; - - lgdt(&gdt_description_structure); - - // Grub has already loaded the segment registers - // with the correct values (0x8 for cs, 0x10 for the others) -} - -void initialize_idt() { - idt_description_structure.size = sizeof(idt) - 1; - idt_description_structure.offset = (uint32_t) idt; - - uint32_t interrupt_handler_address = (uint32_t) &interrupt_handler; - uint16_t offset_0_15 = interrupt_handler_address & 0x0000FFFF; - uint16_t offset_16_31 = interrupt_handler_address >> 16; - uint16_t selector = KERNAL_CODE_SEGMENT_SELECTOR; - uint8_t zero = 0x00; - uint8_t type_attr = 0x8E; - - for (int i = 0; i < 256; i++) { - idt[i].offset_0_15 = offset_0_15; - idt[i].selector = selector; - idt[i].zero = zero; - idt[i].type_attr = type_attr; - idt[i].offset_16_31 = offset_16_31; - } - - load_idt(&idt_description_structure); -} - -void write(enum output_t output_device, char * s) { - switch (output_device) { - case (SCREEN): - fb_write(s); - break; - case (LOG): - serial_write(SERIAL_COM1_BASE, s); - break; - } -} - -void printf(char * s) { - write(SCREEN, s); -} - -void log(char * s) { - write(LOG, s); -} - static char *welcome_string = "" " " " " @@ -144,25 +41,114 @@ static char *welcome_string = "" " " ""; -void kmain() { +uint32_t trigger_page_fault() { + uint32_t* unmapped_address = (uint32_t *) 0x400000; // 4 MB + return *unmapped_address; +} + +struct test_struct_t { + uint32_t integer; + char character; + char* string; +}; + +void kmain(struct kernel_memory_descriptor_t kernel_memory, uint32_t ebx) { + // GRUB passes info to the kernel through the ebx register + multiboot_info_t *mbinfo = (multiboot_info_t *) ebx; + clear_screen(); - printf(welcome_string); + fprintf(SCREEN, welcome_string); + + serial_init(); + fprintf(LOG, "\n--------------------\ncstackOS is booting!\n--------------------\n\n"); + + #ifdef DEBUG + fprintf(LOG, "\nMultiboot info passed to kernel from GRUB:\n"); + print_multiboot_info(LOG, mbinfo); + fprintf(LOG, "\n"); + #endif - serial_init(SERIAL_COM1_BASE); - log("Initialized serial port.\n"); + fprintf(LOG, "- Initializing symbol table...\n"); + if (load_symbol_table(get_elf_section(mbinfo, ".symtab"), get_elf_section(mbinfo, ".strtab"))) { + fprintf(LOG, " - done\n"); + } else { + fprintf(LOG, "ERROR: Could not initialize symbol table.\n"); + while(1){} + } + fprintf(LOG, "- Initializing global descriptor table...\n"); initialize_gdt(); - log("Loaded global descriptor table.\n"); + fprintf(LOG, " - done\n"); + fprintf(LOG, "- Initializing interrupt descriptor table...\n"); initialize_idt(); - log("Loaded interrupt descriptor table.\n"); - - move_cursor(17, 0); + fprintf(LOG, " - done\n"); + + fprintf(LOG, "- Issuing test interrupt...\n"); + interrupt(); + fprintf(LOG, " - done\n"); + + fprintf(LOG, "- Initializing programable interrupt controller...\n"); + pic_init(); + fprintf(LOG, " - done\n"); + + fprintf(LOG, "- Initializing page allocator...\n"); + uint32_t free_pages = initialize_page_allocator(kernel_memory, mbinfo); + fprintf(LOG, " - done\n"); + fprintf(LOG, " - %i free pages (%i MB)\n", free_pages, free_pages/256); + + fprintf(LOG, "- Initializing page directory...\n"); + page_directory_t pd = initialize_kernel_page_directory(); + fprintf(LOG, " - done\n"); + fprintf(LOG, " - Address of page directory: %x\n", (uint32_t) pd); + uint32_t num_pages = num_present_pages(pd); + fprintf(LOG, " - %i present pages\n", num_pages); + + fprintf(LOG, "- Triggering a page fault...\n"); + uint32_t value = trigger_page_fault(); + fprintf(LOG, " - done\n"); + fprintf(LOG, " - value at unmapped address was %x\n", value); + + fprintf(LOG, "- Initializing task state segment...\n"); + initialize_tss(); + fprintf(LOG, " - done\n"); + + fprintf(LOG, "- Dynamically allocating a struct...\n"); + struct test_struct_t* test = (struct test_struct_t*) malloc(sizeof(struct test_struct_t)); + fprintf(LOG, " - done\n"); + fprintf(LOG, " - address (on heap) is: %x\n", (uint32_t) test); + + uint32_t local = 0xDEADBEEF; + + fprintf(LOG, " - local variable (on stack) at: %x\n", (uint32_t) &local); + + void* sp = current_stack_pointer(); + fprintf(LOG, " - stack pointer is: %x\n", (uint32_t) sp); + + fprintf(LOG, "- Testing format strings...\n"); + fprintf( + LOG, + " - %%s -> %s, %%c -> %c, %%x -> %x, %%X -> %X, %%u -> %u, %%i -> %i, %%o -> %o\n", + "test", 'A', 0xDEADBEEF, 0xDEADBEEF, 0, -12345, 12345 + ); + + fprintf(LOG, "- Loading file system from GRUB module...\n"); + initialize_filesystem(first_module(mbinfo)); + fprintf(LOG, " - done\n"); + + char* file_name = "shell.bin"; + struct file_t* file = get_file(file_name); + if (file == 0) { + fprintf(LOG, "ERROR: could not find file %s\n", file_name); + while(1){} + } - interrupt(49); + fprintf(LOG, "- Creating a user process...\n"); + create_process(file); + fprintf(LOG, " - done\n"); // Loop forever - // TODO: accept user input - while(1) {}; + // User input is accepted asynchronously via interrupts + while(1){} } \ No newline at end of file diff --git a/link.ld b/link.ld index e3d6195..bc3e119 100644 --- a/link.ld +++ b/link.ld @@ -10,26 +10,32 @@ ENTRY(loader) /* the name of the entry label */ file that we're linking */ SECTIONS { - . = 0x00100000; /* the code should be loaded at 1 MB */ + . = 0xC0100000; /* the code should be linked as though it were loaded at 3GB + 1MB. In actuality, it will be loaded at physical address 1MB, then we will map virtual addresses above 3GB to physical address starting at 0 */ - .text ALIGN (0x1000) : /* align at 4 KB, the size of a page */ + kernel_virtual_start = .; + kernel_physical_start = . - 0xC0000000; + + .text ALIGN (0x1000) : AT(ADDR(.text)-0xC0000000) /* align at 4 KB, the size of a page */ { *(.text) /* all text sections from all files */ } - .rodata ALIGN (0x1000) : /* align at 4 KB, the size of a page */ + .rodata ALIGN (0x1000) : AT(ADDR(.rodata)-0xC0000000) /* align at 4 KB, the size of a page */ { *(.rodata*) /* all read-only data sections from all files */ } - .data ALIGN (0x1000) : /* align at 4 KB, the size of a page */ + .data ALIGN (0x1000) : AT(ADDR(.data)-0xC0000000) /* align at 4 KB, the size of a page */ { *(.data) /* all data sections from all files */ } - .bss ALIGN (0x1000) : /* align at 4 KB, the size of a page */ + .bss ALIGN (0x1000) : AT(ADDR(.bss)-0xC0000000) /* align at 4 KB, the size of a page */ { *(COMMON) /* all COMMON sections from all files */ *(.bss) /* all bss sections from all files */ } + + kernel_virtual_end = .; + kernel_physical_end = . - 0xC0000000; } \ No newline at end of file diff --git a/link_user_program.ld b/link_user_program.ld new file mode 100644 index 0000000..a759645 --- /dev/null +++ b/link_user_program.ld @@ -0,0 +1,22 @@ +OUTPUT_FORMAT("binary") /* output flat binary */ + +SECTIONS +{ + . = 0; /* relocate to address 0 */ + + .text ALIGN(4): + { + start_user_program.o(.text) /* include the .text section of start_user_program.o */ + *(.text) /* include all other .text sections */ + } + + .data ALIGN(4): + { + *(.data) + } + + .rodata ALIGN(4): + { + *(.rodata*) + } +} \ No newline at end of file diff --git a/loader.h b/loader.h new file mode 100644 index 0000000..dd9fa55 --- /dev/null +++ b/loader.h @@ -0,0 +1,12 @@ +#ifndef INCLUDE_LOADER_H +#define INCLUDE_LOADER_H + +#include "types.h" + +uint32_t KERNEL_VIRTUAL_BASE; + +void * kernel_stack_lowest_address; +void * PageDirectoryVirtualAddress; +void * PageDirectoryPhysicalAddress; + +#endif /* INCLUDE_LOADER_H */ \ No newline at end of file diff --git a/loader.s b/loader.s index 50534c0..3571b7b 100644 --- a/loader.s +++ b/loader.s @@ -6,6 +6,11 @@ global loader ; the entry symbol for ELF extern kmain ; the starting point in our C code +extern kernel_virtual_start +extern kernel_virtual_end +extern kernel_physical_start +extern kernel_physical_end + MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant ; 'equ' is a pseduo-instruction which does not @@ -14,13 +19,43 @@ MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant ; whereever 'MAGIC_NUMBER' shows up, in the code, ; it will be replaced with 0x1BADB002 -FLAGS equ 0x0 ; multiboot flags +ALIGN_MODULES equ 0x00000001 ; tell GRUB to align modules on page boundaries. + ; We use modules to load a 'user' program into + ; memory + +FLAGS equ ALIGN_MODULES ; multiboot flags passed to GRUB -CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum - ; (magic number + checksum + flags should equal 0) +; calculate the checksum +; (magic number + checksum + flags should equal 0) +CHECKSUM equ -(MAGIC_NUMBER + FLAGS) KERNEL_STACK_SIZE equ 4096 ; size of stack in bytes (1 kilobyte) +; This is the virtual base address of kernel space. It must be used to convert virtual +; addresses into physical addresses until paging is enabled. Note that this is not +; the virtual address where the kernel image itself is loaded -- just the amount that must +; be subtracted from a virtual address to get a physical address. +global KERNEL_VIRTUAL_BASE +KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB +KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; Page directory index of kernel's 4MB PTE. + +section .data +align 0x1000 +global PageDirectoryVirtualAddress +PageDirectoryVirtualAddress: + ; This page directory entry identity-maps the first 4MB of the 32-bit physical address space. + ; All bits are clear except the following: + ; bit 7: PS The kernel page is 4MB. + ; bit 1: RW The kernel page is read/write. + ; bit 0: P The kernel page is present. + ; This entry must be here -- otherwise the kernel will crash immediately after paging is + ; enabled because it can't fetch the next instruction! It's ok to unmap this page later. + dd 0x00000083 + times (KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages before kernel space. + ; This page directory entry defines a 4MB page containing the kernel. + dd 0x00000083 + times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages after the kernel image. + section .text ; start of the text (code) section ; .data is for initialized variables ; .bss is for uninitialized variables @@ -36,18 +71,53 @@ align 4 ; the code must be 4 byte aligned dd FLAGS ; the flags, dd CHECKSUM ; and the checksum -loader: ; the loader label (defined as entry point in linker script) - ; that means the address of this instruction will - ; appear in the symbol table +_loader: +loader equ (_loader - KERNEL_VIRTUAL_BASE) + ; NOTE: Until paging is set up, the code must be position-independent and use physical + ; addresses, not virtual ones! + global PageDirectoryPhysicalAddress + PageDirectoryPhysicalAddress equ (PageDirectoryVirtualAddress - KERNEL_VIRTUAL_BASE) ; 0x104000 + mov ecx, PageDirectoryPhysicalAddress + mov cr3, ecx ; Load Page Directory Base Register. + + mov ecx, cr4 + or ecx, 0x00000010 ; Set PSE bit in CR4 to enable 4MB pages. + mov cr4, ecx + + mov ecx, cr0 + or ecx, 0x80000000 ; Set PG bit in CR0 to enable paging. + mov cr0, ecx + + ; Start fetching instructions in kernel space. + ; Since eip at this point holds the physical address of this command (approximately 0x00100000) + ; we need to do a long jump to the correct virtual address of higher_half_loader which is + ; approximately 0xC0100000. + lea ecx, [higher_half_loader] + jmp ecx - mov eax, 0xCAFEBABE ; place the number 0xCAFEBABE in the register eax +higher_half_loader: + ; Unmap the identity-mapped first 4MB of physical address space. It should not be needed + ; anymore. + mov dword [PageDirectoryVirtualAddress], 0 + invlpg [0] - mov esp, kernel_stack + KERNEL_STACK_SIZE ; point esp to the start of the + mov esp, kernel_stack_lowest_address + KERNEL_STACK_SIZE ; point esp to the start of the ; stack (end of memory area) + add ebx, KERNEL_VIRTUAL_BASE ; make the address virtual + push ebx ; GRUB stores a pointer to a struct in the register ebx that, + ; among other things, describes at which addresses the modules are loaded. + ; Push ebx on the stack before calling kmain to make it an argument for kmain. + + push kernel_physical_end + push kernel_physical_start + push kernel_virtual_end + push kernel_virtual_start - jmp kmain + call kmain ; use call rather than jmp so C function finds paramters in the correct place + hlt ; should never get here. kmain should not return. +global kernel_stack_lowest_address section .bss ; Use the 'bss' section for the stack align 4 ; align at 4 bytes for performance reasons - kernel_stack: ; label points to beginning of memory + kernel_stack_lowest_address: ; label points to beginning of memory resb KERNEL_STACK_SIZE ; reserve stack for the kernel \ No newline at end of file diff --git a/memory.h b/memory.h new file mode 100644 index 0000000..18cee9c --- /dev/null +++ b/memory.h @@ -0,0 +1,15 @@ +#ifndef INCLUDE_MEMORY_H +#define INCLUDE_MEMORY_H + +#define UPPER_GB_START (void*) 0xC0000000 +#define TMP_PAGE_0 (void*) 0xFFBFB000 +#define TMP_PAGE_1 (void*) 0xFFBFC000 +#define TMP_PAGE_2 (void*) 0xFFBFD000 +#define TMP_PAGE_3 (void*) 0xFFBFE000 +#define TMP_PAGE_4 (void*) 0xFFBFF000 +#define FIRST_PAGE_TABLE_ADDRESS (void*) 0xFFC00000 // 4 MB from end +#define PAGE_DIRECTORY_ADDRESS (void*) 0xFFFFF000 // 4 KB from end + +#define KERNEL_STACK_SIZE 4096 + +#endif /* INCLUDE_MEMORY_H */ \ No newline at end of file diff --git a/menu.lst b/menu.lst index 93bfce3..d262cf1 100644 --- a/menu.lst +++ b/menu.lst @@ -2,4 +2,5 @@ default=0 timeout=0 title os -kernel /boot/kernel.elf \ No newline at end of file +kernel /boot/kernel.elf +module /modules/built_file_system \ No newline at end of file diff --git a/multiboot.h b/multiboot.h new file mode 100644 index 0000000..bf9fed9 --- /dev/null +++ b/multiboot.h @@ -0,0 +1,125 @@ +#ifndef MULTIBOOT_H +#define MULTIBOOT_H +// The following was copied from https://www.gnu.org/software/grub/manual/multiboot/html_node/multiboot.h.html + +/* multiboot.h - the header for Multiboot */ +/* Copyright (C) 1999, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Macros. */ + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +#ifdef __ELF__ +# define MULTIBOOT_HEADER_FLAGS 0x00000003 +#else +# define MULTIBOOT_HEADER_FLAGS 0x00010003 +#endif + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (16KB). */ +#define STACK_SIZE 0x4000 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* Do not include here in boot.S. */ + +/* Types. */ + +/* The Multiboot header. */ +typedef struct multiboot_header +{ + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* The symbol table for a.out. */ +typedef struct aout_symbol_table +{ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* The section header table for ELF. */ +typedef struct elf_section_header_table +{ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* The Multiboot information. */ +typedef struct multiboot_info +{ + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union + { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; +} multiboot_info_t; + +/* The module structure. */ +typedef struct module +{ + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* The memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map +{ + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +#endif /* ! ASM */ + +#endif /* MULTIBOOT_H */ \ No newline at end of file diff --git a/multiboot_utils.c b/multiboot_utils.c new file mode 100644 index 0000000..4e84811 --- /dev/null +++ b/multiboot_utils.c @@ -0,0 +1,112 @@ +#include "multiboot_utils.h" +#include "elf.h" +#include "loader.h" +#include "stdlib/string.h" + +uint32_t p_to_v(uint32_t physical_address) { + return physical_address + (uint32_t) &KERNEL_VIRTUAL_BASE; +} + +void print_module_info(FILE stream, struct module * m) { + fprintf(stream, (char*) (p_to_v(m->string))); + fprintf(stream, ":\n"); + fprintf(stream, "mod_start (virtual): %x\n", p_to_v(m->mod_start)); + fprintf(stream, "mod_end (virtual): %x\n", p_to_v(m->mod_end)); +} + +struct elf_section_header_t * get_elf_section(multiboot_info_t* info, char * section_name) { + elf_section_header_table_t section_table = info->u.elf_sec; + + uint32_t addr = p_to_v(section_table.addr); + uint32_t num_sections = section_table.num; + uint32_t shndx = section_table.shndx; + + struct elf_section_header_t * section_header_table = (struct elf_section_header_t *) addr; + uint32_t string_table_start = p_to_v(section_header_table[shndx].sh_addr); + + for (uint32_t i = 0; i < num_sections; i++) { + uint32_t sh_name = section_header_table[i].sh_name; + if (sh_name != 0) { + char * name = (char*) (string_table_start + sh_name); + int diff = strcmp(name, section_name); + if (diff == 0) { + return section_header_table + i; + } + } + } + + return 0; +} + + +void print_elf_section_header_table(FILE stream, elf_section_header_table_t table) { + fprintf(stream, "\nELF sections:\n"); + + uint32_t addr = p_to_v(table.addr); + uint32_t num = table.num; + uint32_t shndx = table.shndx; + + struct elf_section_header_t * section_header_table = (struct elf_section_header_t *) addr; + uint32_t string_table_start = p_to_v(section_header_table[shndx].sh_addr); + + for (uint32_t i = 0; i < num; i++) { + uint32_t sh_addr = section_header_table[i].sh_addr; + fprintf(stream, "%x : %x : ", sh_addr, section_header_table[i].sh_size); + + uint32_t sh_name = section_header_table[i].sh_name; + if (sh_name != 0) { + char * name = (char*) (string_table_start + sh_name); + fprintf(stream, name); + } else { + fprintf(stream, "(NULL SECTION)"); + } + fprintf(stream, "\n"); + } +} + +void print_memory_map(FILE stream, multiboot_info_t* info) { + fprintf(stream, "\nmemory map:\n"); + memory_map_t * memory_map = (memory_map_t *) p_to_v(info->mmap_addr); + uint32_t num_entries = info->mmap_length / sizeof(memory_map_t); + + for (uint32_t i = 0; i < num_entries; i++) { + fprintf(stream, "base_addr_low: %x\n", memory_map[i].base_addr_low); + fprintf(stream, "base_addr_high: %x\n", memory_map[i].base_addr_high); + fprintf(stream, "length_low: %x\n", memory_map[i].length_low); + fprintf(stream, "length_high: %x\n", memory_map[i].length_high); + fprintf(stream, "type: %x\n", memory_map[i].type); + fprintf(stream, "\n"); + } +} + +void print_multiboot_info(FILE stream, multiboot_info_t* info) { + fprintf(stream, "flags: %x\n", info->flags); + fprintf(stream, "mem_lower (kilobytes): %i\n", info->mem_lower); + fprintf(stream, "mem_upper (kilobytes): %i\n", info->mem_upper); + fprintf(stream, "boot_device: %x\n", info->boot_device); + fprintf(stream, "cmdline: %x\n", info->cmdline); + fprintf(stream, "mods_count: %i\n", info->mods_count); + fprintf(stream, "mods_addr (virtual): %x\n", info->mods_addr); + + fprintf(stream, "\nGRUB modules: \n"); + struct module * modules; + if (info->mods_count > 0) { + modules = (struct module *) (p_to_v(info->mods_addr)); + for (uint8_t i = 0; i < info->mods_count; i++) { + print_module_info(stream, &(modules[i])); + } + } + + print_elf_section_header_table(stream, info->u.elf_sec); + + print_memory_map(stream, info); +} + +struct module* first_module(multiboot_info_t* info) { + if (info->mods_count == 0) { + return 0; + } + + struct module* module_info = (struct module*) (p_to_v(info->mods_addr)); + return module_info; +} diff --git a/multiboot_utils.h b/multiboot_utils.h new file mode 100644 index 0000000..e4bcf73 --- /dev/null +++ b/multiboot_utils.h @@ -0,0 +1,13 @@ +#ifndef MULTIBOOT_UTILS_H +#define MULTIBOOT_UTILS_H + +#include "multiboot.h" +#include "kernel_stdio.h" +#include "types.h" + +struct module* first_module(multiboot_info_t* info); +struct elf_section_header_t * get_elf_section(multiboot_info_t* info, char * section_name); +uint32_t p_to_v(uint32_t physical_address); +void print_multiboot_info(FILE stream, multiboot_info_t* info); + +#endif diff --git a/process.c b/process.c new file mode 100644 index 0000000..18f26b7 --- /dev/null +++ b/process.c @@ -0,0 +1,97 @@ +#include "process.h" + +#include "assembly_interface.h" +#include "data_structures/page_table.h" +#include "memory.h" +#include "kernel_stdio.h" +#include "stdlib.h" + +uint32_t next_pid = 0; + +struct process_t { + uint32_t pid; + page_directory_t pd; +}; + +void create_process(struct file_t* file) { + struct process_t* p = malloc(sizeof(struct process_t)); + p->pid = next_pid; + next_pid += 1; + + page_in(TMP_PAGE_0); + page_directory_t pd = TMP_PAGE_0; + p->pd = pd; + void* pd_physical_address = virtual_to_physical(pd); + + uint32_t pde = make_page_directory_entry( + pd_physical_address, + FOUR_KB, + false, + false, + SUPERVISOR, + READ_WRITE, + true + ); + pd[1023] = pde; + + page_in(TMP_PAGE_1); + page_table_t code_pt = TMP_PAGE_1; + pde = make_page_directory_entry( + virtual_to_physical(code_pt), + FOUR_KB, + false, + false, + USER, + READ_ONLY, + true + ); + pd[0] = pde; + + page_in(TMP_PAGE_2); + void* user_code = TMP_PAGE_2; + uint32_t pte = make_page_table_entry( + virtual_to_physical(user_code), + false, + false, + false, + USER, + READ_ONLY, + true + ); + code_pt[0] = pte; + + page_in(TMP_PAGE_3); + page_table_t stack_pt = TMP_PAGE_3; + pde = make_page_directory_entry( + virtual_to_physical(stack_pt), + FOUR_KB, + false, + false, + USER, + READ_WRITE, + true + ); + pd[page_directory_offset(UPPER_GB_START) - 1] = pde; + + page_in(TMP_PAGE_4); + pte = make_page_table_entry( + virtual_to_physical(TMP_PAGE_4), + false, + false, + false, + USER, + READ_WRITE, + true + ); + stack_pt[1023] = pte; + + map_kernel_into_page_directory(pd); + + for (uint32_t i = 0; i < file->size; i++) { + ((char*)user_code)[i] = (file->bytes)[i]; + } + + set_page_directory(virtual_to_physical(pd)); + + enter_user_mode(); +} \ No newline at end of file diff --git a/process.h b/process.h new file mode 100644 index 0000000..34fec83 --- /dev/null +++ b/process.h @@ -0,0 +1,10 @@ +#ifndef INCLUDE_PROCESS_H +#define INCLUDE_PROCESS_H + +#include "multiboot.h" +#include "types.h" +#include "kernel_filesystem.h" + +void create_process(struct file_t* file); + +#endif /* INCLUDE_PROCESS_H */ \ No newline at end of file diff --git a/program.s b/program.s new file mode 100644 index 0000000..d142bf8 --- /dev/null +++ b/program.s @@ -0,0 +1,8 @@ +BITS 32 ; In a flat binary program, nasm assumes the code will run in 16-bit mode. + ; More advanced executable formats like ELF specify this automatically. + +mov eax, 0xDEADBEEF ; Write a recognizable value to a register just so we know + ; that this program ran. + +jmp $ ; Enter infinite loop, nothing more to do. + ; `$` means "beginning of line", ie. the same instruction. \ No newline at end of file diff --git a/script/build_file_system b/script/build_file_system new file mode 100755 index 0000000..96df07c --- /dev/null +++ b/script/build_file_system @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby + +def include_file(path, output_file) + f2 = File.open(path) + filename = path.split("/").last + output_file.write("FILE #{filename} #{f2.size}\n") + output_file.write(f2.read) + output_file.write("\n") + f2.close +end + +f = File.open('built_file_system', 'w') +include_file("#{File.dirname(__FILE__)}/../shell.bin", f) + +dirname = "#{File.dirname(__FILE__)}/../file_system_root" +Dir.foreach(dirname) do |item| + next if item == '.' or item == '..' + include_file("#{dirname}/#{item}", f) +end + +f.close \ No newline at end of file diff --git a/script/sorted-symbol-table b/script/sorted-symbol-table new file mode 100755 index 0000000..3460ba2 --- /dev/null +++ b/script/sorted-symbol-table @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby +raw = `greadelf --symbols kernel.elf` + +lines = raw.split("\n").drop(3) + +formatted_lines = lines.map do |line| + line.split(":").drop(1).join("").strip +end + +puts formatted_lines.sort.join("\n") \ No newline at end of file diff --git a/script/user_program_dump b/script/user_program_dump new file mode 100755 index 0000000..2d1c449 --- /dev/null +++ b/script/user_program_dump @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby +raw = `xxd user_program.bin` + +lines = raw.split("\n") + +formatted_lines = lines.map do |line| + line[9,41].tr(' ', '') +end + +puts formatted_lines.join("").gsub(/(.{2})/, '\1 ') \ No newline at end of file diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..7d9bad7 --- /dev/null +++ b/shell.c @@ -0,0 +1,51 @@ +#include "stdlib/filesystem.h" +#include "stdlib/stdio.h" +#include "stdlib/string.h" +#include "stdlib/syscalls.h" + +void print_prompt() { + printf("> "); +} + +void handle_ls(char* input) { + bool flag_long = false; + char* flag = input + 2; + while (*flag == ' ') { + flag++; + } + if (*flag != 0) { + if (strncmp(flag, "-l", 2) == 0) { + flag_long = true; + } else { + printf("Unrecognized flag `%s`\n", flag); + return; + } + } + struct file_t files[10]; + uint32_t num_files = count_files(); + list_files(files); + for (uint32_t i = 0; i < num_files; i++) { + if (flag_long) { + printf("%s (%d bytes)\n", files[i].name, files[i].size); + } else { + printf("%s\n", files[i].name); + } + } +} + +void handle_input(char* input) { + if (strncmp(input, "ls", 2) == 0) { + handle_ls(input); + } else { + printf("Unknown command `%s`\n", input); + } + printf("> "); +} + +int main() { + print_prompt(); + register_input_handler(handle_input); + while(1){} + + return 0; +} diff --git a/start_user_program.s b/start_user_program.s new file mode 100644 index 0000000..79d2163 --- /dev/null +++ b/start_user_program.s @@ -0,0 +1,8 @@ +section .text +extern main + mov eax, 0xCAFEBABE + ; push argv + ; push argc + call main + ; main has returned, eax is return value + jmp $ ; loop forever \ No newline at end of file diff --git a/stdarg.h b/stdarg.h new file mode 100644 index 0000000..8be7b67 --- /dev/null +++ b/stdarg.h @@ -0,0 +1,133 @@ +/* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you include this header file into source + files compiled by GCC, this header file does not by itself cause + the resulting executable to be covered by the GNU General Public + License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General + Public License. */ + +/* + * ISO C Standard: 7.15 Variable arguments + */ + +#ifndef _STDARG_H +#ifndef _ANSI_STDARG_H_ +#ifndef __need___va_list +#define _STDARG_H +#define _ANSI_STDARG_H_ +#endif /* not __need___va_list */ +#undef __need___va_list + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef __builtin_va_list __gnuc_va_list; +#endif + +/* Define the standard macros for the user, + if this invocation was from the user program. */ +#ifdef _STDARG_H + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +/* Define va_list, if desired, from __gnuc_va_list. */ +/* We deliberately do not define va_list when called from + stdio.h, because ANSI C says that stdio.h is not supposed to define + va_list. stdio.h needs to have access to that data type, + but must not use that name. It should use the name __gnuc_va_list, + which is safe because it is reserved for the implementation. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef _BSD_VA_LIST +#undef _BSD_VA_LIST +#endif + +#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST)) +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#ifdef _SCO_DS +#define __VA_LIST +#endif +#endif /* _VA_LIST_ */ +#else /* not __svr4__ || _SCO_DS */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. + But on BSD NET2 we must not test or define or undef it. + (Note that the comments in NET 2's ansi.h + are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT) +/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */ +#ifndef _VA_LIST_DEFINED +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +/* The macro __va_list__ is used by BeOS. */ +#ifndef __va_list__ +typedef __gnuc_va_list va_list; +#endif /* not __va_list__ */ +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_DEFINED */ +#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)) +#define _VA_LIST_ +#endif +#ifndef _VA_LIST +#define _VA_LIST +#endif +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED +#endif +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#endif +#ifndef __va_list__ +#define __va_list__ +#endif + +#endif /* not _VA_LIST_, except on certain systems */ + +#endif /* not __svr4__ */ + +#endif /* _STDARG_H */ + +#endif /* not _ANSI_STDARG_H_ */ +#endif /* not _STDARG_H */ \ No newline at end of file diff --git a/stdlib.c b/stdlib.c new file mode 100644 index 0000000..fe8fac7 --- /dev/null +++ b/stdlib.c @@ -0,0 +1,36 @@ +#include "stdlib.h" + +#include "assembly_interface.h" +#include "data_structures/page_table.h" +#include "loader.h" + +// naive strategy for now: keep track of highest allocated +// address, don't worry about freeing memory. + +void* lowest_free_memory = &kernel_stack_lowest_address; + +void* malloc(uint32_t bytes) { + void* chunk_start = lowest_free_memory; + lowest_free_memory += bytes; + + if (lowest_free_memory >= current_stack_pointer()) { + interrupt_out_of_memory(); + } + + return chunk_start; +} + +bool isdigit(char c) { + return c >= '0' && c <= '9'; +} + +int atoi (const char * str) { + int value = 0; + while(isdigit(*str)) { + value *= 10; + value += (*str)-'0'; + str++; + } + + return value; +} \ No newline at end of file diff --git a/stdlib.h b/stdlib.h new file mode 100644 index 0000000..a3f6fc7 --- /dev/null +++ b/stdlib.h @@ -0,0 +1,9 @@ +#ifndef STDLIB_H +#define STDLIB_H + +#include "types.h" + +void* malloc(uint32_t bytes); +int atoi (const char * str); + +#endif /* STDLIB_H */ \ No newline at end of file diff --git a/stdlib/filesystem.h b/stdlib/filesystem.h new file mode 100644 index 0000000..3eec210 --- /dev/null +++ b/stdlib/filesystem.h @@ -0,0 +1,14 @@ +#ifndef INCLUDE_FILESYSTEM_H +#define INCLUDE_FILESYSTEM_H + +#include "types.h" + +#define FILE_NAME_MAX_LENGTH 63 +struct file_t { + char name[FILE_NAME_MAX_LENGTH+1]; + uint32_t size; + char* bytes; + struct file_t* next_sibling; +}; + +#endif /* INCLUDE_FILESYSTEM_H */ \ No newline at end of file diff --git a/stdlib/stdarg.h b/stdlib/stdarg.h new file mode 100644 index 0000000..8be7b67 --- /dev/null +++ b/stdlib/stdarg.h @@ -0,0 +1,133 @@ +/* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you include this header file into source + files compiled by GCC, this header file does not by itself cause + the resulting executable to be covered by the GNU General Public + License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General + Public License. */ + +/* + * ISO C Standard: 7.15 Variable arguments + */ + +#ifndef _STDARG_H +#ifndef _ANSI_STDARG_H_ +#ifndef __need___va_list +#define _STDARG_H +#define _ANSI_STDARG_H_ +#endif /* not __need___va_list */ +#undef __need___va_list + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef __builtin_va_list __gnuc_va_list; +#endif + +/* Define the standard macros for the user, + if this invocation was from the user program. */ +#ifdef _STDARG_H + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +/* Define va_list, if desired, from __gnuc_va_list. */ +/* We deliberately do not define va_list when called from + stdio.h, because ANSI C says that stdio.h is not supposed to define + va_list. stdio.h needs to have access to that data type, + but must not use that name. It should use the name __gnuc_va_list, + which is safe because it is reserved for the implementation. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef _BSD_VA_LIST +#undef _BSD_VA_LIST +#endif + +#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST)) +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#ifdef _SCO_DS +#define __VA_LIST +#endif +#endif /* _VA_LIST_ */ +#else /* not __svr4__ || _SCO_DS */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. + But on BSD NET2 we must not test or define or undef it. + (Note that the comments in NET 2's ansi.h + are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT) +/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */ +#ifndef _VA_LIST_DEFINED +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +/* The macro __va_list__ is used by BeOS. */ +#ifndef __va_list__ +typedef __gnuc_va_list va_list; +#endif /* not __va_list__ */ +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_DEFINED */ +#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)) +#define _VA_LIST_ +#endif +#ifndef _VA_LIST +#define _VA_LIST +#endif +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED +#endif +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#endif +#ifndef __va_list__ +#define __va_list__ +#endif + +#endif /* not _VA_LIST_, except on certain systems */ + +#endif /* not __svr4__ */ + +#endif /* _STDARG_H */ + +#endif /* not _ANSI_STDARG_H_ */ +#endif /* not _STDARG_H */ \ No newline at end of file diff --git a/stdlib/stdio.c b/stdlib/stdio.c new file mode 100644 index 0000000..4121db8 --- /dev/null +++ b/stdlib/stdio.c @@ -0,0 +1,212 @@ +#include "stdio.h" + +#include "stdarg.h" +#include "syscalls.h" + +#define BUFFER_SIZE 128 + +struct buffer_t { + char bytes[BUFFER_SIZE+1]; // 1 bytes for null character + uint8_t bytes_in_buffer; +}; + +void flush_buffer(struct buffer_t* buffer) { + write_to_screen(buffer->bytes); + buffer->bytes_in_buffer = 0; +} + +void write_byte(char byte, struct buffer_t* buffer) { + buffer->bytes[buffer->bytes_in_buffer] = byte; + + buffer->bytes_in_buffer++; + + if (buffer->bytes_in_buffer >= BUFFER_SIZE) { + flush_buffer(buffer); + } +} + +void write_half_byte(uint8_t half_byte, bool upcase, struct buffer_t* buffer) { + switch (half_byte) { + case 0x0: + write_byte('0', buffer); + break; + case 0x1: + write_byte('1', buffer); + break; + case 0x2: + write_byte('2', buffer); + break; + case 0x3: + write_byte('3', buffer); + break; + case 0x4: + write_byte('4', buffer); + break; + case 0x5: + write_byte('5', buffer); + break; + case 0x6: + write_byte('6', buffer); + break; + case 0x7: + write_byte('7', buffer); + break; + case 0x8: + write_byte('8', buffer); + break; + case 0x9: + write_byte('9', buffer); + break; + case 0xA: + write_byte(upcase ? 'A' : 'a', buffer); + break; + case 0xB: + write_byte(upcase ? 'B' : 'b', buffer); + break; + case 0xC: + write_byte(upcase ? 'C' : 'c', buffer); + break; + case 0xD: + write_byte(upcase ? 'D' : 'd', buffer); + break; + case 0xE: + write_byte(upcase ? 'E' : 'e', buffer); + break; + case 0xF: + write_byte(upcase ? 'F' : 'f', buffer); + break; + } +} + +void print_uint8(uint8_t data, struct buffer_t* buffer) { + uint8_t half_byte; + write_byte('0', buffer); + write_byte('x', buffer); + for (int i = 1; i >=0; i--) { + half_byte = (data >> (4*i)) & 0x0F; + write_half_byte(half_byte, true, buffer); + } +} + +void write_string(char* s, struct buffer_t* buffer) { + while(*s) { + write_byte(*s, buffer); + s++; + } +} + +void write_uint(uint32_t value, struct buffer_t* buffer) { + if (value == 0) { + write_byte('0', buffer); + return; + } + + char output[10]; + for (int place = 0; place < 10; place++) { + output[place] = value % 10; + value = value / 10; + } + + bool past_leading_zeroes = false; + for (int place = 9; place >= 0; place--) { + if (output[place] > 0) { + past_leading_zeroes = true; + } + + if (past_leading_zeroes) { + write_byte(output[place] + '0', buffer); + } + } +} + +void write_int(int value, struct buffer_t* buffer) { + if (value < 0) { + write_byte('-', buffer); + value *= -1; + } + write_uint(value, buffer); +} + +void write_octal(uint32_t value, struct buffer_t* buffer) { + write_byte('0', buffer); + write_byte('o', buffer); + bool past_leading_zeroes = false; + uint8_t part = (value >> 30) & 0b11; + if (part > 0) { + write_half_byte(part, true, buffer); + past_leading_zeroes = true; + } + for (int i = 10; i >=0; i--) { + part = (value >> (3*i)) & 0b111; + if (part > 0) { + past_leading_zeroes = true; + } + + if (past_leading_zeroes) { + write_half_byte(part, true, buffer); + } + } +} + +enum format_string_mode {NORMAL, COMMAND}; +int printf (const char * format, ...) { + va_list vl; + va_start(vl,format); + + struct buffer_t buffer; + for (int i = 0; i <=BUFFER_SIZE; i++) { + buffer.bytes[i] = 0; + buffer.bytes_in_buffer = 0; + } + + int i = 0; + enum format_string_mode mode = NORMAL; + uint32_t vararg; + while (format[i]) { + switch (mode) { + case (NORMAL): + if (format[i] == '%') { + mode = COMMAND; + } else { + write_byte(format[i], &buffer); + } + break; + case (COMMAND): + if (format[i] == '%') { + write_byte('%', &buffer); + } else if (format[i] == 'c') { + write_byte((uint32_t) va_arg(vl,uint32_t), &buffer); + } else if (format[i] == 'i' || format[i] == 'd') { + write_int(va_arg(vl, int), &buffer); + } else if (format[i] == 'o') { + write_octal(va_arg(vl, int), &buffer); + } else if (format[i] == 's') { + write_string((char*) va_arg(vl,char*), &buffer); + } else if (format[i] == 'u') { + write_uint(va_arg(vl, uint32_t), &buffer); + } else if (format[i] == 'x') { + write_byte('0', &buffer); + write_byte('x', &buffer); + vararg = va_arg(vl,uint32_t); + for (int i = 7; i >=0; i--) { + write_half_byte((vararg >> (4*i)) & 0x0F, false, &buffer); + } + } else if (format[i] == 'X') { + write_byte('0', &buffer); + write_byte('x', &buffer); + vararg = va_arg(vl,uint32_t); + for (int i = 7; i >=0; i--) { + write_half_byte((vararg >> (4*i)) & 0x0F, true, &buffer); + } + } else { + write_byte('?', &buffer); + mode = NORMAL; + } + mode = NORMAL; + break; + } + i++; + } + flush_buffer(&buffer); + return i; +} \ No newline at end of file diff --git a/stdlib/stdio.h b/stdlib/stdio.h new file mode 100644 index 0000000..8e82ab0 --- /dev/null +++ b/stdlib/stdio.h @@ -0,0 +1,8 @@ +#ifndef STDIO_H +#define STDIO_H + +#include "../types.h" + +int printf (const char * format, ...); + +#endif /* STDIO_H */ \ No newline at end of file diff --git a/stdlib/string.c b/stdlib/string.c new file mode 100644 index 0000000..8bbd046 --- /dev/null +++ b/stdlib/string.c @@ -0,0 +1,51 @@ +#include "string.h" + +/* +Returns an integral value indicating the relationship between the strings: +return value indicates +<0 the first character that does not match has a lower value in ptr1 than in ptr2 +0 the contents of both strings are equal +>0 the first character that does not match has a greater value in ptr1 than in ptr2 +*/ +int strcmp(const char * str1, const char * str2) { + while (*str1 != 0 && *str2 != 0) { + int diff = *str1 - *str2; + if (diff != 0) { + return diff; + } + + str1++; + str2++; + } + + // One of these points to 0 + return *str1 - *str2; +} + +int strncmp (const char * str1, const char * str2, uint32_t num) { + while (*str1 != 0 && *str2 != 0 && num > 1) { + int diff = *str1 - *str2; + if (diff != 0) { + return diff; + } + + str1++; + str2++; + num--; + } + + return *str1 - *str2; +} + +void* memcpy (void* dest, const void* src, uint32_t count) { + char* dest_byte = (char*) dest; + char* src_byte = (char*) src; + + for (uint32_t i = 0; i < count; i++) { + *dest_byte = *src_byte; + dest_byte++; + src_byte++; + } + + return dest; +} \ No newline at end of file diff --git a/stdlib/string.h b/stdlib/string.h new file mode 100644 index 0000000..d1b7ea6 --- /dev/null +++ b/stdlib/string.h @@ -0,0 +1,10 @@ +#ifndef STRING_H +#define STRING_H + +#include "types.h" + +void* memcpy (void* dest, const void* src, uint32_t count); +int strcmp (const char * str1, const char * str2); +int strncmp (const char * str1, const char * str2, uint32_t num); + +#endif /* STRING_H */ \ No newline at end of file diff --git a/stdlib/syscalls.h b/stdlib/syscalls.h new file mode 100644 index 0000000..99dfab0 --- /dev/null +++ b/stdlib/syscalls.h @@ -0,0 +1,22 @@ +#ifndef INCLUDE_SYSCALLS_H +#define INCLUDE_SYSCALLS_H + +#include "types.h" +#include "filesystem.h" + +enum _Syscall { + WRITE_TO_SCREEN, + COUNT_FILES, + LIST_FILES, + REGISTER_INPUT_HANDLER +}; +typedef enum _Syscall Syscall; + +void write_to_screen(char* s); +uint32_t count_files(); +void list_files(struct file_t buffer[]); + +typedef void (*InputHandler)(char*); +void register_input_handler(InputHandler handler); + +#endif /* INCLUDE_SYSCALLS_H */ \ No newline at end of file diff --git a/stdlib/syscalls.s b/stdlib/syscalls.s new file mode 100644 index 0000000..5db2e44 --- /dev/null +++ b/stdlib/syscalls.s @@ -0,0 +1,38 @@ +section .text +global write_to_screen +; write_to_screen +; stack: [esp + 4] string +; [esp ] return address +write_to_screen: + mov eax, 0 + mov ebx, [esp+4] + int 0x80 + ret ; return to the calling function + +global count_files +; count_files +; stack: [esp ] return address +count_files: + mov eax, 1 + int 0x80 + ret ; return to the calling function + +global list_files +; list_files +; stack: [esp + 4] address of buffer +; [esp ] return address +list_files: + mov eax, 2 + mov ebx, [esp+4] + int 0x80 + ret ; return to the calling function + +global register_input_handler +; register_input_handler +; stack: [esp + 4] address of handler +; [esp ] return address +register_input_handler: + mov eax, 3 + mov ebx, [esp+4] + int 0x80 + ret ; return to the calling function diff --git a/stdlib/types.h b/stdlib/types.h new file mode 100644 index 0000000..4b96d9e --- /dev/null +++ b/stdlib/types.h @@ -0,0 +1,22 @@ +#ifndef INCLUDE_TYPES_H +#define INCLUDE_TYPES_H + +typedef unsigned char int8; +typedef int8 byte; +typedef unsigned short int16; +typedef int16 byte2; +typedef unsigned long int32; +typedef int16 byte4; +typedef unsigned long long int64; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; + +typedef void (*void_function_t)(void); + +#define bool char +#define true 1 +#define false 0 + +#endif /* INCLUDE_TYPES_H */ \ No newline at end of file diff --git a/types.h b/types.h index 9b2309d..4b96d9e 100644 --- a/types.h +++ b/types.h @@ -1,3 +1,6 @@ +#ifndef INCLUDE_TYPES_H +#define INCLUDE_TYPES_H + typedef unsigned char int8; typedef int8 byte; typedef unsigned short int16; @@ -8,4 +11,12 @@ typedef unsigned long long int64; typedef unsigned char uint8_t; typedef unsigned short uint16_t; -typedef unsigned long uint32_t; \ No newline at end of file +typedef unsigned long uint32_t; + +typedef void (*void_function_t)(void); + +#define bool char +#define true 1 +#define false 0 + +#endif /* INCLUDE_TYPES_H */ \ No newline at end of file