├── .github └── workflows │ ├── ci-cd.yml │ └── tagged-release.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── config.sh ├── disk.img ├── docs ├── Makefile ├── make.bat └── source │ ├── conf.py │ ├── docs_source │ ├── drivers │ │ └── ata │ │ │ └── ata_driver.rst │ ├── libc │ │ ├── kassert.rst │ │ ├── kerrno.rst │ │ └── kstring.rst │ └── utils │ │ └── data_structures │ │ └── hashmap │ │ └── hashmap.rst │ └── index.rst ├── generate_grubcfg.sh ├── get_pwd.sh ├── grub.cfg ├── is_multiboot.sh ├── kernel ├── Makefile ├── arch │ └── i686 │ │ ├── acpica │ │ ├── Makefile │ │ ├── acapps.h │ │ ├── acbuffer.h │ │ ├── acclib.h │ │ ├── accommon.h │ │ ├── acconfig.h │ │ ├── acconvert.h │ │ ├── acdebug.h │ │ ├── acdisasm.h │ │ ├── acdispat.h │ │ ├── acevents.h │ │ ├── acexcep.h │ │ ├── acglobal.h │ │ ├── achware.h │ │ ├── acinterp.h │ │ ├── aclocal.h │ │ ├── acmacros.h │ │ ├── acnames.h │ │ ├── acnamesp.h │ │ ├── acobject.h │ │ ├── acopcode.h │ │ ├── acoutput.h │ │ ├── acparser.h │ │ ├── acpi.h │ │ ├── acpiosxf.h │ │ ├── acpixf.h │ │ ├── acpredef.h │ │ ├── acresrc.h │ │ ├── acrestyp.h │ │ ├── acstruct.h │ │ ├── actables.h │ │ ├── actbinfo.h │ │ ├── actbl.h │ │ ├── actbl1.h │ │ ├── actbl2.h │ │ ├── actbl3.h │ │ ├── actypes.h │ │ ├── acutils.h │ │ ├── acuuid.h │ │ ├── amlcode.h │ │ ├── amlresrc.h │ │ ├── dispatcher │ │ │ ├── dsargs.c │ │ │ ├── dscontrol.c │ │ │ ├── dsdebug.c │ │ │ ├── dsfield.c │ │ │ ├── dsinit.c │ │ │ ├── dsmethod.c │ │ │ ├── dsmthdat.c │ │ │ ├── dsobject.c │ │ │ ├── dsopcode.c │ │ │ ├── dspkginit.c │ │ │ ├── dsutils.c │ │ │ ├── dswexec.c │ │ │ ├── dswload.c │ │ │ ├── dswload2.c │ │ │ ├── dswscope.c │ │ │ └── dswstate.c │ │ ├── events │ │ │ ├── evevent.c │ │ │ ├── evglock.c │ │ │ ├── evgpe.c │ │ │ ├── evgpeblk.c │ │ │ ├── evgpeinit.c │ │ │ ├── evgpeutil.c │ │ │ ├── evhandler.c │ │ │ ├── evmisc.c │ │ │ ├── evregion.c │ │ │ ├── evrgnini.c │ │ │ ├── evsci.c │ │ │ ├── evxface.c │ │ │ ├── evxfevnt.c │ │ │ ├── evxfgpe.c │ │ │ └── evxfregn.c │ │ ├── executer │ │ │ ├── exconcat.c │ │ │ ├── exconfig.c │ │ │ ├── exconvrt.c │ │ │ ├── excreate.c │ │ │ ├── exdebug.c │ │ │ ├── exdump.c │ │ │ ├── exfield.c │ │ │ ├── exfldio.c │ │ │ ├── exmisc.c │ │ │ ├── exmutex.c │ │ │ ├── exnames.c │ │ │ ├── exoparg1.c │ │ │ ├── exoparg2.c │ │ │ ├── exoparg3.c │ │ │ ├── exoparg6.c │ │ │ ├── exprep.c │ │ │ ├── exregion.c │ │ │ ├── exresnte.c │ │ │ ├── exresolv.c │ │ │ ├── exresop.c │ │ │ ├── exserial.c │ │ │ ├── exstore.c │ │ │ ├── exstoren.c │ │ │ ├── exstorob.c │ │ │ ├── exsystem.c │ │ │ ├── extrace.c │ │ │ └── exutils.c │ │ ├── hardware │ │ │ ├── hwacpi.c │ │ │ ├── hwesleep.c │ │ │ ├── hwgpe.c │ │ │ ├── hwpci.c │ │ │ ├── hwregs.c │ │ │ ├── hwsleep.c │ │ │ ├── hwtimer.c │ │ │ ├── hwvalid.c │ │ │ ├── hwxface.c │ │ │ └── hwxfsleep.c │ │ ├── namespace │ │ │ ├── nsaccess.c │ │ │ ├── nsalloc.c │ │ │ ├── nsarguments.c │ │ │ ├── nsconvert.c │ │ │ ├── nsdump.c │ │ │ ├── nsdumpdv.c │ │ │ ├── nseval.c │ │ │ ├── nsinit.c │ │ │ ├── nsload.c │ │ │ ├── nsnames.c │ │ │ ├── nsobject.c │ │ │ ├── nsparse.c │ │ │ ├── nspredef.c │ │ │ ├── nsprepkg.c │ │ │ ├── nsrepair.c │ │ │ ├── nsrepair2.c │ │ │ ├── nssearch.c │ │ │ ├── nsutils.c │ │ │ ├── nswalk.c │ │ │ ├── nsxfeval.c │ │ │ ├── nsxfname.c │ │ │ └── nsxfobj.c │ │ ├── parser │ │ │ ├── psargs.c │ │ │ ├── psloop.c │ │ │ ├── psobject.c │ │ │ ├── psopcode.c │ │ │ ├── psopinfo.c │ │ │ ├── psparse.c │ │ │ ├── psscope.c │ │ │ ├── pstree.c │ │ │ ├── psutils.c │ │ │ ├── pswalk.c │ │ │ └── psxface.c │ │ ├── platform │ │ │ ├── accygwin.h │ │ │ ├── acefi.h │ │ │ ├── acefiex.h │ │ │ ├── acenv.h │ │ │ ├── acenvex.h │ │ │ ├── acgcc.h │ │ │ ├── acgccex.h │ │ │ ├── acintel.h │ │ │ ├── acos2.h │ │ │ ├── acqnx.h │ │ │ └── acrocketos.h │ │ ├── resources │ │ │ ├── rsaddr.c │ │ │ ├── rscalc.c │ │ │ ├── rscreate.c │ │ │ ├── rsdumpinfo.c │ │ │ ├── rsinfo.c │ │ │ ├── rsio.c │ │ │ ├── rsirq.c │ │ │ ├── rslist.c │ │ │ ├── rsmemory.c │ │ │ ├── rsmisc.c │ │ │ ├── rsserial.c │ │ │ ├── rsutils.c │ │ │ └── rsxface.c │ │ ├── tables │ │ │ ├── tbdata.c │ │ │ ├── tbfadt.c │ │ │ ├── tbfind.c │ │ │ ├── tbinstal.c │ │ │ ├── tbprint.c │ │ │ ├── tbutils.c │ │ │ ├── tbxface.c │ │ │ ├── tbxfload.c │ │ │ └── tbxfroot.c │ │ └── utilities │ │ │ ├── utaddress.c │ │ │ ├── utalloc.c │ │ │ ├── utascii.c │ │ │ ├── utbuffer.c │ │ │ ├── utcache.c │ │ │ ├── utclib.c │ │ │ ├── utcopy.c │ │ │ ├── utdebug.c │ │ │ ├── utdecode.c │ │ │ ├── utdelete.c │ │ │ ├── uterror.c │ │ │ ├── uteval.c │ │ │ ├── utexcep.c │ │ │ ├── utglobal.c │ │ │ ├── uthex.c │ │ │ ├── utids.c │ │ │ ├── utinit.c │ │ │ ├── utlock.c │ │ │ ├── utmath.c │ │ │ ├── utmisc.c │ │ │ ├── utmutex.c │ │ │ ├── utnonansi.c │ │ │ ├── utobject.c │ │ │ ├── utosi.c │ │ │ ├── utownerid.c │ │ │ ├── utpredef.c │ │ │ ├── utprint.c │ │ │ ├── utresdecode.c │ │ │ ├── utresrc.c │ │ │ ├── utstate.c │ │ │ ├── utstring.c │ │ │ ├── utstrsuppt.c │ │ │ ├── utstrtoul64.c │ │ │ ├── uttrack.c │ │ │ ├── utuuid.c │ │ │ ├── utxface.c │ │ │ ├── utxferror.c │ │ │ ├── utxfinit.c │ │ │ └── utxfmutex.c │ │ ├── boot │ │ ├── boot_PT.s │ │ ├── kernel.c │ │ ├── multiboot.h │ │ ├── multiboot_header.s │ │ └── upperhalf_boot.s │ │ ├── drivers │ │ ├── hdd │ │ │ └── ahci │ │ │ │ ├── ahci.c │ │ │ │ └── ahci.h │ │ ├── keyboard │ │ │ ├── default_keyboard_logic.c │ │ │ ├── default_keyboard_logic.h │ │ │ ├── keyboard_driver.c │ │ │ └── keyboard_driver.h │ │ ├── pci │ │ │ ├── legacy_pci │ │ │ │ ├── pci_bus.c │ │ │ │ └── pci_bus.h │ │ │ └── pcie │ │ │ │ ├── pcie_bus.c │ │ │ │ └── pcie_bus.h │ │ ├── pit │ │ │ ├── pit.c │ │ │ └── pit.h │ │ ├── port_mapped_io │ │ │ ├── hardware_communication.s │ │ │ ├── hardware_io.c │ │ │ └── hardware_io.h │ │ ├── serial │ │ │ ├── serial_driver.c │ │ │ └── serial_driver.h │ │ └── vga_driver │ │ │ ├── default_vga_driver.c │ │ │ ├── default_vga_driver.h │ │ │ ├── vga_driver.c │ │ │ └── vga_driver.h │ │ ├── interrupts │ │ ├── enable_interrupts.s │ │ ├── interrupt_handler.s │ │ ├── interrupt_types.h │ │ ├── interrupts.c │ │ └── interrupts.h │ │ ├── linker.ld │ │ ├── make.config │ │ ├── osi_shim │ │ ├── acpi_init.c │ │ ├── acpi_init.h │ │ └── osi.c │ │ └── usermode │ │ ├── gdt.c │ │ ├── gdt.h │ │ ├── gdt_entries.s │ │ ├── system_call_handler.s │ │ └── system_call_implementations.h ├── include │ └── kernel │ │ └── utils │ │ └── communication_and_events │ │ ├── message_queue.h │ │ └── observer.h ├── kernel │ ├── ATA │ │ ├── ata_driver.c │ │ └── ata_driver.h │ ├── mem │ │ ├── higher_half_utils.h │ │ ├── initialize_kernel_memory.c │ │ ├── initialize_kernel_memory.h │ │ ├── mem_constants.h │ │ ├── paging │ │ │ ├── enable_paging.s │ │ │ ├── paging.c │ │ │ └── paging.h │ │ ├── phys │ │ │ ├── global_phys_allocator.c │ │ │ └── global_phys_allocator.h │ │ └── virt │ │ │ ├── heap_virt_mem_allocator.c │ │ │ ├── heap_virt_mem_allocator.h │ │ │ ├── kernel_virt_allocator.c │ │ │ ├── kernel_virt_allocator.h │ │ │ ├── osi_virt_mem_allocator.c │ │ │ └── osi_virt_mem_allocator.h │ ├── scheduler │ │ ├── process.h │ │ ├── scheduler.c │ │ ├── scheduler.h │ │ ├── task_switch.s │ │ ├── timer.c │ │ └── timer.h │ ├── subsystems │ │ └── terminal │ │ │ ├── default_terminal_functions.c │ │ │ ├── default_terminal_functions.h │ │ │ ├── default_terminal_system.c │ │ │ ├── default_terminal_system.h │ │ │ ├── keyboard_callbacks.c │ │ │ ├── keyboard_callbacks.h │ │ │ ├── terminal_driver.c │ │ │ └── terminal_driver.h │ ├── synchronization_primitives │ │ ├── int_lock.c │ │ ├── int_lock.h │ │ ├── spinlock.c │ │ └── spinlock.h │ ├── tar_fs │ │ ├── tar.c │ │ └── tar.h │ └── utils │ │ ├── algorithms │ │ ├── comparison.h │ │ ├── sort │ │ │ ├── quicksort.c │ │ │ └── quicksort.h │ │ ├── swap.c │ │ └── swap.h │ │ ├── allocators │ │ ├── bitmap │ │ │ ├── bitmap_allocator.c │ │ │ └── bitmap_allocator.h │ │ └── buddy │ │ │ ├── buddy_memory_allocator.c │ │ │ └── buddy_memory_allocator.h │ │ ├── bitset │ │ ├── bitset.c │ │ └── bitset.h │ │ ├── data_structures │ │ ├── hashmap │ │ │ ├── default_hashmap_functions.c │ │ │ ├── default_hashmap_functions.h │ │ │ └── hashmap.h │ │ ├── string │ │ │ ├── string.c │ │ │ └── string.h │ │ └── vector │ │ │ ├── vector.c │ │ │ └── vector.h │ │ └── wrappers │ │ ├── physical_pointer.c │ │ └── physical_pointer.h └── libk │ ├── kassert.h │ ├── kctype.c │ ├── kctype.h │ ├── kerrno.c │ ├── kerrno.h │ ├── kmath.c │ ├── kmath.h │ ├── kstdio.c │ ├── kstdio.h │ ├── kstdlib.c │ ├── kstdlib.h │ ├── kstring.c │ ├── kstring.h │ ├── optional.h │ └── sys │ └── kstdlib_constants.h ├── logo ├── Rocket.svg ├── rocket_min.svg ├── social-preview-wip.svg ├── social-preview.svg ├── webicon.svg └── webicon_min.svg ├── make.config ├── make_ramdisk.py ├── ramdisk_files ├── bar.txt ├── baz.txt ├── foo.txt ├── port_io.c ├── port_io.h ├── serial.c ├── serial.h ├── strlen.c ├── strlen.h ├── test_program └── test_program.c ├── test ├── libc │ ├── Test-kstdlib.c │ ├── Test-kstring.c │ ├── Test-kstring2.c │ ├── Test-kstring3.c │ └── Test-kstring4.c ├── test_kernel_early.h ├── unity_config.h └── utils │ └── data_structures │ └── hashmap │ └── Test-hashmap.c ├── toolchain.sh └── userspace └── Makefile /.github/workflows/ci-cd.yml: -------------------------------------------------------------------------------- 1 | name: CI/CD 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | container: 13 | image: ghcr.io/operatingsystemrocket/image:latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Checkout submodules # checkout rest 17 | shell: bash 18 | run: | 19 | auth_header="$(git config --local --get http.https://github.com/.extraheader)" 20 | git submodule sync --recursive 21 | git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 22 | - name: tests 23 | run: make build 24 | 25 | test: 26 | runs-on: ubuntu-latest 27 | container: 28 | image: ghcr.io/operatingsystemrocket/image:latest 29 | steps: 30 | - uses: actions/checkout@v2 31 | - name: Checkout submodules # checkout rest 32 | shell: bash 33 | run: | 34 | auth_header="$(git config --local --get http.https://github.com/.extraheader)" 35 | git submodule sync --recursive 36 | git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 37 | - name: tests 38 | run: make test TEST=1 39 | 40 | #horribly inefficient since it reruns the tests. TODO: fix 41 | pre-release: 42 | runs-on: ubuntu-latest 43 | container: 44 | image: ghcr.io/operatingsystemrocket/image:latest 45 | steps: 46 | - uses: actions/checkout@v2 47 | - name: Checkout submodules # checkout rest 48 | shell: bash 49 | run: | 50 | auth_header="$(git config --local --get http.https://github.com/.extraheader)" 51 | git submodule sync --recursive 52 | git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 53 | - name: tests 54 | run: make test TEST=1 55 | - name: clean 56 | run: make clean #clean so that we can do a release build and release it 57 | - name: release-build 58 | run: make RELEASE=1 #do release build 59 | - uses: "marvinpinto/action-automatic-releases@latest" 60 | with: 61 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 62 | automatic_release_tag: "latest" 63 | prerelease: true 64 | title: "Development Build" 65 | files: | 66 | LICENSE 67 | build/results/os.iso 68 | -------------------------------------------------------------------------------- /.github/workflows/tagged-release.yml: -------------------------------------------------------------------------------- 1 | name: Tagged Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | tagged-release: 10 | runs-on: ubuntu-latest 11 | container: 12 | image: ghcr.io/operatingsystemrocket/image:latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Checkout submodules # checkout rest 17 | shell: bash 18 | run: | 19 | auth_header="$(git config --local --get http.https://github.com/.extraheader)" 20 | git submodule sync --recursive 21 | git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1 22 | - name: tests 23 | run: make test TEST=1 24 | - name: clean 25 | run: make clean #clean so that we can do a release build and release it 26 | - name: release-build 27 | run: make RELEASE=1 #do release build 28 | - uses: "marvinpinto/action-automatic-releases@latest" 29 | with: 30 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 31 | prerelease: false 32 | files: | 33 | LICENSE 34 | build/results/os.iso 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | *.i 10 | ramdisk.img 11 | build/ 12 | sysroot/ 13 | 14 | # Linker output 15 | *.ilk 16 | *.map 17 | *.exp 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Libraries 24 | *.lib 25 | *.a 26 | *.la 27 | *.lo 28 | 29 | # Shared objects (inc. Windows DLLs) 30 | *.dll 31 | *.so 32 | *.so.* 33 | *.dylib 34 | 35 | # Executables 36 | *.exe 37 | *.out 38 | *.app 39 | *.i*86 40 | *.x86_64 41 | *.hex 42 | 43 | *.bin 44 | *.iso 45 | *.kernel 46 | isodir/ 47 | 48 | # Debug files 49 | *.dSYM/ 50 | *.su 51 | *.idb 52 | *.pdb 53 | 54 | # Kernel Module Compile Results 55 | *.mod* 56 | *.cmd 57 | .tmp_versions/ 58 | modules.order 59 | Module.symvers 60 | Mkfile.old 61 | dkms.conf 62 | 63 | # Documentation output 64 | *.html 65 | *.pdf 66 | 67 | # Editor configs 68 | .idea/ 69 | .vscode/ 70 | *.json 71 | *.xml 72 | 73 | # Documatic settings 74 | .env 75 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Unity"] 2 | path = Unity 3 | url = https://github.com/OperatingSystemRocket/Unity.git 4 | [submodule "acpica"] 5 | path = acpica 6 | url = https://github.com/OperatingSystemRocket/acpica.git 7 | [submodule "mlibc"] 8 | path = mlibc 9 | url = https://github.com/managarm/mlibc.git 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 OperatingSystemRocket 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #PROJECTS := userspace/ kernel/ 2 | PROJECTS := kernel/ 3 | HEADER_PROJECTS := ${PROJECTS} 4 | 5 | .PHONY: all build_iso clean build headers 6 | .SUFFIXES: .o .c .S 7 | 8 | all : build_iso 9 | 10 | build_iso : build 11 | mkdir -p isodir/ 12 | mkdir -p isodir/boot/ 13 | mkdir -p isodir/boot/grub/ 14 | cp kernel/rocketos.kernel isodir/boot/rocketos.kernel 15 | cp ramdisk.img isodir/boot/ramdisk.img 16 | cp grub.cfg isodir/boot/grub/grub.cfg 17 | grub-mkrescue -o os.iso isodir 18 | 19 | run : build_iso 20 | qemu-system-i386 -machine q35 -soundhw pcspk -serial stdio -drive file=disk.img,format=raw,index=0 -cdrom os.iso 21 | 22 | build : headers 23 | @for e in ${HEADER_PROJECTS}; do \ 24 | (cd $$e; $(MAKE) install); done 25 | 26 | release : headers 27 | @for e in ${HEADER_PROJECTS}; do \ 28 | (cd $$e; $(MAKE) install RELEASE=1); done 29 | 30 | headers : 31 | @for e in ${HEADER_PROJECTS}; do \ 32 | (cd $$e; $(MAKE) install-headers); done 33 | 34 | clean : 35 | @for e in ${PROJECTS}; do \ 36 | (cd $$e; $(MAKE) clean); done 37 | -rm -r sysroot/ 38 | -rm -r isodir/ 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | RocketOS logo 3 |

4 | 5 | #

RocketOS

6 | 7 |

8 | 9 | C/C++ CI 10 | 11 | 12 | Docs 13 | 14 | 15 | Pre-Releases 16 | 17 | 18 | License 19 | 20 |

21 | 22 | 23 | ## What is RocketOS? 24 | 25 | RocketOS is a Unix based OS that uses legacy BIOS and GRUB and is written in C17. 26 | It is being developed for educational purposes primarily, but it still is a serious project. 27 | It is currently in its infancy. 28 | 29 | 30 | ## Development Environment 31 | 32 | This guide assumes a unix environment with access to the `apt` package manager. 33 | You will have to manually edit the install script on other platforms. 34 | This repo provides a bash script that when run will install and setup all software required to develop RocketOS. 35 | To use it, just download `toolchain.sh` and run it. 36 | Follow any prompts for putting in your root password. 37 | This script will be building gcc from source, so it might take a while to finish. 38 | 39 | 40 | ## How to install RocketOS 41 | 42 | Navigate to releases. 43 | 44 | You should also have obtained a copy of the MIT license together with this project. 45 | If not, go to: https://mit-license.org/. 46 | You can download and use this iso without any software. 47 | Flash the iso to a USB or run it in a VM and then the OS should boot and dump you into a terminal. 48 | 49 | 50 | ## How to contribute 51 | 52 | RocketOS is currently very early in its development, but we do have a CI/CD system and can handle external pull requests. 53 | The most useful thing currently would be contributions or filing issues (though issues of any kind are welcome) 54 | in unit tests and documentation as there is currently a backlog. 55 | To contribute you must agree to have your code and other changes licensed under the MIT license. 56 | We do not currently require you to forfeit your individual copyright to your changes. 57 | 58 | 59 | ## Where can I find the docs? 60 | 61 | Documentation 62 | 63 | 64 | ## Acknowledgments 65 | All the amazing art assets and designs used for the README.md, url preview, and located in `logos/` 66 | were created by: https://github.com/StefanGreve. Check them out! 67 | 68 | 69 | ## Roadmap 70 | 71 | - [x] Global Descriptor Table 72 | - [x] CPU Interrupts 73 | - [x] VGA Driver 74 | - [x] Keyboard Support 75 | - [x] Basic Working Text Terminal 76 | - [x] Serial Driver 77 | - [ ] Mouse Support 78 | - [x] Paging and Virtual Memory 79 | - [x] Dynamic Memory Allocation 80 | - [x] (PIC) Timer 81 | - [x] Tasks and Scheduling 82 | - [ ] Full Process support (in progress) 83 | - [ ] Floating Point Number Support 84 | - [ ] Time and Calendar 85 | - [x] Privilege Levels (Protection Rings) 86 | - [ ] ELF Loader 87 | - [ ] Disk/HDD Support (ATA driver) 88 | - [ ] Filesystem 89 | - [ ] Full libc Implementation 90 | - [ ] Basic GUI Support 91 | -------------------------------------------------------------------------------- /config.sh: -------------------------------------------------------------------------------- 1 | #export MAKE=${MAKE:-make} 2 | export HOST=${HOST:-i686} 3 | 4 | export AR=${HOST}-ar 5 | export AS=${HOST}-as 6 | export CC=${HOST}-gcc 7 | 8 | export PREFIX=/usr 9 | export EXEC_PREFIX=$PREFIX 10 | export BOOTDIR=/boot 11 | export LIBDIR=$EXEC_PREFIX/lib 12 | export INCLUDEDIR=$PREFIX/include 13 | 14 | export CFLAGS='-O2 -g' 15 | export CPPFLAGS='' 16 | 17 | # Configure the cross-compiler to use the desired system root. 18 | export SYSROOT="$(pwd)/sysroot" 19 | export CC="$CC --sysroot=$SYSROOT" 20 | 21 | export DESTDIR=${SYSROOT} 22 | 23 | # Work around that the -elf gcc targets doesn't have a system include directory 24 | # because it was configured with --without-headers rather than --with-sysroot. 25 | if echo "$HOST" | grep -Eq -- '-elf($|-)'; then 26 | export CC="$CC -isystem=$INCLUDEDIR" 27 | fi 28 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | 2 | # Configuration file for the Sphinx documentation builder. 3 | # 4 | # This file only contains a selection of the most common options. For a full 5 | # list see the documentation: 6 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 7 | 8 | # -- Path setup -------------------------------------------------------------- 9 | 10 | # If extensions (or modules to document with autodoc) are in another directory, 11 | # add these directories to sys.path here. If the directory is relative to the 12 | # documentation root, use os.path.abspath to make it absolute, like shown here. 13 | # 14 | # import os 15 | # import sys 16 | # sys.path.insert(0, os.path.abspath('.')) 17 | 18 | import sphinx_rtd_theme 19 | 20 | 21 | # -- Project information ----------------------------------------------------- 22 | 23 | project = 'RocketOS' 24 | copyright = '2021, Lincoln S, Dexter W, Alan E' 25 | author = 'Lincoln S, Dexter W, Alan E' 26 | 27 | # The full version, including alpha/beta/rc tags 28 | release = '0.0.1' 29 | 30 | 31 | # -- General configuration --------------------------------------------------- 32 | 33 | # Add any Sphinx extension module names here, as strings. They can be 34 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 35 | # ones. 36 | extensions = [ 37 | "sphinx.ext.intersphinx", 38 | "sphinx.ext.autodoc", 39 | "sphinx.ext.mathjax", 40 | "sphinx.ext.viewcode", 41 | "sphinx_rtd_theme", 42 | ] 43 | 44 | # Add any paths that contain templates here, relative to this directory. 45 | templates_path = ['_templates'] 46 | 47 | # List of patterns, relative to source directory, that match files and 48 | # directories to ignore when looking for source files. 49 | # This pattern also affects html_static_path and html_extra_path. 50 | exclude_patterns = [] 51 | 52 | # -- Options for HTML output ------------------------------------------------- 53 | 54 | # The theme to use for HTML and HTML Help pages. See the documentation for 55 | # a list of builtin themes. 56 | # 57 | html_theme = 'sphinx_rtd_theme' 58 | 59 | # Add any paths that contain custom static files (such as style sheets) here, 60 | # relative to this directory. They are copied after the builtin static files, 61 | # so a file named "default.css" will overwrite the builtin "default.css". 62 | html_static_path = ['_static'] 63 | -------------------------------------------------------------------------------- /docs/source/docs_source/drivers/ata/ata_driver.rst: -------------------------------------------------------------------------------- 1 | ata_driver 2 | =========== 3 | 4 | .. |br| raw:: html 5 | 6 |
7 | 8 | This module has 4 functions that are defined as 9 | follows: 10 | 11 | ``void ata_driver_init(void);`` 12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13 | 14 | This function initializes the 15 | internal data structures of 16 | the ata driver and must be 17 | called before any other ata 18 | driver functions. 19 | 20 | **Example Usage**:: 21 | 22 | #include "ata_driver.h" 23 | 24 | int main(void) { 25 | ata_driver_init(); 26 | 27 | //call any ata driver functions you want 28 | 29 | return 0; 30 | } 31 | 32 | |br| 33 | 34 | ``void ata_driver_write_n(const char* data_stream, size_t byte_location, size_t data_stream_size);`` 35 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 36 | 37 | This function writes ``data_stream_size`` 38 | amount of bytes from ``data_stream`` 39 | to the HDD at location ``byte_location``. 40 | 41 | **Example Usage**:: 42 | 43 | #include "ata_driver.h" 44 | 45 | int main(void) { 46 | ata_driver_init(); 47 | 48 | ata_driver_write_n("Hello World!", 0u, 5u); //only wrote "Hello" to the HDD 49 | } 50 | 51 | ``void ata_driver_write(const char* data_stream, size_t byte_location);`` 52 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 53 | 54 | This function is a utility function that is equivalent to calling 55 | ``ata_driver_write_n(data_stream, byte_location, strlen(data_stream));``. 56 | ``data_stream`` must be a null terminated string. 57 | 58 | **Example Usage**:: 59 | 60 | #include "ata_driver.h" 61 | 62 | int main(void) { 63 | ata_driver_init(); 64 | 65 | ata_driver_write("Hello", 0u); //"Hello" is written to HDD 66 | } 67 | 68 | |br| 69 | 70 | ``void ata_driver_read_n(char* bufffer, size_t byte_location, size_t byte_count);`` 71 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 72 | 73 | This function reads ``byte_count`` 74 | bytes from the HDD starting 75 | at ``byte_location`` into the user 76 | allocated buffer ``buffer``. 77 | 78 | **Example Usage**:: 79 | 80 | #include "ata_driver.h" 81 | #include "kstdio.h" 82 | 83 | int main(void) { 84 | ata_driver_init(); 85 | 86 | void ata_driver_write("Hello", 0u); 87 | char buffer[10]; 88 | ata_driver_read_n(buffer, 0u, 5u); 89 | buffer[5] = '\0'; //ata_driver_read doesn't null terminate the buffer 90 | 91 | kprintf("%s\n", buffer); 92 | 93 | return 0; 94 | } 95 | 96 | **Output**: 97 | 98 | Hello 99 | 100 | |br| 101 | 102 | -------------------------------------------------------------------------------- /docs/source/docs_source/libc/kassert.rst: -------------------------------------------------------------------------------- 1 | kassert 2 | ======= 3 | 4 | .. |br| raw:: html 5 | 6 |
7 | 8 | This module has four macros and is header only. 9 | The four macros are as follows: 10 | 11 | ``kassert(cond, return_code)`` 12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13 | 14 | This macro should be used 15 | in non-void functions 16 | for assertions that don't need custom error messages. 17 | 18 | **Example Usage**:: 19 | 20 | #include "kassert.h" 21 | #include "kstdio.h" 22 | 23 | int func(void) { 24 | kassert(1 == 2, -1); 25 | } 26 | 27 | int main(void) { 28 | terminal_initialize(); 29 | const int x = func(); 30 | kprintf("%i\n", x); 31 | return 0; 32 | } 33 | 34 | **Output**: 35 | 36 | .. raw:: html 37 | 38 | [file: foo/bar.c :: line: 5]: Condition Failed: 1==2 39 | 40 | -1 41 | 42 | |br| 43 | 44 | ``kassert_void(cond)`` 45 | ^^^^^^^^^^^^^^^^^^^^^^^ 46 | 47 | This macro should be used 48 | in void functions 49 | for assertions that don't need custom error messages. 50 | 51 | **Example Usage**:: 52 | 53 | #include "kassert.h" 54 | 55 | void func(void) { 56 | kassert_void(1 == 2); 57 | } 58 | 59 | int main(void) { 60 | terminal_initialize(); 61 | func(); 62 | return 0; 63 | } 64 | 65 | **Output**: 66 | 67 | .. raw:: html 68 | 69 | [file: foo/bar.c :: line: 5]: Condition Failed: 1==2 70 | 71 | |br| 72 | 73 | ``kassert_message(cond, message, return_code)`` 74 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 75 | 76 | This macro should be used 77 | in non-void functions 78 | for assertions that need custom error messages. 79 | 80 | **Example Usage**:: 81 | 82 | #include "kassert.h" 83 | #include "kstdio.h" 84 | 85 | 86 | int func(void) { 87 | kassert_message(1 == 2, "arithmetic is broken", -1); 88 | } 89 | 90 | int main(void) { 91 | terminal_initialize(); 92 | const int x = func(); 93 | printf("%i\n", x); 94 | return 0; 95 | } 96 | 97 | **Output**: 98 | 99 | .. raw:: html 100 | 101 | arithmetic is broken 102 | 103 | -1 104 | 105 | |br| 106 | 107 | ``kassert_message_void(cond, message)`` 108 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 109 | 110 | This macro should be used 111 | in void functions 112 | for assertions that need custom error messages. 113 | 114 | **Example Usage**:: 115 | 116 | #include "kassert.h" 117 | 118 | void func(void) { 119 | kassert_message_void(1 == 2, "arithmetic is broken"); 120 | } 121 | 122 | int main(void) { 123 | terminal_initialize(); 124 | func(); 125 | return 0; 126 | } 127 | 128 | **Output**: 129 | 130 | .. raw:: html 131 | 132 | arithmetic is broken 133 | 134 | |br| 135 | 136 | Reason for the Naming 137 | ^^^^^^^^^^^^^^^^^^^^^^ 138 | 139 | The ``k`` prefix to the file and the functions 140 | is the naming convention 141 | for this implementation/version of libc 142 | including for non-standard functions and extensions. 143 | 144 | The reason why is that tests are run in userland and 145 | linked against glibc. So, to be able to test our libc 146 | on our host development machines, the prefix is needed. 147 | 148 | 149 | 150 | Differences with Standard in libc 151 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 152 | 153 | These assertions do NOT cause terminate to be invoked. 154 | It is often preferable to have assertions, but not terminate 155 | in the kernel. 156 | 157 | All of these assertions will log to standard output 158 | (via the vga driver) the error message and then return their 159 | error code that was passed in (or just ``return;`` 160 | in the case of the void versions). 161 | 162 | Miscellaneous Notes 163 | ^^^^^^^^^^^^^^^^^^^^ 164 | 165 | All 4 macros will print a newline character 166 | after the message even if the custom message 167 | had no newline at the end. 168 | -------------------------------------------------------------------------------- /docs/source/docs_source/libc/kerrno.rst: -------------------------------------------------------------------------------- 1 | kerrno 2 | ====== 3 | 4 | This is an implementation of from libc. 5 | 6 | It is just a few macro define constants and the 7 | ``errno`` variable. 8 | Please refer to the cppreference docs for errno 9 | for examples of use. 10 | 11 | 12 | .. 13 | errno is so simple and widely known and 14 | our implementation is so boring, 15 | that it isn't necessary to write examples 16 | or write thorough docs on what errno is. 17 | 18 | 19 | Differences from the C standard 20 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 21 | 22 | The C11 standard defines that ``errno`` must be a macro. 23 | In our implementation, 24 | we just make ``errno`` an ``extern int``. 25 | -------------------------------------------------------------------------------- /docs/source/docs_source/libc/kstring.rst: -------------------------------------------------------------------------------- 1 | kstring 2 | ======= 3 | 4 | .. |br| raw:: html 5 | 6 |
7 | 8 | This module has 18 functions that are defined as 9 | follows: 10 | 11 | ``void* kmemcpy(void *restrict destination, const void *restrict source, size_t num);`` 12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13 | 14 | This function copies 15 | memory of size num from 16 | memory location source to the 17 | destination. Source and destination 18 | memory cannot overlap. 19 | 20 | **Example Usage**:: 21 | 22 | #include "kstring.h" 23 | #include "kstdio.h" 24 | #include "stdint.h" 25 | 26 | int main(void) { 27 | terminal_initialize(); 28 | const char src[13] = "Hello world!"; 29 | char dest[13]; 30 | kmemcpy(dest, src, kstrlen(src)+1); 31 | kprintf(dest); 32 | return 0; 33 | } 34 | 35 | **Output**: 36 | 37 | Hello world! 38 | 39 | |br| 40 | 41 | ``void* kmemmove(void* destination, const void* source, size_t num);`` 42 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 43 | 44 | This function copies 45 | memory of size num from 46 | memory location source to the 47 | destination. Source and destination 48 | memory can overlap. 49 | 50 | **Example Usage**:: 51 | 52 | #include "kstring.h" 53 | #include "kstdio.h" 54 | #include "stdint.h" 55 | 56 | int main(void) { 57 | terminal_initialize(); 58 | char src[] = "Hello world!"; 59 | kmemmove(src+4, src+2, 4); 60 | kprintf(src); 61 | return 0; 62 | } 63 | 64 | **Output**: 65 | 66 | Hellllo rld! 67 | 68 | |br| 69 | 70 | ``void* kmemchr(void* ptr, int32_t value, size_t num);`` 71 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 72 | 73 | This function 74 | finds the first occurrence of 75 | value in memory of size num. 76 | 77 | **Example Usage**:: 78 | 79 | #include "kstring.h" 80 | #include "kstdio.h" 81 | #include "stdint.h" 82 | 83 | int main(void) { 84 | terminal_initialize(); 85 | unsigned char source_buffer[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x70, 0x09, 0x02, 0x03}; 86 | const unsigned char \*const result = kmemchr((unsigned char\*) source_buffer, 0x09, sizeof(source_buffer)); 87 | kprintf("%d", (result == &buffer[5])); 88 | return 0; 89 | } 90 | 91 | **Output**: 92 | 93 | 1 94 | 95 | |br| 96 | 97 | ``int32_t kmemcmp(const void* ptr1, const void* ptr2, size_t num);`` 98 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 99 | 100 | This function compares 101 | two blocks of memory 102 | of size num. 103 | 104 | **Example Usage**:: 105 | 106 | #include "kstring.h" 107 | #include "kstdio.h" 108 | #include "stdint.h" 109 | 110 | int main(void) { 111 | terminal_initialize(); 112 | const char \*const str1 = "abc"; 113 | const char \*const str2 = "cde"; 114 | const int32_t result = kmemcmp(str1, str2, kstrlen(str1)); 115 | kprintf("%d", result); 116 | return 0; 117 | } 118 | 119 | **Output**: 120 | 121 | -1 122 | 123 | |br| 124 | 125 | ``void* kmemset(void* ptr, int32_t value, size_t num);`` 126 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 127 | 128 | This function 129 | sets memory of size num to 130 | value. 131 | 132 | **Example Usage**:: 133 | 134 | #include "kstring.h" 135 | #include "kstdio.h" 136 | #include "stdint.h" 137 | 138 | int main(void) { 139 | terminal_initialize(); 140 | uint32_t buffer[] = {0xDEAD, 0xBEEF, 0x10, 0x54, 0x97, 0x83, 0x12, 0x10}; 141 | const uint32_t \*const result = kmemset(buffer, 0xFF, sizeof(buffer)); 142 | for(int32_t i = 0; i < sizeof(buffer)/sizeof(uint32_t); ++i) { 143 | kprintf("%x\n", buffer[i]); 144 | } 145 | return 0; 146 | } 147 | 148 | **Output**: 149 | 150 | ffffffff 151 | ffffffff 152 | ffffffff 153 | ffffffff 154 | ffffffff 155 | ffffffff 156 | ffffffff 157 | ffffffff 158 | 159 | |br| 160 | 161 | ``char* kstrcat(char* destination, const char* source);`` 162 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 163 | 164 | This function 165 | concatenates two strings 166 | (without bounds checking). 167 | 168 | **Example Usage**:: 169 | 170 | #include "kstring.h" 171 | #include "kstdio.h" 172 | #include "stdint.h" 173 | 174 | int main(void) { 175 | terminal_initialize(); 176 | char buffer[32] = "abc"; 177 | const char \*const result = kstrcat(buffer, "cdef"); 178 | kprintf(result); 179 | return 0; 180 | } 181 | 182 | **Output**: 183 | 184 | abccdef 185 | 186 | |br| 187 | 188 | ``char* kstrncat(char* destination, const char* source, size_t num);`` 189 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 190 | 191 | This function 192 | concatenates two strings 193 | (with bounds checking). 194 | 195 | **Example Usage**:: 196 | 197 | #include "kstring.h" 198 | #include "kstdio.h" 199 | #include "stdint.h" 200 | 201 | int main(void) { 202 | terminal_initialize(); 203 | char buffer[6] = "abc"; 204 | const char \*const result = kstrncat(buffer, "cdef", sizeof(buffer)/sizeof(char)); 205 | kprintf(result); 206 | return 0; 207 | } 208 | 209 | **Output**: 210 | 211 | abccd 212 | 213 | |br| 214 | 215 | ``char* kstrchr(char* str, int32_t character);`` 216 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 217 | 218 | This function 219 | finds the first occurrence of 220 | character in string str 221 | (searching from start of string). 222 | 223 | **Example Usage**:: 224 | 225 | #include "kstring.h" 226 | #include "kstdio.h" 227 | #include "stdint.h" 228 | 229 | int main(void) { 230 | terminal_initialize(); 231 | char source[] = "aba"; 232 | const char c = 'a'; 233 | const char \*const expected = source; 234 | const char \*const result = kstrchr(source, c); 235 | kprintf("%d", (result == expected)); 236 | return 0; 237 | } 238 | 239 | **Output**: 240 | 241 | 1 242 | 243 | |br| 244 | 245 | ``char* kstrrchr(char* str, int32_t character);`` 246 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 247 | 248 | This function 249 | finds the first occurrence of 250 | character in string str 251 | (searching from end of string). 252 | 253 | **Example Usage**:: 254 | 255 | #include "kstring.h" 256 | #include "kstdio.h" 257 | #include "stdint.h" 258 | 259 | int main(void) { 260 | terminal_initialize(); 261 | char source[] = "aba"; 262 | const char c = 'a'; 263 | const char \*const expected = source + 2; 264 | const char \*const result = kstrrchr(source, c); 265 | kprintf("%d", (result == expected)); 266 | return 0; 267 | } 268 | 269 | **Output**: 270 | 271 | 1 272 | 273 | |br| 274 | 275 | 276 | -------------------------------------------------------------------------------- /docs/source/docs_source/utils/data_structures/hashmap/hashmap.rst: -------------------------------------------------------------------------------- 1 | hashmap 2 | ======== 3 | 4 | .. |br| raw:: html 5 | 6 |
7 | 8 | This module has 5 functions 9 | and 2 macro functions 10 | that are defined as follows: 11 | 12 | ``GENERATE_HASHMAP_DECLARATION(TYPE_OF_KEY, TYPE_OF_DATA)`` 13 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 14 | 15 | This macro function acts as a 16 | monomorphized generic and generates prototypes 17 | of all of the functions of this module such 18 | that they work with the type passed as `TYPE_OF_DATA`. 19 | 20 | |br| 21 | 22 | ``GENERATE_HASHMAP_DEFINITION(TYPE_OF_KEY, TYPE_OF_DATA)`` 23 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 24 | This macro function acts as a 25 | monomorphized generic and generates definitions/bodies 26 | of all of the functions of this module such 27 | that they work with the type passed as `TYPE_OF_DATA`. 28 | It is the source file counterpart to 29 | ``GENERATE_HASHMAP_DECLARATION()`. 30 | 31 | |br| 32 | 33 | ``void hashmap_init(struct hashmap* hashmap, uint32_t (*hash_function)(TYPE_OF_KEY));`` 34 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 35 | 36 | This function is generated by 37 | the two aforementioned macro functions. 38 | It initializes an existing `hashmap` instance 39 | passed by pointer by the user. `hash_function` 40 | must be a function capable of hashing instances 41 | of `TYPE_OF_KEY` into `uint32_t`'s. This is how 42 | the keys are determined for data values. 43 | This function does not heap allocate using `kmalloc`. 44 | 45 | Note: `hashmap_init` and `hashmap` are both name 46 | mangled in a non API stable way (the mangling may 47 | change at any time). If you need their true mangled 48 | names, use the name getter macro functions. 49 | 50 | |br| 51 | 52 | ``TYPE_OF_DATA* find(struct hashmap* hashmap, TYPE_OF_KEY key);`` 53 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 54 | 55 | |br| 56 | 57 | ``TYPE_OF_DATA remove(struct hashmap* hashmap, TYPE_OF_KEY key);`` 58 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 59 | 60 | |br| 61 | 62 | ``void add(struct hashmap* hashmap, TYPE_OF_KEY key, TYPE_OF_DATA data);`` 63 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 64 | 65 | |br| 66 | 67 | ``void hashmap_destroy(struct hashmap* hashmap);`` 68 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 69 | 70 | This function is generated by 71 | the two aforementioned macro functions. 72 | It zeroes out the `hashmap` instance 73 | passed by pointer by the user 74 | and frees all resources allocated by it. 75 | 76 | Note: `hashmap_destroy` and `hashmap` are both name 77 | mangled in a non API stable way (the mangling may 78 | change at any time). If you need their true mangled 79 | names, use the name getter macro functions. 80 | 81 | |br| 82 | 83 | .. 84 | TODO: Insert the macros to get the mangled names later 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to RocketOS's Documentation! 2 | ========================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Pages: 7 | 8 | docs_source/drivers/ata/ata_driver.rst 9 | 10 | docs_source/libc/kassert 11 | docs_source/libc/kerrno 12 | docs_source/libc/kstring 13 | -------------------------------------------------------------------------------- /generate_grubcfg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | touch $1 4 | echo "set timeout=0" > $1 5 | echo "set default=0" >> $1 6 | echo "menuentry \"$2\"" { >> $1 7 | echo " multiboot $3" >> $1 8 | echo " boot" >> $1 9 | echo "}" >> $1 10 | -------------------------------------------------------------------------------- /get_pwd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "$(dirname $(realpath $0))" 4 | 5 | -------------------------------------------------------------------------------- /grub.cfg: -------------------------------------------------------------------------------- 1 | set timeout=1 2 | set default=0 3 | 4 | menuentry "os" { 5 | multiboot2 /boot/rocketos.kernel --console 6 | gfxpayload=text 7 | module2 /boot/ramdisk.img 8 | boot 9 | } 10 | -------------------------------------------------------------------------------- /is_multiboot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if grub-file --is-x86-multiboot2 $1; then 4 | echo multiboot confirmed 5 | else 6 | echo the file is not multiboot 7 | fi 8 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local 2 | EXEC_PREFIX ?= $(PREFIX) 3 | BOOTDIR ?= $(EXEC_PREFIX)/boot 4 | INCLUDEDIR ?= $(PREFIX)/include 5 | 6 | CFLAGS := $(CFLAGS) -ffreestanding -Wall -Wextra 7 | CPPFLAGS := $(CPPFLAGS) -D__is_kernel -I../sysroot/usr/include/userspace -I../sysroot/usr/include/kernel/kernel -I../sysroot/usr/include/kernel/arch/i686 -I../kernel/arch/i686/ -I../kernel/kernel/ 8 | 9 | include ../make.config 10 | 11 | KERNEL_FLAGS ?= -std=gnu17 -ffreestanding -DRocketOS -mgeneral-regs-only 12 | 13 | ifdef RELEASE 14 | IMAGE_FLAGS := -ffreestanding $(RELEASE_LINK_FLAGS) -nostdlib -lgcc 15 | else 16 | IMAGE_FLAGS := -ffreestanding $(DEBUG_LINK_FLAGS) -nostdlib -lgcc 17 | endif 18 | 19 | 20 | ARCHDIR = arch/$(HOST) 21 | 22 | include $(ARCHDIR)/make.config 23 | 24 | 25 | #arch 26 | ARCH_AS_NAMES := $(shell find arch/ -name '*.s') 27 | ARCH_C_NAMES := $(shell find arch/ -name '*.c' | grep -v arch/i686/acpica/) 28 | ARCH_H_NAMES := $(shell find arch/ -name '*.h' | grep -v arch/i686/acpica/) 29 | 30 | #kernel 31 | KERNEL_AS_NAMES := $(shell find kernel/ -name '*.s') 32 | KERNEL_C_NAMES := $(shell find kernel/ -name '*.c') 33 | KERNEL_H_NAMES := $(shell find kernel/ -name '*.h') 34 | 35 | #libk 36 | LIBK_C_NAMES := $(shell find libk/ -name '*.c') 37 | LIBK_H_NAMES := $(shell find libk/ -name '*.h') 38 | 39 | #sysroot 40 | INCLUDE_HEADERS := $(shell find include/ -name '*.h') 41 | 42 | #list of all kernel headers with include prefix 43 | INCLUDE_LIST := $(addprefix -I,$(dir $(INCLUDE_HEADERS) $(LIBK_H_NAMES) $(ARCH_H_NAMES) $(KERNEL_H_NAMES))) 44 | 45 | 46 | OBJ_LIST := $(patsubst %.s,%.o,$(ARCH_AS_NAMES)) $(patsubst %.s,%.o,$(KERNEL_AS_NAMES)) $(patsubst %.c,%.o,$(ARCH_C_NAMES)) $(patsubst %.c,%.o,$(KERNEL_C_NAMES)) $(patsubst %.c,%.o,$(LIBK_C_NAMES)) 47 | 48 | 49 | .PHONY: all clean build_acpica install install-headers install-kernel 50 | .SUFFIXES: .o .c .s 51 | 52 | all: rocketos.kernel 53 | 54 | rocketos.kernel: $(OBJ_LIST) $(ARCHDIR)/linker.ld build_acpica 55 | $(CC) -T $(ARCHDIR)/linker.ld -o $@ $(IMAGE_FLAGS) $(OBJ_LIST) arch/i686/acpica/acpica.a -lgcc 56 | ../is_multiboot.sh rocketos.kernel 57 | 58 | build_acpica: 59 | @cd arch/i686/acpica; $(MAKE) 60 | 61 | .c.o: 62 | $(CC) -MD -c $< -o $@ $(KERNEL_FLAGS) $(WARNING_FLAGS) $(FLAGS) $(CPPFLAGS) $(INCLUDE_LIST) -Iarch/i686/acpica/ 63 | 64 | .S.o: 65 | $(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS) 66 | 67 | clean: 68 | -rm rocketos.kernel 69 | -rm $(shell find -name '*.o') 70 | -rm $(shell find -name '*.d') 71 | -rm -r $(DESTDIR)$(INCLUDEDIR)/kernel/ 72 | @cd arch/i686/acpica; $(MAKE) clean 73 | 74 | install: install-headers install-kernel 75 | 76 | install-headers: 77 | mkdir -p $(DESTDIR)$(INCLUDEDIR)/kernel 78 | cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/kernel/. 79 | 80 | install-kernel: rocketos.kernel 81 | mkdir -p $(DESTDIR)$(BOOTDIR) 82 | cp rocketos.kernel $(DESTDIR)$(BOOTDIR) 83 | 84 | -include $(OBJS:.o=.d) 85 | -------------------------------------------------------------------------------- /kernel/arch/i686/acpica/Makefile: -------------------------------------------------------------------------------- 1 | # acpica 2 | ACPICA_C_NAMES := $(shell find -name '*.c') 3 | ACPICA_H_NAMES := $(shell find -name '*.h') 4 | ACPICA_O_NAMES := $(patsubst %.c,%.o,$(ACPICA_C_NAMES)) 5 | 6 | 7 | # add -I 8 | ACPICA_H_FILES_INCLUDE := $(addprefix -I,$(dir $(ACPICA_H_NAMES))) 9 | 10 | 11 | CC := i686-elf-gcc 12 | 13 | .PHONY: all build 14 | .SUFFIXES: .o .c 15 | 16 | all: acpica.a 17 | 18 | acpica.a: $(ACPICA_O_NAMES) 19 | i686-elf-ar rcs $@ $(ACPICA_O_NAMES) -lgcc 20 | 21 | .c.o: 22 | $(CC) -MD -c $< -o $@ $(ACPICA_H_FILES_INCLUDE) -std=gnu17 -ffreestanding -DRocketOS -nostdlib 23 | 24 | clean: 25 | -rm $(shell find -name '*.o') 26 | -rm $(shell find -name '*.d') 27 | -rm acpica.a 28 | -------------------------------------------------------------------------------- /kernel/arch/i686/acpica/platform/acrocketos.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ACPI_MACHINE_WIDTH 32 4 | 5 | 6 | 7 | #ifndef ACPI_DIV_64_BY_32 8 | #define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ 9 | do { \ 10 | UINT64 (__n) = ((UINT64) n_hi) << 32 | (n_lo); \ 11 | (r32) = ((__n) / (d32)); \ 12 | (q32) = (UINT32) (__n); \ 13 | } while (0) 14 | #endif 15 | 16 | #ifndef ACPI_SHIFT_RIGHT_64 17 | #define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ 18 | do { \ 19 | (n_lo) >>= 1; \ 20 | (n_lo) |= (((n_hi) & 1) << 31); \ 21 | (n_hi) >>= 1; \ 22 | } while (0) 23 | #endif 24 | 25 | #define COMPILER_DEPENDENT_UINT64 unsigned long long 26 | 27 | 28 | //tell ACPICA to use its internal cache 29 | #define ACPI_CACHE_T ACPI_MEMORY_LIST 30 | #define ACPI_USE_LOCAL_CACHE 1 31 | 32 | //TODO: support multithreading for ACPICA in the future 33 | #define ACPI_SINGLE_THREADED 34 | -------------------------------------------------------------------------------- /kernel/arch/i686/boot/boot_PT.s: -------------------------------------------------------------------------------- 1 | %define PAGE_SIZE 4096 2 | %define PAGE_PRESENT 0x001 3 | %define PAGE_WRITE 0x002 4 | %define PAGE_GLOBAL 0x100 5 | %define ENTRIES_PER_PT 1024 6 | %define ENTRIES_PER_PD 1024 7 | %define KERNEL_OFFSET 0xC0000000 8 | %define V2P(a) ((a) - KERNEL_OFFSET) 9 | 10 | 11 | section .data 12 | global boot_page_table 13 | align PAGE_SIZE 14 | boot_page_table: 15 | %assign addr 0 16 | %rep ENTRIES_PER_PT 17 | dd addr | PAGE_PRESENT 18 | %assign addr (addr + PAGE_SIZE) 19 | %endrep 20 | align PAGE_SIZE 21 | global boot_page_directory 22 | boot_page_directory: 23 | %rep ENTRIES_PER_PD 24 | dd (boot_page_table - KERNEL_OFFSET) + PAGE_PRESENT 25 | %endrep 26 | 27 | -------------------------------------------------------------------------------- /kernel/arch/i686/boot/kernel.c: -------------------------------------------------------------------------------- 1 | 2 | #include "multiboot.h" 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "acpi_init.h" 35 | 36 | #include 37 | 38 | #include 39 | 40 | #include 41 | 42 | 43 | extern uint32_t boot_page_directory; 44 | extern uint32_t boot_page_table; 45 | 46 | extern uint32_t upper_memory; 47 | 48 | 49 | void kernel_main(const uint32_t mboot_magic, const uint32_t mboot_header) { 50 | if(serial_init()) { //fails if serial is faulty 51 | serial_writestring("Serial driver works\n"); 52 | } 53 | 54 | for(uint32_t i = 0u; i < 1024u; ++i) { 55 | kprintf("boot_page_directory[%u]: %p\n", i, (&boot_page_directory)[i]); 56 | } 57 | 58 | for(uint32_t i = 0u; i < 1024u; ++i) { 59 | kprintf("boot_page_table[%u]: %p\n", i, (&boot_page_table)[i]); 60 | } 61 | 62 | kprintf("upper_memory: %p\n", &upper_memory); 63 | 64 | 65 | gdt_init(); 66 | gdt_load(); 67 | 68 | pic_init(); 69 | isr_install(); 70 | 71 | initialize_kernel_memory(); 72 | kdynamic_memory_init(); 73 | 74 | terminal_context_initialize(); 75 | default_keyboard_map_state_init(); 76 | set_default_functions(); 77 | 78 | serial_writestring("after interrupts installed\n"); 79 | 80 | serial_writestring("Kernel memory initialized\n"); 81 | 82 | kprintf("mboot_magic: %X\n", mboot_magic); 83 | if (mboot_magic != MULTIBOOT2_BOOTLOADER_MAGIC) { 84 | kprintf("Invalid Multiboot Magic!\n"); 85 | } else { 86 | kprintf("The multiboot structure was loaded properly\n"); 87 | } 88 | 89 | struct multiboot_tag_module* module = NULL; 90 | 91 | struct multiboot_tag* tag = (struct multiboot_tag*)(mboot_header + 8); 92 | identity_map_page_in_kernel_addr((uint32_t)mboot_header & PAGE_BITMASK, PT_PRESENT, PD_PRESENT); 93 | identity_map_page_in_kernel_addr((uint32_t)tag & PAGE_BITMASK, PT_PRESENT, PD_PRESENT); 94 | kprintf("tag address: %p\n", tag); 95 | uint32_t size = *(uint32_t*)mboot_header; 96 | for(; tag->type != MULTIBOOT_TAG_TYPE_END; tag = (struct multiboot_tag*)((multiboot_uint8_t*)tag + ((tag->size+7) & ~7))) { 97 | identity_map_page_in_kernel_addr((uint32_t)tag & PAGE_BITMASK, PT_PRESENT, PD_PRESENT); 98 | if(tag->type == MULTIBOOT_TAG_TYPE_MODULE) { 99 | module = (struct multiboot_tag_module*)tag; 100 | kprintf("Module at 0x%X-0x%X. Command line [%s]\n", 101 | module->mod_start, 102 | module->mod_end, 103 | module->cmdline); 104 | } 105 | } 106 | 107 | const uint32_t addr = module->mod_start; 108 | identity_map_page_in_kernel_addr(addr & PAGE_BITMASK, PT_PRESENT, PD_PRESENT); 109 | 110 | kprintf("first_module: %p\n", module); 111 | kprintf("addr: %p\n", addr); 112 | kprintf("module->mod_start: %X\n", module->mod_start); 113 | 114 | kprintf("Module at 0x%X-0x%X. Command line [%s]\n", 115 | module->mod_start, 116 | module->mod_end, 117 | module->cmdline); 118 | 119 | parse_headers(addr); 120 | print_file("bar.txt"); 121 | kprintf("\n"); 122 | 123 | 124 | acpi_init(); 125 | 126 | write_tss(); 127 | 128 | 129 | struct default_terminal_context *const data = get_default_terminal_context(); 130 | data->vga_context = get_default_vga_context(); 131 | struct GET_OBSERVER_TYPENAME(key_message) *const observer = zeroed_out_kmalloc(sizeof(struct GET_OBSERVER_TYPENAME(key_message))); 132 | *observer = (struct GET_OBSERVER_TYPENAME(key_message)){ data, catch_keycode }; 133 | ADD_OBSERVER(128, key_message, get_subject(), observer); 134 | default_context_terminal_start(); 135 | enable_keyboard(); 136 | 137 | 138 | kprintf("before scheduler_init()\n"); 139 | scheduler_init(); 140 | //scheduler_exec(string_new("test_program"), NULL); 141 | kputs("before test_program"); 142 | enable_interrupts(); 143 | //parse_elf_file("test_program"); 144 | scheduler_load_process_in_new_address_space("test_program"); 145 | kputs("after test_program"); 146 | scheduler_start(); 147 | 148 | for(;;) { 149 | kprintf("in the main function\n"); 150 | asm volatile("hlt"); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /kernel/arch/i686/boot/multiboot_header.s: -------------------------------------------------------------------------------- 1 | MULTIBOOT2_HEADER_MAGIC equ 0xe85250d6 2 | GRUB_MULTIBOOT_ARCHITECTURE_I386 equ 0 3 | MULTIBOOT_HEADER_TAG_FRAMEBUFFER equ 5 4 | MULTIBOOT_HEADER_TAG_OPTIONAL equ 1 5 | MULTIBOOT_HEADER_TAG_END equ 0 6 | STACK_SIZE equ 0x4000 7 | 8 | 9 | section .multiboot 10 | align 0x8 11 | multiboot_header: ; TODO: don't have the stack and other static data sections inside section .text 12 | dd MULTIBOOT2_HEADER_MAGIC 13 | dd GRUB_MULTIBOOT_ARCHITECTURE_I386 14 | dd multiboot_header_end - multiboot_header 15 | dd -(MULTIBOOT2_HEADER_MAGIC + GRUB_MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header)) 16 | 17 | framebuffer_tag_start: 18 | dw MULTIBOOT_HEADER_TAG_FRAMEBUFFER 19 | dw MULTIBOOT_HEADER_TAG_OPTIONAL 20 | dd framebuffer_tag_end - framebuffer_tag_start 21 | dd 1024 22 | dd 768 23 | dd 32 24 | framebuffer_tag_end: 25 | dw MULTIBOOT_HEADER_TAG_END 26 | dw 0 27 | dd 0 28 | multiboot_header_end: 29 | -------------------------------------------------------------------------------- /kernel/arch/i686/boot/upperhalf_boot.s: -------------------------------------------------------------------------------- 1 | %define KERNEL_OFFSET 0xC0000000 2 | %define PAGE_SIZE 0x1000 3 | 4 | %define V2P(a) ((a) - KERNEL_OFFSET) 5 | %define P2V(a) ((a) + KERNEL_OFFSET) 6 | 7 | section .bss 8 | global BootStack 9 | align PAGE_SIZE 10 | resb PAGE_SIZE 11 | BootStack: 12 | 13 | section .text 14 | global _start 15 | _start: 16 | cli 17 | 18 | mov edi, eax 19 | mov esi, ebx 20 | 21 | ; Set up a known stack 22 | mov esp, (V2P(BootStack)) 23 | 24 | extern boot_page_directory 25 | mov eax, (V2P(boot_page_directory)) 26 | mov cr3, eax 27 | 28 | ; Set CR0.PG 29 | ; enabling Paging 30 | mov eax, cr0 31 | or eax, 1<<31 32 | mov cr0, eax 33 | 34 | ; Jump to kernel address space 35 | lea eax, [upper_memory] 36 | jmp eax 37 | 38 | global upper_memory 39 | upper_memory: 40 | ; Move stack pointer to kernel space 41 | mov eax, KERNEL_OFFSET 42 | add esp, eax 43 | 44 | ; Remove identity mapping 45 | xor eax, eax 46 | mov [boot_page_directory], eax 47 | 48 | ; Update page tables 49 | mov eax, cr3 50 | mov cr3, eax 51 | 52 | ; Jump to kernel_main() 53 | extern kernel_main 54 | mov eax, (kernel_main) 55 | push esi 56 | push edi 57 | call eax 58 | 59 | hlt 60 | jmp $ 61 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/hdd/ahci/ahci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include "kstdlib.h" 9 | #include 10 | #include "kstring.h" 11 | 12 | #include 13 | 14 | 15 | struct hba_port { 16 | uint32_t command_list_base; 17 | uint32_t command_list_base_upper; 18 | uint32_t fis_base_addr; 19 | uint32_t fis_base_addr_upper; 20 | uint32_t interrupt_status; 21 | uint32_t interrupt_enable; 22 | uint32_t command_and_status; 23 | uint32_t reserved_0; 24 | uint32_t task_file_data; 25 | uint32_t signature; 26 | uint32_t sata_status; 27 | uint32_t sata_control; 28 | uint32_t sata_error; 29 | uint32_t sata_active; 30 | uint32_t command_issue; 31 | uint32_t sata_notification; 32 | uint32_t fis_switch_control; 33 | uint32_t reserved_1[11]; 34 | uint32_t vendor_data[4]; 35 | }; 36 | 37 | struct hba_memory { 38 | uint32_t host_capabilities; 39 | uint32_t global_host_control; 40 | uint32_t interrupt_status; 41 | uint32_t ports_implemented; 42 | uint32_t version; 43 | uint32_t ccc_control; 44 | uint32_t ccc_ports; 45 | uint32_t enclosure_management_location; 46 | uint32_t enclosure_management_control; 47 | uint32_t host_capabilities_extended; 48 | uint32_t bios_handoff_control_and_status; 49 | uint8_t reserved[0x74]; 50 | uint8_t vendor_specific[0x60]; 51 | struct hba_port ports[]; 52 | }; 53 | 54 | //TODO: stop using bitset members and instead manually set the bits as C bitsets are pretty bad 55 | struct hba_command_header { 56 | uint8_t command_fis_length : 5; 57 | uint8_t atapi : 1; 58 | uint8_t write : 1; 59 | uint8_t prefetchable : 1; 60 | 61 | uint8_t reset : 1; 62 | uint8_t bist : 1; 63 | uint8_t clear_busy : 1; 64 | uint8_t reserved_0 : 1; 65 | uint8_t port_multiplier : 4; 66 | 67 | uint16_t prdt_length; 68 | uint32_t prdb_count; 69 | uint32_t command_table_base_addr; 70 | uint32_t command_table_base_addr_upper; 71 | uint32_t reserved_1[4]; 72 | }; 73 | 74 | struct fis_register_h2d { 75 | uint8_t fis_type; 76 | 77 | uint8_t port_multiplier : 4; 78 | uint8_t reserved_0 : 3; 79 | uint8_t command_control : 1; 80 | 81 | uint8_t command; 82 | uint8_t feature_low; 83 | 84 | uint8_t lba0; 85 | uint8_t lba1; 86 | uint8_t lba2; 87 | uint8_t device_register; 88 | 89 | uint8_t lba3; 90 | uint8_t lba4; 91 | uint8_t lba5; 92 | uint8_t feature_high; 93 | 94 | uint8_t count_low; 95 | uint8_t count_high; 96 | uint8_t iso_command_completion; 97 | uint8_t control; 98 | 99 | uint8_t reserved_1[4]; 100 | }; 101 | 102 | struct hba_prdt_entry { 103 | uint32_t data_base_addr; 104 | uint32_t data_base_addr_upper; 105 | uint32_t reserved_0; 106 | 107 | uint32_t byte_count : 22; 108 | uint32_t reserved_1 : 9; 109 | uint32_t interrupt_on_completion : 1; 110 | }; 111 | 112 | struct hba_command_table { 113 | uint8_t command_fis[64]; 114 | 115 | uint8_t atapi_command[16]; 116 | 117 | uint8_t reserved[48]; 118 | 119 | struct hba_prdt_entry prdt_entries[]; 120 | }; 121 | 122 | 123 | enum hba_port_type { 124 | HBA_PORT_TYPE_NONE = 0, 125 | HBA_PORT_TYPE_SATA = 1, 126 | HBA_PORT_TYPE_SEMB = 2, 127 | HBA_PORT_TYPE_PM = 3, 128 | HBA_PORT_TYPE_SATAPI = 4, 129 | }; 130 | 131 | enum fis_type { 132 | FIS_TYPE_REG_H2D = 0x27, 133 | FIS_TYPE_REG_D2H = 0x34, 134 | FIS_TYPE_DMA_ACTIVATE = 0x39, 135 | FIS_TYPE_DMA_SETUP = 0x41, 136 | FIS_TYPE_DATA = 0x46, 137 | FIS_TYPE_BIST = 0x58, 138 | FIS_TYPE_PIO_SETUP = 0x5F, 139 | FIS_TYPE_DEV_BITS = 0xA1, 140 | }; 141 | 142 | #define HBA_PORT_PRESENT 0x03 143 | #define HBA_PORT_IPM_ACTIVE 0x01 144 | #define SATA_ATAPI_SIGNATURE 0xEB140101 145 | #define SATA_ATA_SIGNATURE 0x00000101 146 | #define SATA_SEMB_SIGNATURE 0xC33C0101 147 | #define SATA_PM_SIGNATURE 0x96690101 148 | 149 | #define HBA_PxCMD_CR 0x8000 150 | #define HBA_PxCMD_FRE 0x0010 151 | #define HBA_PxCMD_ST 0x0001 152 | #define HBA_PxCMD_FR 0x4000 153 | 154 | #define ATA_CMD_READ_DMA_EX 0x25 155 | 156 | #define ATA_DEV_BUSY 0x80 157 | #define ATA_DEV_DRQ 0x08 158 | 159 | #define HBA_PxIS_TFES (1u << 30u) 160 | 161 | struct ahci_port { 162 | struct hba_port* port; 163 | enum hba_port_type type; 164 | uint8_t* buffer; 165 | uint8_t port_number; 166 | }; 167 | 168 | 169 | void init_ahci(struct pci_device_header* pci_device); 170 | void probe_ports(void); 171 | void start_cmd(struct ahci_port* port); 172 | void stop_cmd(struct ahci_port* port); 173 | void configure_port(struct ahci_port* port); 174 | bool read_sector(struct ahci_port* port, uint32_t sector, uint16_t sector_count, void* buffer); 175 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/keyboard/default_keyboard_logic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | //for keys which are just 0 in the default keymap 11 | enum type_of_key { 12 | CONTROL = 0u, 13 | LEFT_SHIFT = 1u, 14 | RIGHT_SHIFT = 2u, 15 | ALT = 3u, 16 | CAPS_LOCK = 4u, 17 | F1 = 5u, 18 | F2 = 6u, 19 | F3 = 7u, 20 | F4 = 8u, 21 | F5 = 9u, 22 | F6 = 10u, 23 | F7 = 11u, 24 | F8 = 12u, 25 | F9 = 13u, 26 | F10 = 14u, 27 | NUMS_LOCK = 15u, 28 | SCROLL_LOCK = 16u, 29 | HOME_KEY = 17u, 30 | UP_ARROW = 18u, 31 | PAGE_UP = 19u, 32 | LEFT_ARROW = 20u, 33 | RIGHT_ARROW = 21u, 34 | END_KEY = 22u, 35 | DOWN_ARROW = 23u, 36 | PAGE_DOWN = 24u, 37 | INSERT_KEY = 25u, 38 | DELETE_KEY = 26u, 39 | F11 = 27u, 40 | F12 = 28u, 41 | 42 | NORMAL_KEY = 29u, //is a number, letter, or displayable symbol 43 | 44 | INVALID_KEY = 30u, 45 | }; 46 | 47 | struct key_message { 48 | char keycode; 49 | size_t key_type; //by default uses the constants defined in `enum type_of_key` 50 | }; 51 | 52 | 53 | GENERATE_SUBJECT_DECLARATION(128, key_message) 54 | 55 | 56 | struct default_keyboard_map_state { 57 | bool rshift; 58 | bool lshift; 59 | bool caps_lock; 60 | const char* keyboard_map; //must be 128 entries 61 | struct GET_SUBJECT_TYPENAME(128, key_message) subject; 62 | }; 63 | 64 | struct GET_SUBJECT_TYPENAME(128, key_message)* get_subject(void); 65 | 66 | 67 | void process_keystroke(void* context, unsigned char keycode); 68 | void default_keyboard_map_state_init(void); 69 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/keyboard/keyboard_driver.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //data context (containing keyboard map) 5 | static void* data_context; 6 | 7 | //params: `data_context`, scancode 8 | static void(*current_process_keystroke_implementation)(void*, unsigned char); 9 | 10 | 11 | void set_data_context(void *const new_context) { 12 | data_context = new_context; 13 | } 14 | 15 | void set_process_keystroke_implementation(void(*const new_implementation)(void*, unsigned char)) { 16 | current_process_keystroke_implementation = new_implementation; 17 | } 18 | 19 | 20 | __attribute__((interrupt)) static void keyboard_irq(struct interrupt_frame *const frame) { 21 | (void) frame; //silence unused parameter warning as this param is needed for hardware reasons 22 | 23 | const unsigned char scancode = inb(0x60); 24 | 25 | current_process_keystroke_implementation(data_context, scancode); 26 | 27 | pic_send_eoi(1); 28 | } 29 | 30 | 31 | void enable_keyboard(void) { 32 | pic_irq_enable(1); 33 | idt_register_handler(33, (uint32_t)keyboard_irq); 34 | } 35 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/keyboard/keyboard_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | void set_data_context(void* new_context); 15 | void set_process_keystroke_implementation(void(*new_implementation)(void*, unsigned char)); 16 | void enable_keyboard(void); 17 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/pci/legacy_pci/pci_bus.c: -------------------------------------------------------------------------------- 1 | #include "pci_bus.h" 2 | 3 | 4 | #define CONFIG_ADDRESS 0xCF8 5 | #define CONFIG_DATA 0xCFC 6 | 7 | uint32_t pci_config_read_long(const uint8_t bus, const uint8_t device, const uint8_t function, const uint8_t offset) { 8 | const uint32_t address = 9 | (uint32_t)(1 << 31) //enabled 10 | | ((uint32_t)bus << 16) //bus number 11 | | ((uint32_t)device << 11) //device number 12 | | ((uint32_t)function << 8) //function number 13 | | (((uint32_t)offset) & 0xFC); //Register number 14 | 15 | outl(CONFIG_ADDRESS, address); 16 | 17 | return inl(CONFIG_DATA); 18 | } 19 | uint16_t pci_config_read_word(const uint8_t bus, const uint8_t device, const uint8_t function, const uint8_t offset) { 20 | return (pci_config_read_long(bus, device, function, offset) >> ((offset & 3) * 8)) & 0xffff; 21 | } 22 | uint8_t pci_config_read_byte(const uint8_t bus, const uint8_t device, const uint8_t function, const uint8_t offset) { 23 | return (pci_config_read_long(bus, device, function, offset) >> ((offset & 3) * 8)) & 0xff; 24 | } 25 | 26 | void pci_config_write_long(const uint8_t bus, const uint8_t device, const uint8_t function, const uint8_t offset, const uint32_t value) { 27 | const uint32_t address = 28 | (uint32_t)(1 << 31) //enabled 29 | | ((uint32_t)bus << 16) //bus number 30 | | ((uint32_t)device << 11) //device number 31 | | ((uint32_t)function << 8) //function number 32 | | (((uint32_t)offset) & 0xFC); //Register number 33 | 34 | outl(CONFIG_ADDRESS, address); 35 | 36 | outl(CONFIG_DATA, value); 37 | } 38 | void pci_config_write_word(const uint8_t bus, const uint8_t device, const uint8_t function, const uint8_t offset, const uint16_t value) { 39 | uint32_t tmp = pci_config_read_long(bus, device, function, offset); 40 | 41 | tmp &= ~(0xffff << ((offset & 3) * 8)); 42 | tmp |= (value << ((offset & 3) * 8)); 43 | 44 | pci_config_write_long(bus, device, function, offset, tmp); 45 | } 46 | void pci_config_write_byte(const uint8_t bus, const uint8_t device, const uint8_t function, const uint8_t offset, const uint8_t value) { 47 | uint32_t tmp = pci_config_read_long(bus, device, function, offset); 48 | 49 | tmp &= ~(0xff << ((offset & 3) * 8)); 50 | tmp |= (value << ((offset & 3) * 8)); 51 | 52 | pci_config_write_long(bus, device, function, offset, tmp); 53 | } 54 | 55 | uint16_t get_vendor_id(uint8_t bus, uint8_t device, uint8_t function) { 56 | // read "device id | vendor id" 57 | uint32_t large = pci_config_read_long(bus, device, function, 0); 58 | // extract vendor id 59 | return large; 60 | } 61 | uint8_t get_header_type(uint8_t bus, uint8_t device, uint8_t function) { 62 | // read "BIST | header type | latency timer | cache line size" 63 | uint32_t large = pci_config_read_long(bus, device, function, 12); 64 | // extract header type only 65 | return large >> 16 & 0xFF; 66 | } 67 | uint16_t get_device_id(uint8_t bus, uint8_t device, uint8_t function) { 68 | // read "device id | vendor id" 69 | uint32_t large = pci_config_read_long(bus, device, function, 0); 70 | // extract device id 71 | return large >> 16; 72 | } 73 | uint8_t get_class_code(uint8_t bus, uint8_t device, uint8_t function) { 74 | // read "class code | subclass | prog if | revision id" 75 | uint32_t large = pci_config_read_long(bus, device, function, 8); 76 | // extract class code only 77 | return large >> 24 & 0xFF; 78 | } 79 | uint8_t get_subclass(uint8_t bus, uint8_t device, uint8_t function) { 80 | // read "class code | subclass | prog if | revision id" 81 | uint32_t large = pci_config_read_long(bus, device, function, 8); 82 | // extract subclass only 83 | return large >> 16 & 0xFF; 84 | } 85 | 86 | static uint8_t num_of_devices = 0u; 87 | 88 | void check_function(uint8_t bus, uint8_t device, uint8_t function) { 89 | uint16_t vendor_id = get_vendor_id(bus, device, function); 90 | if(vendor_id == 0xFFFF) { 91 | return; 92 | } 93 | 94 | uint16_t device_id = get_device_id(bus, device, function); 95 | uint8_t class_code = get_class_code(bus, device, function); 96 | uint8_t sub_class = get_subclass(bus, device, function); 97 | 98 | //kprintf("vendor_id: %X, device_id: %X, class_code: %X, subclass: %X\n", (uint32_t)vendor_id, (uint32_t)device_id, (uint32_t)class_code, (uint32_t)sub_class); 99 | ++num_of_devices; 100 | } 101 | void check_device(uint8_t bus, uint8_t device) { 102 | check_function(bus, device, 0); 103 | 104 | uint8_t header_type = get_header_type(bus, device, 0); 105 | if((header_type & 0x80) != 0) { 106 | for(uint8_t function = 1; function < 8; ++function){ 107 | check_function(bus, device, function); 108 | } 109 | } 110 | } 111 | void brute_force_check_all_buses(void) { 112 | for(uint16_t bus = 0; bus < 256; ++bus) { 113 | for(uint8_t device = 0; device < 32; ++device) { 114 | check_device(bus, device); 115 | } 116 | } 117 | //kprintf("legacy PCI num_of_devices: %u\n", (uint32_t)num_of_devices); 118 | } 119 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/pci/legacy_pci/pci_bus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | uint32_t pci_config_read_long(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset); 11 | uint16_t pci_config_read_word(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset); 12 | uint8_t pci_config_read_byte(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset); 13 | 14 | void pci_config_write_long(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value); 15 | void pci_config_write_word(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint16_t value); 16 | void pci_config_write_byte(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint8_t value); 17 | 18 | void brute_force_check_all_buses(void); 19 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/pci/pcie/pcie_bus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "acpi.h" 8 | #include 9 | #include "kstring.h" 10 | 11 | #include "kstdio.h" 12 | 13 | struct pci_device_header { 14 | uint16_t vendor_id; 15 | uint16_t device_id; 16 | uint16_t command; 17 | uint16_t status; 18 | uint8_t revision_id; 19 | uint8_t prog_if; 20 | uint8_t subclass; 21 | uint8_t class_code; 22 | uint8_t cache_line_size; 23 | uint8_t latency_timer; 24 | uint8_t header_type; 25 | uint8_t bist; 26 | }; 27 | 28 | struct pci_header0 { 29 | struct pci_device_header header; 30 | uint32_t bar[6]; 31 | uint32_t cardbus_cis_ptr; 32 | uint16_t subsystem_vendor_id; 33 | uint16_t subsystem_id; 34 | uint32_t expansion_rom_base_addr; 35 | uint8_t capabilities_ptr; 36 | uint8_t reserved_0; 37 | uint16_t reserved_1; 38 | uint32_t reserved_2; 39 | uint8_t interrupt_line; 40 | uint8_t interrupt_pin; 41 | uint8_t min_grant; 42 | uint8_t max_latency; 43 | }; 44 | 45 | void print_all_tables(ACPI_TABLE_RSDP* rsdp); 46 | void* find_table(ACPI_TABLE_RSDP* rsdp, const char* signature); 47 | ACPI_TABLE_MCFG* find_mcfg(ACPI_TABLE_RSDP* rsdp); 48 | ACPI_TABLE_MADT* find_madt(ACPI_TABLE_RSDP* rsdp); 49 | void enumerate_pcie(const ACPI_TABLE_MCFG* mcfg); 50 | void detect_cores(ACPI_TABLE_MADT* madt); 51 | void print_cores_info(void); 52 | 53 | 54 | void init_ahci(struct pci_device_header* pci_device); //duplicate prototype here to avoid circular dependency/include 55 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/pit/pit.c: -------------------------------------------------------------------------------- 1 | #include "pit.h" 2 | 3 | 4 | #define PID_HZ 3579545 5 | 6 | #define LOWEST_HZ 18 7 | #define HIGHEST_HZ 1193180 //1193181 //TODO: might make 1193181 8 | 9 | #define HIGHEST_DIVISOR 65535 //65536 //TODO: might make 0 or conditionally 65536 10 | #define LOWEST_DIVISOR 1 11 | 12 | static uint8_t current_command_bitset = 0; 13 | static uint32_t current_frequency = 0; 14 | static uint32_t current_reload_value = 0; 15 | 16 | void init_pit(const uint32_t requested_frequency, const enum PIT_CHANNEL channel, const enum ACCESS_MODE access_mode, const enum PIT_MODE mode) { 17 | const uint8_t command_bitset = (uint8_t)((channel << 6) | (access_mode << 4) | (mode << 1)); 18 | current_command_bitset = command_bitset; 19 | outb(PIT_COMMAND_REG, command_bitset); 20 | 21 | //if(channel == PIT_CHANNEL_0) { 22 | uint32_t reload_value = 0; 23 | 24 | if(requested_frequency <= LOWEST_HZ) { 25 | reload_value = HIGHEST_DIVISOR; 26 | } else if(requested_frequency >= HIGHEST_HZ) { 27 | reload_value = LOWEST_DIVISOR; 28 | } else { 29 | reload_value = (HIGHEST_HZ / requested_frequency); 30 | } 31 | 32 | current_frequency = HIGHEST_HZ/reload_value; 33 | current_reload_value = reload_value; 34 | kprintf("requested frequency: %u, current_frequency: %u\n", requested_frequency, current_frequency); 35 | kprintf("reload_value: %u\n", reload_value); 36 | 37 | if(access_mode == ACCESS_MODE_LOBYTE_ONLY) { 38 | outb(PIT_CHANNEL_0_REG, reload_value & 0xFF); 39 | } else if(access_mode == ACCESS_MODE_HIBYTE_ONLY) { 40 | outb(PIT_CHANNEL_0_REG, (reload_value >> 8) & 0xFF); 41 | } else if(access_mode == ACCESS_MODE_LOBYTE_HIBYTE) { 42 | outb(PIT_CHANNEL_0_REG, reload_value & 0xFF); 43 | outb(PIT_CHANNEL_0_REG, (reload_value >> 8) & 0xFF); 44 | } 45 | //} 46 | } 47 | 48 | void play_sound(const uint32_t requested_frequency) { 49 | init_pit(requested_frequency, PIT_CHANNEL_2, ACCESS_MODE_LOBYTE_HIBYTE, PIT_MODE_SQUARE_WAVE_GENERATOR); 50 | 51 | const uint8_t tmp = inb(0x61); //TODO: figure out what `tmp` is 52 | if(tmp != (tmp | 3)) { //TODO: figure out what this bitwise AND with 3 is about/for 53 | outb(0x61, tmp | 3); 54 | } 55 | } 56 | 57 | void no_sound(void) { 58 | const uint8_t tmp = inb(0x61) & 0xFC; //TODO: figure out what `tmp` is 59 | outb(0x61, tmp); 60 | } 61 | 62 | void on_sound(void) { 63 | play_sound(current_frequency); 64 | } 65 | 66 | void restore_timer(void) { 67 | outb(PIT_COMMAND_REG, current_command_bitset); 68 | 69 | const uint8_t current_access_mode = current_command_bitset & 0x30; 70 | if(current_access_mode == ACCESS_MODE_LOBYTE_ONLY) { 71 | outb(PIT_CHANNEL_0_REG, current_reload_value & 0xFF); 72 | } else if(current_access_mode == ACCESS_MODE_HIBYTE_ONLY) { 73 | outb(PIT_CHANNEL_0_REG, (current_reload_value >> 8) & 0xFF); 74 | } else if(current_access_mode == ACCESS_MODE_LOBYTE_HIBYTE) { 75 | outb(PIT_CHANNEL_0_REG, current_reload_value & 0xFF); 76 | outb(PIT_CHANNEL_0_REG, (current_reload_value >> 8) & 0xFF); 77 | } 78 | } 79 | 80 | static uint64_t seconds = 0u; 81 | static uint64_t microseconds = 0u; 82 | 83 | #define US_IN_SEC 1000000 84 | 85 | void reset_timer(void) { 86 | reset_seconds(); 87 | reset_us(); 88 | } 89 | void reset_seconds(void) { 90 | seconds = 0u; 91 | } 92 | void reset_us(void) { 93 | microseconds = 0u; 94 | } 95 | void increment_timer(void) { 96 | if(++microseconds == US_IN_SEC) { 97 | microseconds = 0u; 98 | ++seconds; 99 | } 100 | } 101 | uint64_t get_seconds(void) { 102 | return seconds; 103 | } 104 | uint64_t get_us(void) { 105 | return microseconds; 106 | } 107 | 108 | 109 | static uint32_t current_ticks = 0u; 110 | 111 | void reset_ticks(void) { 112 | current_ticks = 0u; 113 | } 114 | void increment_ticks(void) { 115 | ++current_ticks; 116 | } 117 | 118 | void pit_wait_ticks(const uint32_t ticks) { 119 | reset_ticks(); 120 | while(current_ticks < ticks); 121 | } 122 | 123 | #define US_IN_SECS 1000000 124 | 125 | void pit_wait_us(const uint32_t desired_us) { 126 | kassert_void(current_frequency != 0 && current_reload_value != 0); 127 | pit_wait_ticks(((current_frequency*desired_us)/US_IN_SECS) + (((current_frequency*desired_us)%US_IN_SECS)>0)); 128 | } 129 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/pit/pit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include "kstdio.h" 8 | 9 | 10 | #define PIT_CHANNEL_0_REG 0x40 11 | #define PIT_CHANNEL_1_REG 0x41 12 | #define PIT_CHANNEL_2_REG 0x42 13 | #define PIT_COMMAND_REG 0x43 14 | 15 | enum PIT_CHANNEL { 16 | PIT_CHANNEL_0 = 0, 17 | PIT_CHANNEL_2 = 2, 18 | PIT_READ_BACK_COMMAND = 3 19 | }; 20 | 21 | enum ACCESS_MODE { 22 | ACCESS_MODE_LATCH_COUNT = 0, 23 | ACCESS_MODE_LOBYTE_ONLY = 1, 24 | ACCESS_MODE_HIBYTE_ONLY = 2, 25 | ACCESS_MODE_LOBYTE_HIBYTE = 3 26 | }; 27 | 28 | enum PIT_MODE { 29 | PIT_MODE_INTERRUPT_ON_TERMINAL_COUNT = 0, 30 | PIT_MODE_HARDWARE_RETRIGGERABLE_ONE_SHOT = 1, 31 | PIT_MODE_RATE_GENERATOR = 2, 32 | PIT_MODE_SQUARE_WAVE_GENERATOR = 3, 33 | PIT_MODE_SOFTWARE_TRIGGERED_STROBE = 4, 34 | PIT_MODE_HARDWARE_TRIGGERED_STROBE = 5 35 | }; 36 | 37 | 38 | void init_pit(uint32_t requested_frequency, enum PIT_CHANNEL channel, enum ACCESS_MODE access_mode, enum PIT_MODE mode); 39 | 40 | void play_sound(uint32_t frequency); 41 | void no_sound(void); 42 | void on_sound(void); 43 | void restore_timer(void); 44 | 45 | void reset_timer(void); 46 | void reset_seconds(void); 47 | void reset_us(void); 48 | void increment_timer(void); 49 | uint64_t get_seconds(void); 50 | uint64_t get_us(void); 51 | 52 | void reset_ticks(void); 53 | void increment_ticks(void); 54 | void pit_wait_ticks(uint32_t ticks); 55 | void pit_wait_us(uint32_t us); 56 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/port_mapped_io/hardware_communication.s: -------------------------------------------------------------------------------- 1 | section .text 2 | global get_faulting_address 3 | get_faulting_address: 4 | mov eax, cr2 5 | ret 6 | 7 | 8 | global outb 9 | outb: 10 | xchg edx, eax 11 | out dx, al 12 | ret 13 | 14 | global outl 15 | outl: 16 | xchg edx, eax 17 | out dx, eax 18 | ret 19 | 20 | 21 | global inb 22 | inb: 23 | mov edx, eax 24 | in al, dx 25 | ret 26 | 27 | global inl 28 | inl: 29 | mov edx, eax 30 | in eax, dx 31 | ret 32 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/port_mapped_io/hardware_io.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void outw(uint16_t _port, uint16_t _data); 5 | 6 | uint16_t inw(uint16_t _port); 7 | 8 | void io_wait(void); 9 | 10 | void flush_tlb_single_page(uint32_t addr); 11 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/port_mapped_io/hardware_io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | extern uint32_t get_faulting_address(void); 7 | 8 | //TODO: add `outw` 9 | extern void __attribute__((regparm(2))) outb(uint16_t port, uint8_t value); 10 | inline void outw(uint16_t _port, uint16_t _data) { 11 | asm volatile ("outw %[data], %[port]" 12 | : /* No outputs */ 13 | : [port] "dN" (_port), [data] "a" (_data)); 14 | } 15 | extern void __attribute__((regparm(2))) outl(uint16_t port, uint32_t value); 16 | 17 | //TODO: add `inw` 18 | extern uint8_t __attribute__((regparm(1))) inb(uint16_t port); 19 | inline uint16_t inw(uint16_t _port) { 20 | uint16_t rv; 21 | 22 | asm volatile ("inw %[port], %[data]" 23 | : [data] "=a" (rv) 24 | : [port] "dN" (_port)); 25 | 26 | return rv; 27 | } 28 | extern uint32_t __attribute__((regparm(1))) inl(uint16_t port); 29 | 30 | inline void io_wait(void) { 31 | asm volatile("outb %%al, $0x80" : : "a"(0)); 32 | } 33 | 34 | inline void flush_tlb_single_page(const uint32_t addr) { 35 | asm volatile("invlpg (%0)" : : "r" (addr) : "memory"); 36 | //asm volatile("invlpg (%0)" : : "m" (addr)); 37 | } 38 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/serial/serial_driver.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | bool serial_init(void) { 5 | outb(COM1 + 1, 0x00); // Disable all interrupts 6 | outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor) 7 | outb(COM1 + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud 8 | outb(COM1 + 1, 0x00); // (hi byte) 9 | outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit 10 | outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 11 | outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set 12 | outb(COM1 + 4, 0x1E); // Set in loopback mode, test the serial chip 13 | outb(COM1 + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) 14 | 15 | if(inb(COM1 + 0) != 0xAE) return false; 16 | 17 | outb(COM1 + 4, 0x0F); 18 | return true; 19 | } 20 | 21 | 22 | uint8_t serial_received(void); 23 | 24 | uint8_t serial_read(void); 25 | 26 | uint8_t is_transmit_empty(void); 27 | 28 | void serial_putchar(char a); 29 | 30 | void serial_write(const char* text, size_t size); 31 | 32 | void serial_writestring(const char* text); 33 | 34 | 35 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/serial/serial_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kstring.h" 8 | #include 9 | 10 | 11 | //TODO: put these in an enum with a `serial_` prefix on the names 12 | #define COM1 0x3F8 13 | #define COM2 0x2F8 14 | #define COM3 0x3E8 15 | #define COM4 0x2E8 16 | 17 | 18 | //returns whether or not the serial is faulty. true = serial works properly. false = serial is faulty. 19 | bool serial_init(void); 20 | 21 | 22 | //TODO: maybe take the performance hit and make these functions externally linked instead for maintainability reasons 23 | 24 | inline uint8_t serial_received(void) { 25 | return inb(COM1 + 5) & 1u; 26 | } 27 | 28 | inline uint8_t serial_read(void) { 29 | while (serial_received() == 0); 30 | 31 | return inb(COM1); 32 | } 33 | 34 | inline uint8_t is_transmit_empty(void) { 35 | return inb(COM1 + 5) & 0x20u; 36 | } 37 | 38 | inline void serial_putchar(const char c) { 39 | while (is_transmit_empty() == 0); 40 | 41 | outb(COM1, (uint8_t)c); 42 | } 43 | 44 | 45 | size_t kstrlen(const char* str); 46 | 47 | inline void serial_write(const char *const text, const size_t size) { 48 | for(size_t i = 0u; i < size; ++i) { 49 | serial_putchar(text[i]); 50 | } 51 | } 52 | 53 | 54 | inline void serial_writestring(const char *const text) { 55 | serial_write(text, kstrlen(text)); 56 | } 57 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/vga_driver/default_vga_driver.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | static struct vga_driver_context default_vga_driver_context; 5 | 6 | static mutex_t global_vga_context_spinlock = false; 7 | 8 | 9 | void terminal_context_initialize(void) { 10 | acquire_spinlock(&global_vga_context_spinlock); 11 | terminal_initialize(&default_vga_driver_context); 12 | release_spinlock(&global_vga_context_spinlock); 13 | } 14 | void terminal_context_clear(void) { 15 | acquire_spinlock(&global_vga_context_spinlock); 16 | terminal_clear(&default_vga_driver_context); 17 | release_spinlock(&global_vga_context_spinlock); 18 | } 19 | void terminal_context_scroll_clear(void) { 20 | acquire_spinlock(&global_vga_context_spinlock); 21 | terminal_scroll_clear(&default_vga_driver_context); 22 | release_spinlock(&global_vga_context_spinlock); 23 | } 24 | void terminal_context_setcolor(const uint8_t color) { 25 | acquire_spinlock(&global_vga_context_spinlock); 26 | terminal_setcolor(&default_vga_driver_context, color); 27 | release_spinlock(&global_vga_context_spinlock); 28 | } 29 | void terminal_context_resetcolor(void) { 30 | acquire_spinlock(&global_vga_context_spinlock); 31 | terminal_resetcolor(&default_vga_driver_context); 32 | release_spinlock(&global_vga_context_spinlock); 33 | } 34 | void terminal_context_putentryat(const char c, const uint8_t color, const size_t x, const size_t y) { 35 | acquire_spinlock(&global_vga_context_spinlock); 36 | terminal_putentryat(&default_vga_driver_context, c, color, x, y); 37 | release_spinlock(&global_vga_context_spinlock); 38 | } 39 | void terminal_context_putchar(const char c) { 40 | acquire_spinlock(&global_vga_context_spinlock); 41 | terminal_putchar(&default_vga_driver_context, c); 42 | release_spinlock(&global_vga_context_spinlock); 43 | } 44 | void terminal_context_putchar_color(const char c, const uint8_t color) { 45 | acquire_spinlock(&global_vga_context_spinlock); 46 | terminal_putchar_color(&default_vga_driver_context, c, color); 47 | release_spinlock(&global_vga_context_spinlock); 48 | } 49 | void terminal_context_swapchar(const char c) { 50 | acquire_spinlock(&global_vga_context_spinlock); 51 | terminal_swapchar(&default_vga_driver_context, c); 52 | release_spinlock(&global_vga_context_spinlock); 53 | } 54 | void terminal_context_swapchar_color(const char c, const uint8_t color) { 55 | acquire_spinlock(&global_vga_context_spinlock); 56 | terminal_swapchar_color(&default_vga_driver_context, c, color); 57 | release_spinlock(&global_vga_context_spinlock); 58 | } 59 | void terminal_context_write(const char *const text, const size_t size) { 60 | acquire_spinlock(&global_vga_context_spinlock); 61 | terminal_write(&default_vga_driver_context, text, size); 62 | release_spinlock(&global_vga_context_spinlock); 63 | } 64 | void terminal_context_writestring(const char *const text) { 65 | acquire_spinlock(&global_vga_context_spinlock); 66 | terminal_writestring(&default_vga_driver_context, text); 67 | release_spinlock(&global_vga_context_spinlock); 68 | } 69 | void terminal_context_write_color(const char *const text, const size_t size, const uint8_t color) { 70 | acquire_spinlock(&global_vga_context_spinlock); 71 | terminal_write_color(&default_vga_driver_context, text, size, color); 72 | release_spinlock(&global_vga_context_spinlock); 73 | } 74 | void terminal_context_writestring_color(const char *const text, const uint8_t color) { 75 | acquire_spinlock(&global_vga_context_spinlock); 76 | terminal_writestring_color(&default_vga_driver_context, text, color); 77 | release_spinlock(&global_vga_context_spinlock); 78 | } 79 | void terminal_context_scroll_down(void) { 80 | acquire_spinlock(&global_vga_context_spinlock); 81 | terminal_scroll_down(&default_vga_driver_context); 82 | release_spinlock(&global_vga_context_spinlock); 83 | } 84 | void terminal_context_scroll_up(void) { 85 | acquire_spinlock(&global_vga_context_spinlock); 86 | terminal_scroll_up(&default_vga_driver_context); 87 | release_spinlock(&global_vga_context_spinlock); 88 | } 89 | void terminal_context_cursor_up(void) { 90 | acquire_spinlock(&global_vga_context_spinlock); 91 | terminal_cursor_up(&default_vga_driver_context); 92 | release_spinlock(&global_vga_context_spinlock); 93 | } 94 | void terminal_context_cursor_left(void) { 95 | acquire_spinlock(&global_vga_context_spinlock); 96 | terminal_cursor_left(&default_vga_driver_context); 97 | release_spinlock(&global_vga_context_spinlock); 98 | } 99 | void terminal_context_cursor_right(void) { 100 | acquire_spinlock(&global_vga_context_spinlock); 101 | terminal_cursor_right(&default_vga_driver_context); 102 | release_spinlock(&global_vga_context_spinlock); 103 | } 104 | void terminal_context_cursor_down(void) { 105 | acquire_spinlock(&global_vga_context_spinlock); 106 | terminal_cursor_down(&default_vga_driver_context); 107 | release_spinlock(&global_vga_context_spinlock); 108 | } 109 | void terminal_context_backspace(void) { 110 | acquire_spinlock(&global_vga_context_spinlock); 111 | terminal_backspace(&default_vga_driver_context); 112 | release_spinlock(&global_vga_context_spinlock); 113 | } 114 | void terminal_context_updatecursor(void) { 115 | acquire_spinlock(&global_vga_context_spinlock); 116 | terminal_updatecursor(&default_vga_driver_context); 117 | release_spinlock(&global_vga_context_spinlock); 118 | } 119 | 120 | 121 | struct vga_driver_context* get_default_vga_context(void) { 122 | return &default_vga_driver_context; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/vga_driver/default_vga_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | 12 | void terminal_context_initialize(void); 13 | void terminal_context_clear(void); 14 | void terminal_context_scroll_clear(void); 15 | void terminal_context_setcolor(uint8_t color); 16 | void terminal_context_resetcolor(void); 17 | void terminal_context_putentryat(char c, uint8_t color, size_t x, size_t y); 18 | void terminal_context_putchar(char c); 19 | void terminal_context_putchar_color(char c, uint8_t color); 20 | void terminal_context_swapchar(char c); 21 | void terminal_context_swapchar_color(char c, uint8_t color); 22 | void terminal_context_write(const char* text, size_t size); 23 | void terminal_context_writestring(const char* text); 24 | void terminal_context_write_color(const char* text, size_t size, uint8_t color); 25 | void terminal_context_writestring_color(const char* text, uint8_t color); 26 | void terminal_context_scroll_down(void); 27 | void terminal_context_scroll_up(void); 28 | void terminal_context_cursor_up(void); 29 | void terminal_context_cursor_left(void); 30 | void terminal_context_cursor_right(void); 31 | void terminal_context_cursor_down(void); 32 | void terminal_context_backspace(void); 33 | void terminal_context_updatecursor(void); 34 | 35 | 36 | //unfortunate escape hatch to the global needed by the terminal system 37 | //(unless the user substitutes in or uses a custom vga context) 38 | struct vga_driver_context* get_default_vga_context(void); 39 | -------------------------------------------------------------------------------- /kernel/arch/i686/drivers/vga_driver/vga_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "kstring.h" 10 | //#include "hardware_io.h" 11 | //#include "terminal_driver.h" 12 | 13 | 14 | #define VGA_WIDTH 80 15 | #define VGA_HEIGHT 25 16 | 17 | 18 | //hardware text mode color constants 19 | enum vga_color { 20 | VGA_COLOR_BLACK = 0, 21 | VGA_COLOR_BLUE = 1, 22 | VGA_COLOR_GREEN = 2, 23 | VGA_COLOR_CYAN = 3, 24 | VGA_COLOR_RED = 4, 25 | VGA_COLOR_MAGENTA = 5, 26 | VGA_COLOR_BROWN = 6, 27 | VGA_COLOR_LIGHT_GREY = 7, 28 | VGA_COLOR_DARK_GREY = 8, 29 | VGA_COLOR_LIGHT_BLUE = 9, 30 | VGA_COLOR_LIGHT_GREEN = 10, 31 | VGA_COLOR_LIGHT_CYAN = 11, 32 | VGA_COLOR_LIGHT_RED = 12, 33 | VGA_COLOR_LIGHT_MAGENTA = 13, 34 | VGA_COLOR_LIGHT_BROWN = 14, 35 | VGA_COLOR_WHITE = 15, 36 | }; 37 | 38 | 39 | struct vga_driver_context { 40 | size_t terminal_row; 41 | size_t terminal_column; 42 | enum vga_color terminal_color; 43 | volatile uint16_t* terminal_buffer; 44 | bool terminal_on; 45 | 46 | uint16_t terminal_upward_history[VGA_WIDTH * VGA_HEIGHT]; 47 | uint16_t terminal_downward_history[VGA_WIDTH * VGA_HEIGHT]; 48 | size_t terminal_upward_history_size; 49 | size_t terminal_downward_history_size; 50 | }; 51 | 52 | 53 | //these two functions are correct by inspection: 54 | inline uint8_t vga_entry_color(const enum vga_color fg, const enum vga_color bg) { 55 | return (uint8_t) (fg | bg << 4u); 56 | } 57 | 58 | inline uint16_t vga_entry(const char uc, const enum vga_color color) { 59 | return (uint16_t) ((uint16_t) uc | (uint16_t) color << 8u); 60 | } 61 | 62 | 63 | void terminal_initialize(struct vga_driver_context* context); 64 | void terminal_clear(struct vga_driver_context* context); 65 | void terminal_scroll_clear(struct vga_driver_context* context); 66 | void terminal_setcolor(struct vga_driver_context* context, enum vga_color color); 67 | void terminal_resetcolor(struct vga_driver_context* context); 68 | void terminal_putentryat(struct vga_driver_context* context, char c, enum vga_color color, size_t x, size_t y); 69 | void terminal_putchar(struct vga_driver_context* context, char c); 70 | void terminal_putchar_color(struct vga_driver_context* context, char c, enum vga_color color); 71 | void terminal_swapchar(struct vga_driver_context* context, char c); 72 | void terminal_swapchar_color(struct vga_driver_context* context, char c, enum vga_color color); 73 | void terminal_write(struct vga_driver_context* context, const char* text, size_t size); 74 | void terminal_writestring(struct vga_driver_context* context, const char* text); 75 | void terminal_write_color(struct vga_driver_context* context, const char* text, size_t size, enum vga_color color); 76 | void terminal_writestring_color(struct vga_driver_context* context, const char* text, enum vga_color color); 77 | void terminal_scroll_down(struct vga_driver_context* context); 78 | void terminal_scroll_up(struct vga_driver_context* context); 79 | void terminal_cursor_up(struct vga_driver_context* context); 80 | void terminal_cursor_left(struct vga_driver_context* context); 81 | void terminal_cursor_right(struct vga_driver_context* context); 82 | void terminal_cursor_down(struct vga_driver_context* context); 83 | void terminal_backspace(struct vga_driver_context* context); 84 | void terminal_updatecursor(struct vga_driver_context* context); 85 | -------------------------------------------------------------------------------- /kernel/arch/i686/interrupts/enable_interrupts.s: -------------------------------------------------------------------------------- 1 | section .text 2 | global enable_interrupts 3 | enable_interrupts: 4 | sti 5 | ret 6 | 7 | global disable_interrupts 8 | disable_interrupts: 9 | cli 10 | ret 11 | -------------------------------------------------------------------------------- /kernel/arch/i686/interrupts/interrupt_handler.s: -------------------------------------------------------------------------------- 1 | %macro save_context 0 2 | push ebp 3 | push edi 4 | push esi 5 | push edx 6 | push ecx 7 | push ebx 8 | push eax 9 | %endmacro 10 | 11 | %macro restore_context 0 12 | pop eax 13 | pop ebx 14 | pop ecx 15 | pop edx 16 | pop esi 17 | pop edi 18 | pop ebp 19 | %endmacro 20 | 21 | %macro restore_kernel_segments 0 22 | push eax 23 | mov ds, eax 24 | mov es, eax 25 | mov es, eax 26 | mov gs, eax 27 | pop eax 28 | %endmacro 29 | 30 | %macro create_irq 1 31 | push eax 32 | push %1 33 | 34 | jmp irq_common_handler 35 | %endmacro 36 | 37 | section .text 38 | global irq_common_handler 39 | irq_common_handler: 40 | push ebp 41 | mov ebp, esp 42 | 43 | push eax 44 | push edx 45 | 46 | mov eax, esp 47 | 48 | extern system_call 49 | call system_call 50 | 51 | add esp, 8 52 | 53 | pop ebp 54 | 55 | iret 56 | 57 | -------------------------------------------------------------------------------- /kernel/arch/i686/interrupts/interrupt_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | enum IDTFlags { 7 | IDT_PRESENT = 1 << 7, 8 | IDT_RING_0 = 0 << 5, 9 | IDT_RING_1 = 1 << 5, 10 | IDT_RING_2 = 2 << 5, 11 | IDT_RING_3 = 3 << 5, 12 | IDT_SS = 1 << 4, 13 | IDT_INTERRUPT = 0xE, 14 | IDT_TRAP = 0xF, 15 | }; 16 | 17 | struct interrupt_frame { 18 | uint16_t error_code; 19 | uint16_t reserved1; 20 | uint32_t eip; 21 | uint16_t cs; 22 | uint16_t reserved2; 23 | uint32_t eflags; 24 | uint32_t esp; 25 | uint16_t ss; 26 | uint16_t reserved3; 27 | uint16_t es; 28 | uint16_t reserved4; 29 | uint16_t ds; 30 | uint16_t reserved5; 31 | uint16_t fs; 32 | uint16_t reserved6; 33 | uint16_t gs; 34 | uint16_t reserved7; 35 | }; 36 | 37 | struct syscall_regs { 38 | uint32_t eax; 39 | uint32_t ebx; 40 | uint32_t ecx; 41 | uint32_t edx; 42 | uint32_t esi; 43 | uint32_t edi; 44 | uint32_t ebp; 45 | uint32_t eip; 46 | uint32_t eflags; 47 | uint32_t esp; 48 | uint32_t cr3; 49 | }; 50 | 51 | struct IDT_entry { 52 | uint16_t offset_lowerbits; 53 | uint16_t selector; 54 | uint8_t zero; 55 | uint8_t type_attr; 56 | uint16_t offset_higherbits; 57 | }; 58 | -------------------------------------------------------------------------------- /kernel/arch/i686/interrupts/interrupts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include "kstdio.h" 7 | #include 8 | #include "interrupt_types.h" 9 | #include 10 | 11 | #include 12 | 13 | 14 | void pic_init(void); 15 | void isr_install(void); 16 | 17 | void pic_send_eoi(uint8_t no); 18 | void pic_irq_enable(uint8_t no); 19 | void idt_register_handler(uint8_t interrupt, uint32_t address); 20 | 21 | void enable_interrupts(void); 22 | void disable_interrupts(void); 23 | 24 | 25 | extern uint32_t __attribute__((naked)) __attribute__((regparm(2))) irq_common_handler(uint32_t eax, uint32_t edx); 26 | -------------------------------------------------------------------------------- /kernel/arch/i686/linker.ld: -------------------------------------------------------------------------------- 1 | 2 | ENTRY(_start) 3 | 4 | KERNEL_OFFSET = 0xC0000000; 5 | KERNEL_START = 0x00100000; /*0x10000;*/ 6 | 7 | SECTIONS 8 | { 9 | . = KERNEL_START + KERNEL_OFFSET; 10 | 11 | .text : AT(ADDR(.text) - KERNEL_OFFSET) 12 | { 13 | immutable_data_start = .; 14 | text_start = .; 15 | *(.multiboot) 16 | *(.text) 17 | text_end = .; 18 | } 19 | . = ALIGN(4K); 20 | .rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) 21 | { 22 | rodata_start = .; 23 | *(.rodata) 24 | rodata_end = .; 25 | immutable_data_end = .; 26 | } 27 | 28 | . = ALIGN(4K); 29 | .data : AT(ADDR(.data) - KERNEL_OFFSET) 30 | { 31 | mutable_data_start = .; 32 | data_start = .; 33 | *(.data) 34 | data_end = .; 35 | } 36 | . = ALIGN(4K); 37 | .bss : AT(ADDR(.bss) - KERNEL_OFFSET) 38 | { 39 | bss_start = .; 40 | *(.COMMON) 41 | *(.bss) 42 | bss_end = .; 43 | mutable_data_end = .; 44 | } 45 | 46 | /* TODO: should be `kernel_end`*/ 47 | endkernel = .; /* define address of extern variable to mark the end of the kernel address space */ 48 | } 49 | -------------------------------------------------------------------------------- /kernel/arch/i686/make.config: -------------------------------------------------------------------------------- 1 | ARCH_CFLAGS= 2 | ARCH_CPPFLAGS= 3 | KERNEL_ARCH_CFLAGS= 4 | KERNEL_ARCH_CPPFLAGS= 5 | 6 | ARCH_FREEOBJS=\ 7 | 8 | ARCH_HOSTEDOBJS=\ 9 | -------------------------------------------------------------------------------- /kernel/arch/i686/osi_shim/acpi_init.c: -------------------------------------------------------------------------------- 1 | #include "acpi_init.h" 2 | 3 | 4 | static const char* AcpiGbl_ExceptionNames_Env[] = { 5 | "AE_OK", 6 | "AE_ERROR", 7 | "AE_NO_ACPI_TABLES", 8 | "AE_NO_NAMESPACE", 9 | "AE_NO_MEMORY", 10 | "AE_NOT_FOUND", 11 | "AE_NOT_EXIST", 12 | "AE_ALREADY_EXISTS", 13 | "AE_TYPE", 14 | "AE_NULL_OBJECT", 15 | "AE_NULL_ENTRY", 16 | "AE_BUFFER_OVERFLOW", 17 | "AE_STACK_OVERFLOW", 18 | "AE_STACK_UNDERFLOW", 19 | "AE_NOT_IMPLEMENTED", 20 | "AE_SUPPORT", 21 | "AE_LIMIT", 22 | "AE_TIME", 23 | "AE_ACQUIRE_DEADLOCK", 24 | "AE_RELEASE_DEADLOCK", 25 | "AE_NOT_ACQUIRED", 26 | "AE_ALREADY_ACQUIRED", 27 | "AE_NO_HARDWARE_RESPONSE", 28 | "AE_NO_GLOBAL_LOCK", 29 | "AE_ABORT_METHOD", 30 | "AE_SAME_HANDLER", 31 | "AE_NO_HANDLER", 32 | "AE_OWNER_ID_LIMIT", 33 | "AE_NOT_CONFIGURED", 34 | "AE_ACCESS", 35 | "AE_IO_ERROR" 36 | }; 37 | 38 | void acpi_init(void) { 39 | disable_interrupts(); 40 | 41 | ACPI_STATUS status = AcpiInitializeSubsystem(); 42 | if(ACPI_FAILURE(status)) { 43 | kprintf("acpica: Impossible to initialize subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status]); 44 | } 45 | kprintf("before AcpiInitializeTables\n"); 46 | status = AcpiInitializeTables(NULL, 16, true); 47 | if(ACPI_FAILURE(status)) { 48 | kprintf("acpica: Impossible to initialize tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status]); 49 | } 50 | kprintf("before AcpiLoadTables\n"); 51 | status = AcpiLoadTables(); 52 | if(ACPI_FAILURE(status)) { 53 | kprintf("acpica: Impossible to load tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status]); 54 | } 55 | kprintf("before AcpiEnableSubsystem\n"); 56 | status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); 57 | if(ACPI_FAILURE(status)) { 58 | kprintf("acpica: Impossible to enable subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status]); 59 | } 60 | kprintf("before AcpiInitializeObjects\n"); 61 | status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION); 62 | if(ACPI_FAILURE(status)) { 63 | kprintf("acpica: Impossible to initialize objects: error: %s\n", AcpiGbl_ExceptionNames_Env[status]); 64 | } 65 | kprintf("AcpiInitializeObjects passed\n"); 66 | 67 | kprintf("\nACPICA initialized\n\n\n"); 68 | 69 | disable_interrupts(); 70 | } 71 | -------------------------------------------------------------------------------- /kernel/arch/i686/osi_shim/acpi_init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "interrupts.h" 4 | #include "kstdio.h" 5 | #include "../acpica/acpi.h" 6 | 7 | 8 | void acpi_init(void); 9 | 10 | -------------------------------------------------------------------------------- /kernel/arch/i686/usermode/gdt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void test_user_function(void) { 5 | const volatile uint32_t ret0 = print_int(40); 6 | print_int(ret0); 7 | const volatile uint32_t ret1 = print_int(5); 8 | print_int(ret1); 9 | const volatile uint32_t ret2 = print_int(6); 10 | print_int(ret2); 11 | const volatile uint32_t ret3 = print_int(2); 12 | print_int(ret3); 13 | 14 | const volatile uint32_t ret4 = print("test"); 15 | print_int(ret4); 16 | const volatile uint32_t ret5 = print("test2"); 17 | print_int(ret5); 18 | const volatile uint32_t ret6 = print("test3"); 19 | print_int(ret6); 20 | 21 | for(volatile int i = 0; ; ++i); 22 | } 23 | 24 | //extern void* stack_bottom; 25 | //extern void* stack_top; 26 | 27 | 28 | struct gdt_entry { 29 | uint16_t limit_low; 30 | uint16_t base_low_1; 31 | uint8_t base_low_2; 32 | uint8_t settings_flags; //bitset 33 | uint8_t size_flags; //bitset 34 | uint8_t base_high; 35 | }; 36 | 37 | struct gdt_ptr { 38 | uint16_t limit; 39 | uint32_t base; 40 | } __attribute__((packed)); 41 | 42 | //binary literals are clearer/more readable than hex in this case 43 | //`#pragma GCC diagnostic ignored "-Wpedantic"` does not work, hence why `__extension__` is used instead 44 | struct gdt_entry gdt_entries[7] = { 45 | {0, 0, 0, 0, 0, 0}, 46 | {0xffff, 0, 0, __extension__ 0b10011010, __extension__ 0b11001111, 0}, 47 | {0xffff, 0, 0, __extension__ 0b10010010, __extension__ 0b11001111, 0}, 48 | {0xffff, 0, 0, __extension__ 0b11111010, __extension__ 0b11011111, 0}, 49 | {0xffff, 0, 0, __extension__ 0b11110010, __extension__ 0b11011111, 0}, 50 | {0, 0, 0, 0, 0, 0}, 51 | {0, 0, 0, 0, 0, 0} 52 | }; 53 | struct gdt_ptr gdt_entries_ptr = { 54 | (sizeof(struct gdt_entry) * 7) - 1, 55 | (uint32_t) &gdt_entries[0] 56 | }; 57 | 58 | 59 | struct tss_entry_struct tss_entry; 60 | 61 | 62 | void gdt_init(void) { 63 | const uint32_t base = (uint32_t) &tss_entry; 64 | const uint32_t limit = sizeof(struct tss_entry_struct); 65 | 66 | gdt_entries[5].limit_low = limit & 0xFFFF; 67 | gdt_entries[5].base_low_1 = base & 0xFFFF; 68 | gdt_entries[5].base_low_2 = (base & 0xFF0000) >> 16; 69 | gdt_entries[5].settings_flags = __extension__ 0b11101001; 70 | gdt_entries[5].size_flags = (uint8_t) (limit & 0xF0000); 71 | gdt_entries[5].base_high = (uint8_t) ((base & 0xFF000000) >> 24); 72 | } 73 | 74 | 75 | static uint32_t* kernel_stack_phys_page; 76 | static uint32_t* kernel_stack_virt_page; 77 | 78 | uint32_t* get_kernel_stack_phys_page(void) { 79 | return kernel_stack_phys_page; 80 | } 81 | uint32_t* get_kernel_stack_virt_page(void) { 82 | return kernel_stack_virt_page; 83 | } 84 | 85 | extern uint32_t BootStack; 86 | 87 | void write_tss(void) { 88 | kprintf("Writing TSS\n"); 89 | kmemset(&tss_entry, 0, sizeof(struct tss_entry_struct)); 90 | 91 | kprintf("kmemset tss_entry to 0\n"); 92 | 93 | tss_entry.ss0 = 2*sizeof(struct gdt_entry); 94 | 95 | kprintf("wrote to tss_entry.ss0\n"); 96 | 97 | kernel_stack_phys_page = global_phys_allocator_allocate_page(); 98 | kprintf("Allocated physical page: %X\n", kernel_stack_phys_page); 99 | kernel_stack_virt_page = kernel_virt_allocator_allocate_page(); 100 | kprintf("Allocated virtual page: %p\n", kernel_stack_virt_page); 101 | map_page_in_kernel_addr(kernel_stack_virt_page, (uint32_t)kernel_stack_phys_page, PT_PRESENT | PT_RW, PD_PRESENT | PD_RW); 102 | kprintf("Mapped page\n"); 103 | tss_entry.esp0 = ((uint32_t) kernel_stack_virt_page) + PAGE_SIZE; 104 | kprintf("wrote to tss_entry.esp0\n"); 105 | 106 | flush_tss(); 107 | kprintf("Flushed TSS\n"); 108 | } 109 | 110 | void set_kernel_stack(const uint32_t stack) { // Used when an interrupt occurs 111 | tss_entry.esp0 = stack; 112 | } 113 | -------------------------------------------------------------------------------- /kernel/arch/i686/usermode/gdt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "system_call_implementations.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | struct tss_entry_struct { 19 | uint32_t prev_tss; // The previous TSS - with hardware task switching these form a kind of backward linked list. 20 | uint32_t esp0; // The stack pointer to load when changing to kernel mode. 21 | uint32_t ss0; // The stack segment to load when changing to kernel mode. 22 | // Everything below here is unused. 23 | uint32_t esp1; // esp and ss 1 and 2 would be used when switching to rings 1 or 2. 24 | uint32_t ss1; 25 | uint32_t esp2; 26 | uint32_t ss2; 27 | uint32_t cr3; 28 | uint32_t eip; 29 | uint32_t eflags; 30 | uint32_t eax; 31 | uint32_t ecx; 32 | uint32_t edx; 33 | uint32_t ebx; 34 | uint32_t esp; 35 | uint32_t ebp; 36 | uint32_t esi; 37 | uint32_t edi; 38 | uint32_t es; 39 | uint32_t cs; 40 | uint32_t ss; 41 | uint32_t ds; 42 | uint32_t fs; 43 | uint32_t gs; 44 | uint32_t ldt; 45 | uint16_t trap; 46 | uint16_t iomap_base; 47 | }; 48 | 49 | extern struct tss_entry_struct tss_entry; 50 | 51 | 52 | extern void gdt_load(void); 53 | extern void jump_usermode(void); 54 | extern void flush_tss(void); 55 | 56 | void gdt_init(void); 57 | void write_tss(void); 58 | uint32_t* get_kernel_stack_phys_page(void); 59 | uint32_t* get_kernel_stack_virt_page(void); 60 | void set_kernel_stack(uint32_t stack); 61 | -------------------------------------------------------------------------------- /kernel/arch/i686/usermode/gdt_entries.s: -------------------------------------------------------------------------------- 1 | section .text 2 | extern gdt_entries_ptr 3 | global gdt_load 4 | gdt_load: 5 | push eax 6 | lgdt [gdt_entries_ptr] 7 | jmp 0x08:.loaded_cs 8 | .loaded_cs: 9 | mov ax, 0x10 10 | mov ds, ax 11 | mov es, ax 12 | mov fs, ax 13 | mov gs, ax 14 | mov ss, ax 15 | pop eax 16 | ret 17 | 18 | 19 | global flush_tss 20 | flush_tss: 21 | mov ax, (5 * 8) | 3 ; fifth 8-byte selector. Or with 3 to set the RPL (requested privilege level). 22 | ltr ax 23 | ret 24 | 25 | 26 | global jump_usermode 27 | extern test_user_function 28 | jump_usermode: 29 | mov ax, (4 * 8) | 3 ; ring 3 data with bottom 2 bits set for ring 3 30 | mov ds, ax 31 | mov es, ax 32 | mov fs, ax 33 | mov gs, ax ; SS is handled by iret 34 | 35 | ; set up the stack frame iret expects 36 | mov eax, esp 37 | push (4 * 8) | 3 ; data selector 38 | push eax ; current esp 39 | pushf ; eflags 40 | push (3 * 8) | 3 ; code selector (ring 3 code with bottom 2 bits set for ring 3) 41 | push test_user_function ; instruction address to return to 42 | iret 43 | -------------------------------------------------------------------------------- /kernel/arch/i686/usermode/system_call_handler.s: -------------------------------------------------------------------------------- 1 | section .text 2 | global print_int 3 | print_int: 4 | push ebp 5 | mov ebp, esp 6 | push edx 7 | mov edx, 0 8 | int 128 9 | pop edx 10 | pop ebp 11 | ret 12 | 13 | 14 | global print 15 | print: 16 | push ebp 17 | mov ebp, esp 18 | push edx 19 | mov edx, 1 20 | int 128 21 | pop edx 22 | pop ebp 23 | ret 24 | 25 | -------------------------------------------------------------------------------- /kernel/arch/i686/usermode/system_call_implementations.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | #define SYS_LOG 0 8 | #define SYS_MMAP 1 9 | #define SYS_MUNMAP 2 10 | #define SYS_OPEN 3 11 | #define SYS_CLOSE 4 12 | #define SYS_READ 5 13 | #define SYS_WRITE 6 14 | 15 | 16 | extern uint32_t __attribute__((naked)) __attribute__((regparm(1))) print_int(uint32_t eax); 17 | 18 | extern uint32_t __attribute__((naked)) __attribute__((regparm(1))) print(const char* str); 19 | -------------------------------------------------------------------------------- /kernel/include/kernel/utils/communication_and_events/message_queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | //this is a fixed size type safe ring buffer implementation 9 | #define GENERATE_QUEUE_DECLARATION(MAX_NUM_OF_ITEMS, TYPE_OF_DATA) \ 10 | struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS { \ 11 | uint32_t read_index; \ 12 | uint32_t write_index; \ 13 | TYPE_OF_DATA items_buffer[MAX_NUM_OF_ITEMS]; \ 14 | }; \ 15 | struct return_type_##TYPE_OF_DATA { \ 16 | TYPE_OF_DATA data; \ 17 | bool succeeded; \ 18 | }; \ 19 | void queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_init(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS* queue); \ 20 | bool queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_enqueue(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS* queue, TYPE_OF_DATA new_item); \ 21 | struct return_type_##TYPE_OF_DATA queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_dequeue(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS* queue); \ 22 | bool queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_is_empty(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS* queue); 23 | 24 | #define GENERATE_QUEUE_DEFINITION(MAX_NUM_OF_ITEMS, TYPE_OF_DATA) \ 25 | void queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_init(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS *const queue) { \ 26 | queue->read_index = 0u; \ 27 | queue->write_index = 0u; \ 28 | } \ 29 | bool queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_enqueue(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS *const queue, const TYPE_OF_DATA new_item) { \ 30 | const uint32_t num_of_elements = queue->write_index - queue->read_index; \ 31 | \ 32 | const size_t capacity = sizeof(queue->items_buffer)/sizeof(TYPE_OF_DATA); \ 33 | if(capacity == num_of_elements) { \ 34 | return false; /*failed, do nothing more*/ \ 35 | } \ 36 | \ 37 | /*the modulo is to make it wrap since this is a ring buffer*/ \ 38 | const uint32_t index = queue->write_index++ % (capacity-1u); \ 39 | queue->write_index %= (capacity-1u); /*to stop eventual integer overflow*/\ 40 | queue->items_buffer[index] = new_item; \ 41 | return true; /*success*/ \ 42 | } \ 43 | struct return_type_##TYPE_OF_DATA queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_dequeue(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS *const queue) { \ 44 | const uint32_t num_of_elements = queue->write_index - queue->read_index; \ 45 | if(num_of_elements == 0u) { \ 46 | return (struct return_type_##TYPE_OF_DATA){ .succeeded = false }; \ 47 | } \ 48 | \ 49 | const size_t capacity = sizeof(queue->items_buffer)/sizeof(TYPE_OF_DATA); \ 50 | const uint32_t index = queue->read_index++ % (capacity-1u); \ 51 | queue->read_index %= (capacity-1u); \ 52 | \ 53 | return (struct return_type_##TYPE_OF_DATA){ .data = queue->items_buffer[index], .succeeded = true }; \ 54 | } \ 55 | bool queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS##_is_empty(struct queue_##TYPE_OF_DATA##_##MAX_NUM_OF_ITEMS *const queue) { \ 56 | return queue->read_index == queue->write_index; \ 57 | } 58 | -------------------------------------------------------------------------------- /kernel/include/kernel/utils/communication_and_events/observer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | enum event_types { 10 | KEYBOARD_EVENT = 0u, 11 | }; 12 | 13 | 14 | #define GENERATE_SUBJECT_DECLARATION(MAX_NUM_OF_OBSERVERS, TYPE_OF_DATA) \ 15 | struct TYPE_OF_DATA##_event { \ 16 | size_t event_type; \ 17 | struct TYPE_OF_DATA data; \ 18 | }; \ 19 | struct TYPE_OF_DATA##_observer { /*is just a special function object*/ \ 20 | void* context; /*stores data*/ \ 21 | void (*on_notify)(void* context, struct TYPE_OF_DATA##_event event); /*first param should be corresponding `context` member*/ \ 22 | }; \ 23 | struct subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS { \ 24 | struct TYPE_OF_DATA##_observer* observers[MAX_NUM_OF_OBSERVERS]; \ 25 | uint32_t num_of_active_observers; /*the whole buffer is not guarenteed to be filled*/ \ 26 | }; \ 27 | bool add_observer_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(struct subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS* subject, struct TYPE_OF_DATA##_observer* observer); \ 28 | bool remove_observer_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(struct subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS* subject, const struct TYPE_OF_DATA##_observer* observer); \ 29 | void notify_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(struct subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS* subject, struct TYPE_OF_DATA##_event event); 30 | 31 | #define GENERATE_SUBJECT_DEFINITION(MAX_NUM_OF_OBSERVERS, TYPE_OF_DATA) \ 32 | bool add_observer_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(struct subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS *const subject, struct TYPE_OF_DATA##_observer *const observer) { \ 33 | kprintf("add_observer\n"); \ 34 | if(subject->num_of_active_observers == (uint32_t) MAX_NUM_OF_OBSERVERS) { \ 35 | return false; /*can't add it since it is full*/ \ 36 | } \ 37 | \ 38 | subject->observers[subject->num_of_active_observers++] = observer; \ 39 | return true; \ 40 | } \ 41 | bool remove_observer_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(struct subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS *const subject, const struct TYPE_OF_DATA##_observer *const observer) { \ 42 | kprintf("remove_observer\n"); \ 43 | for(uint32_t i = 0u; i < subject->num_of_active_observers; ++i) { \ 44 | if(subject->observers[i] == observer) { \ 45 | subject->observers[i] = subject->observers[--subject->num_of_active_observers]; \ 46 | return true; \ 47 | } \ 48 | } \ 49 | \ 50 | return false; /*`observer` wasn't in the `observers` array*/ \ 51 | } \ 52 | void notify_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(struct subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS *const subject, const struct TYPE_OF_DATA##_event event) { \ 53 | kprintf("notify\n"); \ 54 | for(uint32_t i = 0; i < subject->num_of_active_observers; ++i) { \ 55 | subject->observers[i]->on_notify(subject->observers[i]->context, event); \ 56 | } \ 57 | } 58 | 59 | 60 | #define GET_EVENT_TYPENAME(TYPE_OF_DATA) TYPE_OF_DATA##_event 61 | #define GET_OBSERVER_TYPENAME(TYPE_OF_DATA) TYPE_OF_DATA##_observer 62 | #define GET_SUBJECT_TYPENAME(MAX_NUM_OF_OBSERVERS, TYPE_OF_DATA) subject_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS 63 | 64 | #define ADD_OBSERVER(MAX_NUM_OF_OBSERVERS, TYPE_OF_DATA, SUBJECT, OBSERVER) add_observer_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(SUBJECT, OBSERVER) 65 | #define REMOVE_OBSERVER(MAX_NUM_OF_OBSERVERS, TYPE_OF_DATA, SUBJECT, OBSERVER) remove_observer_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(SUBJECT, OBSERVER) 66 | #define NOTIFY(MAX_NUM_OF_OBSERVERS, TYPE_OF_DATA, SUBJECT, EVENT) notify_##TYPE_OF_DATA##_##MAX_NUM_OF_OBSERVERS(SUBJECT, EVENT) 67 | -------------------------------------------------------------------------------- /kernel/kernel/ATA/ata_driver.c: -------------------------------------------------------------------------------- 1 | #include "ata_driver.h" 2 | 3 | 4 | 5 | #define PRIMARY_IO_BASE_PORT 0x1F0 6 | #define SECONDARY_IO_BASE_PORT 0x170 7 | #define PRIMARY_CONTROL_BASE_PORT 0x3F6 8 | #define SECONDARY_CONTROL_BASE_PORT 0x376 9 | 10 | bool ata_driver_init(struct ata_driver *const driver) { 11 | kassert(driver != NULL, false); 12 | 13 | ata_device_init(&driver->primary_master, true, false); 14 | ata_device_init(&driver->primary_slave, true, true); 15 | ata_device_init(&driver->secondary_master, false, false); 16 | ata_device_init(&driver->secondary_slave, false, true); 17 | 18 | return true; 19 | } 20 | 21 | bool ata_device_init(struct ata_device *const device, bool primary, bool slave) { 22 | kassert(device != NULL, false); 23 | 24 | const uint16_t io_base = primary ? PRIMARY_IO_BASE_PORT : SECONDARY_IO_BASE_PORT; 25 | const uint16_t control_base = primary ? PRIMARY_CONTROL_BASE_PORT : SECONDARY_CONTROL_BASE_PORT; 26 | 27 | device->data = io_base; 28 | device->error = io_base + 1; 29 | device->sector_count = io_base + 2; 30 | device->sector_num = io_base + 3; 31 | device->cylinder_low = io_base + 4; 32 | device->cylinder_high = io_base + 5; 33 | device->drive = io_base + 6; 34 | device->status = io_base + 7; 35 | 36 | device->alternate_status = control_base; 37 | device->device_address = control_base + 1; 38 | 39 | device->slave = slave; 40 | device->primary = primary; 41 | 42 | device->enabled = false; 43 | 44 | return true; 45 | } 46 | 47 | 48 | #define STATUS_REG_BSY 0x80 49 | #define STATUS_REG_DRQ 0x08 50 | #define STATUS_REG_ERR 0x01 51 | 52 | #define IDENTIFY_COMMAND 0xEC 53 | 54 | bool ata_identity(struct ata_device *const device) { 55 | kassert(device != NULL, false); 56 | 57 | outb(device->drive, (0xA0 | (device->slave << 4))); 58 | 59 | outb(device->sector_count, 0); 60 | outb(device->lba_low, 0); 61 | outb(device->lba_mid, 0); 62 | outb(device->lba_high, 0); 63 | 64 | outb(device->command, IDENTIFY_COMMAND); 65 | 66 | const uint8_t status = inb(device->status); 67 | if (!status) { 68 | return false; 69 | } 70 | 71 | while (true) { 72 | const uint8_t status = inb(device->status); 73 | if (status & STATUS_REG_DRQ) { 74 | break; 75 | } 76 | if(status & STATUS_REG_ERR) { 77 | return false; 78 | } 79 | } 80 | 81 | for (uint32_t i = 0; i < 256; i++) { 82 | inw(device->data); 83 | } 84 | 85 | device->enabled = true; 86 | 87 | return true; 88 | } 89 | 90 | bool read_single_sector(struct ata_device *const device, uint32_t lba, uint8_t *const buffer) { 91 | kassert(device != NULL, false); 92 | kassert(buffer != NULL, false); 93 | 94 | const uint8_t status = inb(device->status); 95 | if ((status & STATUS_REG_BSY) || (status & STATUS_REG_DRQ)) { 96 | outb(device->device_control, 4); 97 | outb(device->device_control, 0); 98 | } 99 | 100 | outb(device->drive, (0xE0 | (device->slave << 4)) | ((lba >> 24) & 0x0F)); 101 | 102 | outb(device->sector_count, 1); 103 | 104 | outb(device->lba_low, lba & 0xFF); 105 | outb(device->lba_mid, (lba >> 8) & 0xFF); 106 | outb(device->lba_high, (lba >> 16) & 0xFF); 107 | 108 | outb(device->command, 0x20); 109 | 110 | while (true) { 111 | const uint8_t status = inb(device->status); 112 | if (!(status & STATUS_REG_BSY) && (status & STATUS_REG_DRQ)) { 113 | break; 114 | } 115 | } 116 | 117 | for (size_t i = 0; i < 256; i++) { 118 | ((uint16_t*)buffer)[i] = inw(device->data); 119 | } 120 | 121 | for (int i = 0; i < 4; i++) { 122 | inb(device->alternate_status); 123 | } 124 | 125 | return true; 126 | } 127 | -------------------------------------------------------------------------------- /kernel/kernel/ATA/ata_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | 12 | struct ata_device { 13 | uint16_t data; 14 | union { 15 | uint16_t error; 16 | uint16_t feature; 17 | }; 18 | uint16_t sector_count; 19 | 20 | union { 21 | uint16_t sector_num; 22 | uint16_t lba_low; 23 | }; 24 | union { 25 | uint16_t cylinder_low; 26 | uint16_t lba_mid; 27 | }; 28 | union { 29 | uint16_t cylinder_high; 30 | uint16_t lba_high; 31 | }; 32 | union { 33 | uint16_t drive; 34 | uint16_t head; 35 | }; 36 | union { 37 | uint16_t status; 38 | uint16_t command; 39 | }; 40 | 41 | // Below is based on offset from Control base. 42 | union { 43 | uint16_t alternate_status; 44 | uint16_t device_control; 45 | }; 46 | uint16_t device_address; 47 | 48 | bool slave; 49 | bool primary; 50 | bool enabled; 51 | }; 52 | 53 | struct ata_driver { 54 | struct ata_device primary_master; 55 | struct ata_device primary_slave; 56 | struct ata_device secondary_master; 57 | struct ata_device secondary_slave; 58 | }; 59 | 60 | 61 | bool ata_driver_init(struct ata_driver* driver); 62 | bool ata_device_init(struct ata_device* device, bool primary, bool slave); 63 | 64 | -------------------------------------------------------------------------------- /kernel/kernel/mem/higher_half_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define KERNEL_OFFSET 0xC0000000 4 | #define KERNEL_START 0x00100000 //0x10000 5 | #define V2P(a) (((uint32_t)(a)) - KERNEL_OFFSET) 6 | #define P2V(a) (((uint32_t)(a)) + KERNEL_OFFSET) 7 | 8 | -------------------------------------------------------------------------------- /kernel/kernel/mem/initialize_kernel_memory.c: -------------------------------------------------------------------------------- 1 | #include "initialize_kernel_memory.h" 2 | 3 | 4 | bool initialize_kernel_memory(void) { 5 | //TODO: reserve the space used by the kernel itself (for both the physical and virtual memory allocators) 6 | if(!global_phys_allocator_init()) { 7 | serial_writestring("Failed to initialize global physical memory allocator\n"); 8 | return false; 9 | } 10 | serial_writestring("Initialized global physical memory allocator\n"); 11 | if(!kernel_virt_allocator_init()) { //TODO: reserve the max amount of kernel space in the virtual memory allocator 12 | serial_writestring("Failed to initialize kernel virtual memory allocator\n"); 13 | return false; 14 | } 15 | serial_writestring("Initialized kernel virtual memory allocator\n"); 16 | 17 | if(!paging_init()) { 18 | serial_writestring("Failed to initialize paging\n"); 19 | return false; 20 | } 21 | serial_writestring("Initialized paging\n"); 22 | 23 | return true; 24 | } 25 | -------------------------------------------------------------------------------- /kernel/kernel/mem/initialize_kernel_memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | bool initialize_kernel_memory(void); 12 | -------------------------------------------------------------------------------- /kernel/kernel/mem/mem_constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | //in bytes 7 | #define PAGE_SIZE 4096u 8 | 9 | 10 | #define ADD_TWO_PTRS(ptr1, ptr2) (void*)(((uint32_t)(ptr1))+((uint32_t)(ptr2))) 11 | #define SUB_TWO_PTRS(ptr1, ptr2) (void*)(((uint32_t)(ptr1))-((uint32_t)(ptr2))) 12 | 13 | 14 | #define NUMBER_OF_PAGES (0x100000000u/PAGE_SIZE) // equals 1048576 15 | 16 | // 3GiB User/ 1GiB Kernel 17 | #define KERNEL_PAGES (NUMBER_OF_PAGES/4) 18 | 19 | //in pages 20 | #define MAX_ACPICA_SIZE 1024 21 | 22 | // 1/4 GiB in pages 23 | #define MAX_KERNEL_HEAP_SIZE 0x10000 24 | 25 | // 0 --- (MAX_KERNEL_HEAP_SIZE-1), MAX_KERNEL_HEAP_SIZE --- (MAX_KERNEL_HEAP_SIZE*2-1), (MAX_KERNEL_HEAP_SIZE*2) --- (MAX_KERNEL_HEAP_SIZE*3-1), (MAX_KERNEL_HEAP_SIZE*3) --- (MAX_KERNEL_HEAP_SIZE*4-1) 26 | #define HEAP_START_ADDR (P2V(MAX_KERNEL_HEAP_SIZE*3)) 27 | //#define HEAP_START_ADDR 0xC0030000 28 | -------------------------------------------------------------------------------- /kernel/kernel/mem/paging/enable_paging.s: -------------------------------------------------------------------------------- 1 | section .text 2 | global load_page_directory 3 | load_page_directory: 4 | push eax 5 | mov eax, [esp + 8] 6 | mov cr3, eax 7 | pop eax 8 | ret 9 | 10 | 11 | global get_current_cr3 12 | get_current_cr3: 13 | mov eax, cr3 14 | ret 15 | 16 | 17 | global enable_paging 18 | enable_paging: 19 | push eax 20 | mov eax, cr0 21 | or eax, 80000000h 22 | mov cr0, eax 23 | pop eax 24 | ret 25 | 26 | 27 | global enable_ring0_write_protect 28 | enable_ring0_write_protect: 29 | push eax 30 | mov eax, cr0 31 | or eax, 10000h 32 | mov cr0, eax 33 | pop eax 34 | ret 35 | -------------------------------------------------------------------------------- /kernel/kernel/mem/paging/paging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "mem_constants.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | // Page Table Entry flags 20 | enum page_table_entry_flags { 21 | PT_PRESENT = (1<<0), 22 | PT_RW = (1<<1), 23 | PT_USER = (1<<2), 24 | PT_WRITETHROUGH = (1<<3) 25 | }; 26 | 27 | // Page Directory Entry flags 28 | enum page_directory_entry_flags { 29 | PD_PRESENT = (1<<0), 30 | PD_RW = (1<<1), 31 | PD_USER = (1<<2), 32 | PD_WRITETHROUGH = (1<<3), 33 | PD_DISABLECACHE = (1<<4) 34 | }; 35 | 36 | // Page Fault error flags 37 | enum page_fault_error_flags { 38 | PF_PRESENT = (1<<0), // Was the page present? 39 | PF_RW = (1<<1), // Was the page wrongfully written to? 40 | PF_USER = (1<<2), // Was the CPU in user-mode? 41 | PF_RESERVED = (1<<3), // Were the CPU-reserved bytes overwritten? 42 | PF_ID = (1<<4) // Was the fault caused by an instruction fetch? 43 | }; 44 | 45 | #define PAGE_BITMASK 0xFFFFF000 46 | 47 | 48 | bool paging_init(void); 49 | 50 | void load_and_turn_on_paging(void); 51 | 52 | uint32_t get_physical_address_in_boot(const void* virtual_address); 53 | uint32_t get_physical_address(uint32_t page_directory, const void* virtual_address); 54 | uint32_t get_physical_address_in_kernel_addr(const void* virtual_address); 55 | uint32_t get_physical_address_in_current_addr(const void* virtual_address); 56 | 57 | bool is_readable(uint32_t page_directory, const void* virtual_address); //checks if it is in the paging structure 58 | bool is_readable_in_kernel_addr(const void* virtual_address); //checks if it is in the kernel address space 59 | bool is_readable_in_current_addr(const void* virtual_address); 60 | bool is_writable(uint32_t page_directory, const void* virtual_address); //checks if it is in the paging structure and if the RW flag is set 61 | bool is_writable_in_kernel_addr(const void* virtual_address); //checks if it is in the kernel address space and if the RW flag is set 62 | bool is_writable_in_current_addr(const void* virtual_address); 63 | 64 | 65 | bool identity_map_page(uint32_t page_directory, uint32_t address, uint32_t pt_flags, uint32_t pd_flags); 66 | bool identity_map_pages(uint32_t page_directory, uint32_t address, uint32_t num_of_pages, uint32_t pt_flags, uint32_t pd_flags); 67 | bool identity_map_page_in_kernel_addr(uint32_t address, uint32_t pt_flags, uint32_t pd_flags); 68 | bool identity_map_pages_in_kernel_addr(uint32_t address, uint32_t num_of_pages, uint32_t pt_flags, uint32_t pd_flags); 69 | bool identity_map_page_in_current_addr(uint32_t address, uint32_t pt_flags, uint32_t pd_flags); 70 | bool identity_map_pages_in_current_addr(uint32_t address, uint32_t num_of_pages, uint32_t pt_flags, uint32_t pd_flags); 71 | 72 | void* map_to_arbitrary_kernel_virt_page_in_current_addr(uint32_t phys_addr, uint32_t page_index_in_table); 73 | void* map_to_arbitrary_kernel_virt_pages_in_current_addr(uint32_t phys_addr, uint32_t page_index_in_table, uint32_t size); // `size` is number of pages 74 | 75 | bool unmap_arbitrary_kernel_virt_page_in_current_addr(uint32_t page_index_in_table); 76 | bool unmap_arbitrary_kernel_virt_pages_in_current_addr(uint32_t page_index_in_table, uint32_t size); // `size` is number of pages 77 | 78 | bool map_page(uint32_t page_directory, void* virtual_address, uint32_t phys_frame, uint32_t pt_flags, uint32_t pd_flags); 79 | bool map_pages(uint32_t page_directory, void* virtual_address, uint32_t phys_frame, size_t num_of_pages, uint32_t pt_flags, uint32_t pd_flags); 80 | bool map_page_in_kernel_addr(void* virtual_address, uint32_t phys_frame, uint32_t pt_flags, uint32_t pd_flags); 81 | bool map_pages_in_kernel_addr(void* virtual_address, uint32_t phys_frame, size_t num_of_pages, uint32_t pt_flags, uint32_t pd_flags); 82 | bool map_page_in_current_addr(void* virtual_address, uint32_t phys_frame, uint32_t pt_flags, uint32_t pd_flags); 83 | bool map_pages_in_current_addr(void* virtual_address, uint32_t phys_frame, size_t num_of_pages, uint32_t pt_flags, uint32_t pd_flags); 84 | 85 | uint32_t unmap_page(uint32_t page_directory, const void* virtual_address); 86 | uint32_t unmap_pages(uint32_t page_directory, const void* virtual_address, size_t num_of_pages); 87 | uint32_t unmap_page_in_kernel_addr(const void* virtual_address); 88 | uint32_t unmap_pages_in_kernel_addr(const void* virtual_address, size_t num_of_pages); 89 | uint32_t unmap_page_in_current_addr(const void* virtual_address); 90 | uint32_t unmap_pages_in_current_addr(const void* virtual_address, size_t num_of_pages); 91 | 92 | 93 | inline uint32_t return_page_address(const uint32_t address) { 94 | return address & 0xFFFFF000u; 95 | } 96 | inline uint32_t return_page_offset(const uint32_t address) { 97 | return address & 0x00000FFFu; 98 | } 99 | inline uint32_t get_rounded_up_num_of_pages(const uint32_t address) { 100 | return ((address / PAGE_SIZE) + ((address % PAGE_SIZE) > 0u)); 101 | } 102 | 103 | void map_kernel_inside_user(struct process_t* process); 104 | void clear_physical_page(size_t physical); 105 | bool user_map(struct process_t* process, size_t virt, size_t physical); 106 | bool user_map_pages(struct process_t* process, size_t virt, size_t physical, size_t pages); 107 | 108 | 109 | extern uintptr_t get_current_cr3(void); // returns currently loaded page directory phys addr 110 | extern void set_cr3(uint32_t* new_page_directory_phys_addr); 111 | uint32_t* get_kernel_page_directory(void); 112 | void set_current_page_directory(uint32_t* new_current_page_directory); 113 | uint32_t get_current_page_directory(void); // returns virtual address of current paging subsytem page directory (in kernel space) 114 | uint32_t get_current_page_directory_phys_addr(void); // returns physical address of current paging subsytem page directory 115 | -------------------------------------------------------------------------------- /kernel/kernel/mem/phys/global_phys_allocator.c: -------------------------------------------------------------------------------- 1 | #include "global_phys_allocator.h" 2 | 3 | 4 | struct global_phys_allocator { 5 | uint32_t pages_1024[32]; // in 4MiB blocks 6 | uint32_t pages_512[64]; 7 | uint32_t pages_256[128]; 8 | uint32_t pages_128[256]; 9 | uint32_t pages_64[512]; 10 | uint32_t pages_32[1024]; 11 | uint32_t pages_16[2048]; 12 | uint32_t oct_pages[4096]; 13 | uint32_t quad_pages[8192]; 14 | uint32_t double_pages[16384]; 15 | uint32_t pages[32768]; // in individual pages 16 | }; 17 | 18 | static struct global_phys_allocator global_phys_allocator; 19 | 20 | 21 | bool global_phys_allocator_init(void) { 22 | const bool ret0 = binary_buddy_memory_allocator_init(&global_phys_allocator, sizeof(struct global_phys_allocator)); 23 | serial_writestring("after binary_buddy_memory_allocator_init\n"); 24 | if(!ret0) { 25 | return false; 26 | } 27 | 28 | const uint32_t val = ((V2P(get_endkernel())/PAGE_SIZE) + ((V2P(get_endkernel())%PAGE_SIZE)>0u)); 29 | kprintf("((V2P(get_endkernel())/PAGE_SIZE) + ((V2P(get_endkernel()) PAGE_SIZE)>0u)): %u\n", val); 30 | 31 | const bool ret1 = binary_buddy_memory_allocator_reserve(&global_phys_allocator, 0, ((V2P(get_endkernel())/PAGE_SIZE) + ((V2P(get_endkernel())%PAGE_SIZE)>0u)), 32768, 0, 11); 32 | serial_writestring("after binary_buddy_memory_allocator_reserve\n"); 33 | 34 | return ret1; 35 | } 36 | 37 | void* global_phys_allocator_allocate_page(void) { 38 | return global_phys_allocator_allocate_pages(1); 39 | } 40 | void* global_phys_allocator_allocate_pages(const size_t num_of_pages) { 41 | return binary_buddy_memory_allocator_allocate(&global_phys_allocator, PAGE_SIZE, 32768, 11, num_of_pages); 42 | } 43 | 44 | bool global_phys_allocator_free_page(void *const page_phys_addr) { 45 | return global_phys_allocator_free_pages(page_phys_addr, 1); 46 | } 47 | bool global_phys_allocator_free_pages(void *const page_phys_addr, const size_t num_of_pages) { 48 | return binary_buddy_memory_allocator_free(&global_phys_allocator, PAGE_SIZE, 32768, 11, page_phys_addr, num_of_pages); 49 | } 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | //TODO: move to more apprioriate file 70 | 71 | //The address of this variable is set in the linker script. It has the ending address of the kernel. 72 | //We just need it for the address, it stores no value. 73 | extern uint32_t immutable_data_start; 74 | extern uint32_t text_start; 75 | extern uint32_t text_end; 76 | extern uint32_t rodata_start; 77 | extern uint32_t rodata_end; 78 | extern uint32_t immutable_data_end; 79 | extern uint32_t mutable_data_start; 80 | extern uint32_t data_start; 81 | extern uint32_t data_end; 82 | extern uint32_t bss_start; 83 | extern uint32_t bss_end; 84 | extern uint32_t mutable_data_end; 85 | extern uint32_t endkernel; 86 | 87 | uint32_t get_immutable_data_start(void) { 88 | return (uint32_t)&immutable_data_start; 89 | } 90 | uint32_t get_text_start(void) { 91 | return (uint32_t)&text_start; 92 | } 93 | uint32_t get_text_end(void) { 94 | return (uint32_t)&text_end; 95 | } 96 | uint32_t get_rodata_start(void) { 97 | return (uint32_t)&rodata_start; 98 | } 99 | uint32_t get_rodata_end(void) { 100 | return (uint32_t)&rodata_end; 101 | } 102 | uint32_t get_immutable_data_end(void) { 103 | return (uint32_t)&immutable_data_end; 104 | } 105 | uint32_t get_mutable_data_start(void) { 106 | return (uint32_t)&mutable_data_start; 107 | } 108 | uint32_t get_data_start(void) { 109 | return (uint32_t)&data_start; 110 | } 111 | uint32_t get_data_end(void) { 112 | return (uint32_t)&data_end; 113 | } 114 | uint32_t get_bss_start(void) { 115 | return (uint32_t)&bss_start; 116 | } 117 | uint32_t get_bss_end(void) { 118 | return (uint32_t)&bss_end; 119 | } 120 | uint32_t get_mutable_data_end(void) { 121 | return (uint32_t)&mutable_data_end; 122 | } 123 | uint32_t get_endkernel(void) { 124 | return (uint32_t)&endkernel; 125 | } 126 | -------------------------------------------------------------------------------- /kernel/kernel/mem/phys/global_phys_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #define GLOBAL_PHYS_MEM_SIZE 0x100000000u // 4GiB in bytes 15 | 16 | 17 | bool global_phys_allocator_init(void); 18 | void* global_phys_allocator_allocate_page(void); 19 | void* global_phys_allocator_allocate_pages(size_t num_of_pages); 20 | bool global_phys_allocator_free_page(void* page_phys_addr); 21 | bool global_phys_allocator_free_pages(void* page_phys_addr, size_t num_of_pages); 22 | 23 | 24 | uint32_t get_immutable_data_start(void); 25 | uint32_t get_text_start(void); 26 | uint32_t get_text_end(void); 27 | uint32_t get_rodata_start(void); 28 | uint32_t get_rodata_end(void); 29 | uint32_t get_immutable_data_end(void); 30 | uint32_t get_mutable_data_start(void); 31 | uint32_t get_data_start(void); 32 | uint32_t get_data_end(void); 33 | uint32_t get_bss_start(void); 34 | uint32_t get_bss_end(void); 35 | uint32_t get_mutable_data_end(void); 36 | uint32_t get_endkernel(void); 37 | -------------------------------------------------------------------------------- /kernel/kernel/mem/virt/heap_virt_mem_allocator.c: -------------------------------------------------------------------------------- 1 | #include "heap_virt_mem_allocator.h" 2 | 3 | 4 | static uint32_t num_of_pages_allocated = 0u; 5 | 6 | void* kernel_virt_mem_allocate_page(void) { 7 | return kernel_virt_mem_allocate_pages(1u); 8 | } 9 | void* kernel_virt_mem_allocate_pages(const size_t num_of_pages) { 10 | if(num_of_pages_allocated+num_of_pages > MAX_KERNEL_HEAP_SIZE) { 11 | return NULL; 12 | } 13 | 14 | void *const page_virt_addr = ADD_TWO_PTRS(HEAP_START_ADDR, num_of_pages_allocated*PAGE_SIZE); 15 | 16 | num_of_pages_allocated += num_of_pages; 17 | 18 | return page_virt_addr; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /kernel/kernel/mem/virt/heap_virt_mem_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | void* kernel_virt_mem_allocate_page(void); 12 | void* kernel_virt_mem_allocate_pages(size_t num_of_pages); 13 | 14 | -------------------------------------------------------------------------------- /kernel/kernel/mem/virt/kernel_virt_allocator.c: -------------------------------------------------------------------------------- 1 | #include "kernel_virt_allocator.h" 2 | 3 | 4 | struct kernel_virt_allocator { // owns 1GiB of the address space (the upper GiB) 5 | uint32_t pages_256[32]; 6 | uint32_t pages_128[64]; 7 | uint32_t pages_64[128]; 8 | uint32_t pages_32[256]; 9 | uint32_t pages_16[512]; 10 | uint32_t oct_pages[1024]; 11 | uint32_t quad_pages[2048]; 12 | uint32_t double_pages[4096]; 13 | uint32_t pages[8192]; // in individual pages 14 | }; 15 | 16 | static struct kernel_virt_allocator kernel_virt_allocator; 17 | 18 | 19 | bool kernel_virt_allocator_init(void) { 20 | const bool ret0 = binary_buddy_memory_allocator_init(&kernel_virt_allocator, sizeof(struct kernel_virt_allocator)); 21 | if(!ret0) { 22 | return false; 23 | } 24 | 25 | const uint32_t val = ((V2P(get_endkernel())/PAGE_SIZE) + ((V2P(get_endkernel())%PAGE_SIZE)>0u)); 26 | kprintf("((V2P(get_endkernel())/PAGE_SIZE) + ((V2P(get_endkernel()) PAGE_SIZE)>0u)): %u\n", val); 27 | 28 | //TODO: double check the -1u later in the end_index param 29 | const bool ret1 = binary_buddy_memory_allocator_reserve(&kernel_virt_allocator, 0, ((V2P(get_endkernel())/PAGE_SIZE) + ((V2P(get_endkernel())%PAGE_SIZE)>0u))-1u, 8192, 0, 9); 30 | if(!ret1) { 31 | return false; 32 | } 33 | kprintf("Reserved %u pages for kernel\n", val); 34 | 35 | // 0 --- 7, 8 --- 15, 16 --- 23, 24 --- 31 36 | // 16 = start index, increments of `uint32_t`, do not allow indexes between 37 | // 23 = end index, increments of `uint32_t`, do not allow indexes between 38 | //32 = num of elements in `uint32_t`'s in the level 39 | // 8 = level of allocator index, 8 is the highest level, 0 is lowest 40 | // 9 = number of allocator levels 41 | const bool ret2 = binary_buddy_memory_allocator_reserve(&kernel_virt_allocator, 16, 23, 32, 8, 9); 42 | kprintf("Reserved %u pages for heap\n", val); 43 | return ret2; 44 | } 45 | 46 | bool kernel_virt_allocator_reserve_page(void *const page_virt_addr) { 47 | return kernel_virt_allocator_reserve_pages(page_virt_addr, 1); 48 | } 49 | bool kernel_virt_allocator_reserve_pages(void *const page_virt_addr, const size_t num_of_pages) { 50 | //TODO: double check the -1u later in the start_index and end_index params 51 | return binary_buddy_memory_allocator_reserve(&kernel_virt_allocator, ((uint32_t)V2P(page_virt_addr))/PAGE_SIZE-1u, (((uint32_t)V2P(page_virt_addr))/PAGE_SIZE-1u)+num_of_pages, 8192, 0, 9); 52 | } 53 | 54 | void* kernel_virt_allocator_allocate_page(void) { 55 | return kernel_virt_allocator_allocate_pages(1); 56 | } 57 | void* kernel_virt_allocator_allocate_pages(const size_t num_of_pages) { 58 | return (void*)P2V(binary_buddy_memory_allocator_allocate(&kernel_virt_allocator, PAGE_SIZE, 8192, 9, num_of_pages)); 59 | } 60 | 61 | bool kernel_virt_allocator_free_page(void *const page_virt_addr) { 62 | return kernel_virt_allocator_free_pages(page_virt_addr, 1); 63 | } 64 | bool kernel_virt_allocator_free_pages(void *const page_virt_addr, const size_t num_of_pages) { 65 | return binary_buddy_memory_allocator_free(&kernel_virt_allocator, PAGE_SIZE, 8192, 9, (void*)V2P(page_virt_addr), num_of_pages); 66 | } 67 | -------------------------------------------------------------------------------- /kernel/kernel/mem/virt/kernel_virt_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | bool kernel_virt_allocator_init(void); 15 | bool kernel_virt_allocator_reserve_page(void* page_virt_addr); 16 | bool kernel_virt_allocator_reserve_pages(void* page_virt_addr, size_t num_of_pages); 17 | void* kernel_virt_allocator_allocate_page(void); 18 | void* kernel_virt_allocator_allocate_pages(size_t num_of_pages); 19 | bool kernel_virt_allocator_free_page(void* page_virt_addr); 20 | bool kernel_virt_allocator_free_pages(void* page_virt_addr, size_t num_of_pages); 21 | -------------------------------------------------------------------------------- /kernel/kernel/mem/virt/osi_virt_mem_allocator.c: -------------------------------------------------------------------------------- 1 | #include "osi_virt_mem_allocator.h" 2 | 3 | 4 | #define MAX_ACPICA_SIZE_IN_UINT32 (MAX_ACPICA_SIZE/32) 5 | 6 | struct osi_buddy_memory_allocator { 7 | uint32_t quad_pages[MAX_ACPICA_SIZE_IN_UINT32/4]; 8 | uint32_t double_pages[MAX_ACPICA_SIZE_IN_UINT32/2]; 9 | uint32_t pages[MAX_ACPICA_SIZE_IN_UINT32]; // MAX_ACPICA_SIZE_IN_UINT32 is 32 10 | }; 11 | 12 | void* osi_virt_range_start; 13 | static struct osi_buddy_memory_allocator osi_buddy_memory_allocator; 14 | 15 | bool osi_virt_mem_allocator_init(void) { 16 | osi_virt_range_start = kernel_virt_allocator_allocate_pages(MAX_ACPICA_SIZE); 17 | if(osi_virt_range_start == NULL) { 18 | return false; 19 | } 20 | return kmemset(&osi_buddy_memory_allocator, 0, sizeof(struct osi_buddy_memory_allocator)) != NULL; 21 | } 22 | 23 | void* osi_virt_mem_allocator_allocate_page(void) { 24 | return osi_virt_mem_allocator_allocate_pages(1); 25 | } 26 | void* osi_virt_mem_allocator_allocate_pages(const size_t num_of_pages) { 27 | return ADD_TWO_PTRS(osi_virt_range_start, binary_buddy_memory_allocator_allocate(&osi_buddy_memory_allocator, PAGE_SIZE, MAX_ACPICA_SIZE, 3, num_of_pages)); 28 | } 29 | 30 | bool osi_virt_mem_allocator_free_page(void *const page_virt_addr) { 31 | return osi_virt_mem_allocator_free_pages(page_virt_addr, 1); 32 | } 33 | bool osi_virt_mem_allocator_free_pages(void *const page_virt_addr, const size_t num_of_pages) { 34 | return binary_buddy_memory_allocator_free(&osi_buddy_memory_allocator, PAGE_SIZE, MAX_ACPICA_SIZE, 3, SUB_TWO_PTRS(page_virt_addr, osi_virt_range_start), num_of_pages); 35 | } 36 | -------------------------------------------------------------------------------- /kernel/kernel/mem/virt/osi_virt_mem_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | bool osi_virt_mem_allocator_init(void); 13 | void* osi_virt_mem_allocator_allocate_page(void); 14 | void* osi_virt_mem_allocator_allocate_pages(size_t num_of_pages); 15 | bool osi_virt_mem_allocator_free_page(void* page_virt_addr); 16 | bool osi_virt_mem_allocator_free_pages(void* page_virt_addr, size_t num_of_pages); 17 | -------------------------------------------------------------------------------- /kernel/kernel/scheduler/process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | 14 | #define MAX_PRIORITY 4 15 | #define MIN_PRIORITY 1 16 | #define PRIORITY_LEVELS ((MAX_PRIORITY - MIN_PRIORITY) + 1) 17 | #define DEFAULT_PRIORITY 3 18 | 19 | typedef size_t pid_t; ///< A process id 20 | 21 | #define INVALID_PID (1024 * 1024 * 1024) //I'm pretty sure we won't violate this limit 22 | 23 | enum process_state { 24 | PROCESS_EMPTY = 0, ///< Not a process 25 | PROCESS_NEW = 1, ///< A newly created process 26 | PROCESS_READY = 2, ///< A process ready to run 27 | PROCESS_RUNNING = 3, ///< A process currently executing 28 | PROCESS_BLOCKED = 4, ///< A blocked process 29 | PROCESS_SLEEPING= 5, ///< A sleeping process 30 | PROCESS_WAITING = 6, ///< A waiting process (for a child) 31 | PROCESS_KILLED = 7, ///< A killed process 32 | PROCESS_BLOCKED_TIMEOUT = 8, ///< A blocked, with timeout, process 33 | PROCESS_ERROR = 9 /// < used for error return codes involving processes 34 | }; 35 | 36 | 37 | struct process_context { 38 | uint32_t ebx; 39 | uint32_t edx; 40 | uint32_t esi; 41 | uint32_t edi; 42 | uint32_t ebp; 43 | uint32_t eip; 44 | uint32_t esp; 45 | }; 46 | 47 | struct process_t { 48 | pid_t pid; ///< The process id 49 | //pid_t ppid; ///< The parent's process id 50 | 51 | bool system; ///< Indicates if the process is a system process 52 | 53 | size_t priority; ///< The priority of the process 54 | 55 | uint32_t physical_cr3; ///< The physical address of the CR3 56 | uint32_t virtual_cr3; ///< The virtual address of the CR3 in the kernel section of the address space 57 | 58 | uint32_t physical_stack; ///< The physical address of the kernel stack 59 | 60 | volatile struct process_context context; ///< A pointer to the context 61 | 62 | struct string name; ///< The name of the process 63 | }; 64 | 65 | struct process_control_t { 66 | struct process_t process; ///< The process itself 67 | enum process_state state; ///< The state of the process 68 | size_t rounds; ///< The number of rounds remaining 69 | size_t sleep_timeout; ///< The sleep timeout (in ticks) 70 | }; 71 | -------------------------------------------------------------------------------- /kernel/kernel/scheduler/scheduler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | 33 | #define MAX_PROCESS 128 34 | 35 | #define USER_STACK_TOP_ADDR 0xB0000000 36 | 37 | #define STACK_SIZE 4096 38 | 39 | 40 | /*! 41 | * \brief Indicates if the scheduler is started or not 42 | */ 43 | bool scheduler_is_started(void); 44 | 45 | /*! 46 | * \brief Return the id of the current process 47 | */ 48 | pid_t scheduler_get_pid(void); 49 | 50 | /*! 51 | * \brief Return the process with the given ID 52 | */ 53 | struct process_t* scheduler_get_process(pid_t pid); 54 | 55 | /*! 56 | * \brief Returns the state of the process with the given ID 57 | */ 58 | enum process_state scheduler_get_process_state(pid_t pid); 59 | 60 | /*! 61 | * \brief Block the given process and immediately reschedule it 62 | */ 63 | void scheduler_block_process(pid_t pid); 64 | 65 | /*! 66 | * \brief Unblock a blocked process 67 | */ 68 | void scheduler_unblock_process(pid_t pid); 69 | 70 | /*! 71 | * \brief Unblock a process if it is a blocked 72 | */ 73 | void scheduler_unblock_process_hint(pid_t pid); 74 | 75 | /*! 76 | * \brief Init the scheduler 77 | */ 78 | void scheduler_init(void); 79 | 80 | /*! 81 | * \brief Start the scheduler and starts the first process 82 | */ 83 | void scheduler_start(void) __attribute__((noreturn)); 84 | 85 | /*! 86 | * \brief Execute the given file in a new process 87 | */ 88 | GENERATE_OPTIONAL(pid_t) 89 | struct OPTIONAL_NAME(pid_t) scheduler_exec(struct string file, const vector_type(struct string) params); 90 | 91 | /*! 92 | * \brief Kill the current process 93 | */ 94 | void scheduler_kill_current_process(void) __attribute__((noreturn)); 95 | 96 | /*! 97 | * \brief Wait for the given process to terminate 98 | */ 99 | void scheduler_await_termination(pid_t pid); 100 | 101 | /*! 102 | * \brief Allocate more memory for the process 103 | * \param inc The amount of memory to add 104 | */ 105 | void scheduler_sbrk(size_t inc); 106 | 107 | /*! 108 | * \brief Let the scheduler know of a timer tick 109 | */ 110 | void scheduler_tick(void); 111 | 112 | /*! 113 | * \brief Let another process run. 114 | * 115 | * This may change the state of the current process state 116 | */ 117 | void scheduler_yield(void); 118 | 119 | /*! 120 | * \brief Reschedule to another process, if the current process is not running 121 | * 122 | * This will not change the state of the process! 123 | */ 124 | void scheduler_reschedule(void); 125 | 126 | /*! 127 | * \brief Indicates a fault in the current process 128 | */ 129 | void scheduler_fault(void); 130 | 131 | /*! 132 | * \brief Make the current process sleep for the given amount of milliseconds 133 | * \param time The number of milliseconds to wait 134 | */ 135 | void scheduler_sleep_ms(size_t time); 136 | 137 | /*! 138 | * \brief Make the given process sleep for the given amount of milliseconds 139 | * \param time The number of milliseconds to wait 140 | */ 141 | void scheduler_proc_sleep_ms(pid_t pid, size_t time); 142 | 143 | /*! 144 | * \brief Block the given process, but do not reschedule 145 | */ 146 | void scheduler_block_process_light(pid_t pid); 147 | 148 | /*! 149 | * \brief Block the given process, with a possible timeout, but do not reschedule 150 | */ 151 | void scheduler_block_process_timeout_light(pid_t pid, size_t ms); 152 | 153 | /*! 154 | * \brief Creat a kernel process 155 | * \param name The name of the process 156 | * \param user_stack Pointer to the user stack 157 | * \param kernel_stack Pointer to the kernel stack 158 | * \param fun The function to execute 159 | */ 160 | struct process_t* scheduler_create_kernel_task(const char* name, void (*fun)(void)); 161 | 162 | /*! 163 | * \brief Creat a kernel process with some data 164 | * \param name The name of the process 165 | * \param user_stack Pointer to the user stack 166 | * \param kernel_stack Pointer to the kernel stack 167 | * \param fun The function to execute 168 | * \param data The data to pass to the function 169 | */ 170 | struct process_t* scheduler_create_kernel_task_args(const char* name, void (*fun)(void), void* data); 171 | 172 | struct process_t* scheduler_load_process_in_new_address_space(const char* program_filename); // `program_filename` is the name of the ramdisk file to run 173 | 174 | /*! 175 | * \brief Queue a created system process 176 | */ 177 | void scheduler_queue_system_process(pid_t pid); 178 | 179 | /*! 180 | * \brief Queue an initilization task that will be run after the 181 | * scheduler is started 182 | * 183 | * This must be used for drivers that needs scheduling to be started 184 | * or for drivers depending on others drivers asynchronously 185 | * started. 186 | */ 187 | void scheduler_queue_async_init_task(void (*fun)(void)); 188 | 189 | /*! 190 | * \brief Lets the scheduler know that the timer frequency has been updated 191 | */ 192 | void scheduler_frequency_updated(uint64_t old_frequency, uint64_t new_frequency); 193 | 194 | -------------------------------------------------------------------------------- /kernel/kernel/scheduler/task_switch.s: -------------------------------------------------------------------------------- 1 | section .text 2 | 3 | global arch_save_context 4 | arch_save_context: 5 | mov [eax + (0 * 4)], ebx 6 | mov [eax + (1 * 4)], edx 7 | mov [eax + (2 * 4)], esi 8 | mov [eax + (3 * 4)], edi 9 | mov [eax + (4 * 4)], ebp 10 | mov ecx, [esp] 11 | mov [eax + (5 * 4)], ecx ; eip 12 | lea ecx, [esp+8] 13 | mov [eax + (6 * 4)], ecx ; esp 14 | xor ecx, ecx 15 | ret 16 | 17 | global arch_restore_context 18 | arch_restore_context: 19 | mov esp, [eax + (6 * 4)] 20 | mov ecx, [eax + (5 * 4)] ; load eip into ecx 21 | mov ebp, [eax + (4 * 4)] 22 | mov edi, [eax + (3 * 4)] 23 | mov esi, [eax + (2 * 4)] 24 | mov edx, [eax + (1 * 4)] 25 | mov ebx, [eax + (0 * 4)] 26 | jmp ecx 27 | 28 | 29 | global arch_enter_tasklet 30 | arch_enter_tasklet: 31 | pop eax 32 | pop ecx 33 | jmp ecx 34 | 35 | -------------------------------------------------------------------------------- /kernel/kernel/scheduler/timer.c: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | 3 | 4 | static volatile uint64_t _timer_ticks = 0; 5 | static volatile uint64_t _timer_seconds = 0; 6 | static volatile uint64_t _timer_milliseconds = 0; 7 | static uint64_t _timer_frequency = 0; 8 | 9 | static uint64_t (*_counter_fun)(void) = NULL; 10 | static uint64_t _counter_frequency = 0; 11 | 12 | static size_t pit_counter_var = 0; 13 | 14 | 15 | uint64_t pit_counter(void) { 16 | return pit_counter_var; 17 | } 18 | 19 | //TODO: replace __attribute__((interrupt)) as it is garbage 20 | __attribute__((interrupt)) static void timer_handler(struct interrupt_frame *const frame) { 21 | ++pit_counter_var; 22 | 23 | //NOTE: you CANNOT WRITE to VGA in a timer interrupt as this can cause a deadlock since spinlocks are used for synchronization and timer does not early return 24 | //kprintf("timer_handler()\n"); 25 | 26 | timer_tick(); 27 | 28 | //kprintf("after timer_tick()\n"); 29 | 30 | pic_send_eoi(1); 31 | } 32 | 33 | bool pit_counter_install(void) { 34 | uint64_t divisor = 1193180 / PIT_FREQUENCY; 35 | 36 | outb(0x43, 0x36); 37 | outb(0x40, (uint8_t)divisor); 38 | outb(0x40, (uint8_t)(divisor >> 8)); 39 | 40 | // Indicate the timer frequency 41 | timer_set_timer_frequency(PIT_FREQUENCY); 42 | 43 | pic_irq_enable(0); 44 | idt_register_handler(32, (uint32_t)timer_handler); 45 | 46 | // Let the timer know about the counter 47 | timer_counter_fun(pit_counter); 48 | timer_set_counter_frequency(PIT_FREQUENCY); 49 | 50 | return true; 51 | } 52 | 53 | void timer_install(void) { 54 | pit_counter_install(); 55 | } 56 | 57 | void scheduler_tick(void); // can't include scheduler.h because of circular include 58 | 59 | void timer_tick(void) { 60 | // Simply let the scheduler know about the tick 61 | scheduler_tick(); 62 | //kprintf("timer_tick end\n"); 63 | } 64 | 65 | uint64_t timer_seconds(void) { 66 | return timer_counter() / timer_get_counter_frequency(); 67 | } 68 | 69 | uint64_t timer_milliseconds(void) { 70 | return timer_counter() / (timer_get_counter_frequency() / 1000); 71 | } 72 | 73 | uint64_t timer_get_timer_frequency(void) { 74 | return _timer_frequency; 75 | } 76 | 77 | void timer_set_timer_frequency(uint64_t freq) { 78 | uint64_t old_frequency = _timer_frequency; 79 | 80 | _timer_frequency = freq; 81 | 82 | scheduler_frequency_updated(old_frequency, _timer_frequency); 83 | } 84 | 85 | uint64_t timer_counter(void) { 86 | return _counter_fun(); 87 | } 88 | 89 | uint64_t timer_get_counter_frequency(void) { 90 | return _counter_frequency; 91 | } 92 | 93 | void timer_set_counter_frequency(uint64_t freq) { 94 | _counter_frequency = freq; 95 | } 96 | 97 | void timer_counter_fun(uint64_t (*fun)(void)) { 98 | _counter_fun = fun; 99 | } 100 | -------------------------------------------------------------------------------- /kernel/kernel/scheduler/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | #define PIT_FREQUENCY 1000 12 | 13 | /*! 14 | * \brief Install the system timer 15 | */ 16 | void timer_install(void); 17 | 18 | /*! 19 | * \brief Returns a up-counter in seconds 20 | */ 21 | uint64_t timer_seconds(void); 22 | 23 | /*! 24 | * \brief Returns a up-counter in milliseconds 25 | */ 26 | uint64_t timer_milliseconds(void); 27 | 28 | /*! 29 | * \brief Let the timer know of a new tick 30 | */ 31 | void timer_tick(void); 32 | 33 | /*! 34 | * \brief Return the frequency in Hz of the current timer system. 35 | */ 36 | uint64_t timer_get_timer_frequency(void); 37 | 38 | /*! 39 | * \brief Sets the frequency in Hz of the current timer system. 40 | */ 41 | void timer_set_timer_frequency(uint64_t freq); 42 | 43 | /*! 44 | * \brief Returns a up-counter based on the counter frequency 45 | */ 46 | uint64_t timer_counter(void); 47 | 48 | /*! 49 | * \brief Return the frequency in Hz of the current counter system. 50 | */ 51 | uint64_t timer_get_counter_frequency(void); 52 | 53 | /*! 54 | * \brief Sets the frequency in Hz of the current counter system. 55 | */ 56 | void timer_set_counter_frequency(uint64_t freq); 57 | 58 | /*! 59 | * \brief Sets the function to use to get the counter value; 60 | */ 61 | void timer_counter_fun(uint64_t (*fun)(void)); 62 | -------------------------------------------------------------------------------- /kernel/kernel/subsystems/terminal/default_terminal_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | //TODO: consider making this user tweakable 14 | 15 | #define MAX_NUMBER_OF_ARGS 10 16 | #define MAX_ARGUMENT_SIZE 64 17 | 18 | struct default_terminal_context { 19 | size_t start_of_command; 20 | size_t end_of_command; 21 | const char* prompt_symbol; 22 | char command_arguments[MAX_NUMBER_OF_ARGS][MAX_ARGUMENT_SIZE]; 23 | 24 | struct vga_driver_context* vga_context; 25 | }; 26 | 27 | 28 | void default_init_context(struct default_terminal_context* terminal_context_ptr); 29 | 30 | void set_default_functions(void); 31 | 32 | void default_terminal_start(void* context); 33 | void default_terminal_end(void* context); 34 | void default_terminal_process_command(void* context); 35 | void default_terminal_shift(void* context); 36 | 37 | 38 | //utility functions that don't require a context 39 | //TODO: possibly put the context-less functions into their own header and source file 40 | int32_t get_char_location(const char* src, char c, size_t start, size_t end); 41 | void get_string_slice(const char* src, char* dest, size_t start, size_t end); 42 | void get_string_between_chars(const char* src, char* dest, char open, char close); 43 | int8_t get_string_section_after(const char* src, char* dest, const char* search_term); 44 | 45 | bool default_parse_command_args(void* context, const char* args); 46 | void default_run_command(void* context, char* command); 47 | void default_get_command(void* context, char* final, size_t number_of_elements); 48 | 49 | -------------------------------------------------------------------------------- /kernel/kernel/subsystems/terminal/default_terminal_system.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | static struct default_terminal_context terminal_context; 5 | 6 | 7 | void default_context_init_context(void) { 8 | default_init_context(&terminal_context); 9 | } 10 | 11 | void default_context_terminal_start(void) { 12 | kprintf("default_context_terminal_start\n"); 13 | run_terminal_start(&terminal_context); 14 | } 15 | void default_context_terminal_end(void) { 16 | run_terminal_end(&terminal_context); 17 | } 18 | void default_terminal_context_process_command(void) { 19 | run_terminal_process_command(&terminal_context); 20 | } 21 | void default_terminal_context_shift(void) { 22 | run_terminal_shift(&terminal_context); 23 | } 24 | 25 | 26 | void default_context_parse_command_args(const char *const args) { 27 | default_parse_command_args(&terminal_context, args); 28 | } 29 | void default_context_run_command(char *const command) { 30 | default_run_command(&terminal_context, command); 31 | } 32 | void default_context_get_command(char *const final, const size_t number_of_elements) { 33 | default_get_command(&terminal_context, final, number_of_elements); 34 | } 35 | 36 | 37 | struct default_terminal_context* get_default_terminal_context(void) { 38 | return &terminal_context; 39 | } 40 | -------------------------------------------------------------------------------- /kernel/kernel/subsystems/terminal/default_terminal_system.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "default_terminal_functions.h" 5 | 6 | 7 | void default_context_init_context(void); 8 | 9 | void default_context_terminal_start(void); 10 | void default_context_terminal_end(void); 11 | void default_terminal_context_process_command(void); 12 | void default_terminal_context_shift(void); 13 | 14 | 15 | void default_context_parse_command_args(const char* args); 16 | void default_context_run_command(char* command); 17 | void default_context_get_command(char* final, size_t number_of_elements); 18 | 19 | 20 | struct default_terminal_context* get_default_terminal_context(void); 21 | -------------------------------------------------------------------------------- /kernel/kernel/subsystems/terminal/keyboard_callbacks.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | bool is_turned_on = false; 5 | 6 | void catch_keycode(void *const context, struct GET_EVENT_TYPENAME(key_message) event) { 7 | kprintf("catch_keycode: %c\n", event.data.keycode); 8 | struct default_terminal_context *const terminal_context_ptr = (struct default_terminal_context*) context; 9 | 10 | if(event.event_type == KEYBOARD_EVENT) { 11 | if(event.data.key_type == NORMAL_KEY) { 12 | if(event.data.keycode == '\b') { 13 | terminal_backspace(terminal_context_ptr->vga_context); 14 | return; 15 | } else if(terminal_context_ptr->vga_context->terminal_column == 0) { 16 | default_init_context(terminal_context_ptr); 17 | 18 | terminal_writestring(terminal_context_ptr->vga_context, terminal_context_ptr->prompt_symbol); 19 | 20 | terminal_context_ptr->start_of_command += kstrlen(terminal_context_ptr->prompt_symbol); 21 | } 22 | 23 | if(event.data.keycode == '\t' && terminal_context_ptr->vga_context->terminal_row * 80 + terminal_context_ptr->vga_context->terminal_column >= terminal_context_ptr->start_of_command) { 24 | terminal_writestring(terminal_context_ptr->vga_context, " "); 25 | run_terminal_end(context); 26 | } else if(event.data.keycode == '\n') { 27 | run_terminal_end(context); 28 | terminal_putchar(terminal_context_ptr->vga_context, event.data.keycode); 29 | run_terminal_process_command(context); 30 | run_terminal_end(context); 31 | } else if(event.data.keycode > 0 && terminal_context_ptr->vga_context->terminal_row * 80 + terminal_context_ptr->vga_context->terminal_column >= terminal_context_ptr->start_of_command) { 32 | terminal_putchar(terminal_context_ptr->vga_context, event.data.keycode); 33 | run_terminal_end(context); 34 | } 35 | } 36 | else if(event.data.key_type == UP_ARROW) { 37 | terminal_cursor_up(terminal_context_ptr->vga_context); 38 | } 39 | else if(event.data.key_type == LEFT_ARROW) { 40 | terminal_cursor_left(terminal_context_ptr->vga_context); 41 | } 42 | else if(event.data.key_type == RIGHT_ARROW) { 43 | terminal_cursor_right(terminal_context_ptr->vga_context); 44 | } 45 | else if(event.data.key_type == DOWN_ARROW) { 46 | terminal_cursor_down(terminal_context_ptr->vga_context); 47 | } 48 | 49 | if(event.data.keycode == '1') { 50 | init_pit(1000, PIT_CHANNEL_0, ACCESS_MODE_LOBYTE_HIBYTE, PIT_MODE_SQUARE_WAVE_GENERATOR); 51 | } else if (event.data.keycode == '2') { 52 | init_pit(18, PIT_CHANNEL_0, ACCESS_MODE_LOBYTE_HIBYTE, PIT_MODE_SQUARE_WAVE_GENERATOR); 53 | } else if(event.data.keycode == '3') { 54 | is_turned_on = true; 55 | play_sound(1000); 56 | } else if(event.data.keycode == '4') { 57 | is_turned_on = true; 58 | play_sound(18); 59 | } else if(event.data.keycode == '5') { 60 | is_turned_on = true; 61 | play_sound(500); 62 | } else if(event.data.keycode == '6') { 63 | is_turned_on = false; 64 | no_sound(); 65 | restore_timer(); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /kernel/kernel/subsystems/terminal/keyboard_callbacks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | //for testing purposes only 18 | #include 19 | 20 | 21 | void catch_keycode(void* context, struct GET_EVENT_TYPENAME(key_message) event); 22 | 23 | -------------------------------------------------------------------------------- /kernel/kernel/subsystems/terminal/terminal_driver.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | 5 | static void (*terminal_start)(void*); 6 | static void (*terminal_end)(void*); 7 | static void (*terminal_process_command)(void*); 8 | static void (*terminal_shift)(void*); 9 | 10 | 11 | void set_terminal_start(void (*const new_terminal_start)(void*)) { 12 | terminal_start = new_terminal_start; 13 | } 14 | void set_terminal_end(void (*const new_terminal_end)(void*)) { 15 | terminal_end = new_terminal_end; 16 | } 17 | void set_terminal_process_command(void (*const new_terminal_process_command)(void*)) { 18 | terminal_process_command = new_terminal_process_command; 19 | } 20 | void set_terminal_shift(void (*const new_terminal_shift)(void*)) { 21 | terminal_shift = new_terminal_shift; 22 | } 23 | 24 | 25 | 26 | void run_terminal_start(void *const context) { 27 | kprintf("run_terminal_start\n"); 28 | terminal_start(context); 29 | } 30 | void run_terminal_end(void *const context) { 31 | terminal_end(context); 32 | } 33 | void run_terminal_process_command(void *const context) { 34 | terminal_process_command(context); 35 | } 36 | void run_terminal_shift(void *const context) { 37 | terminal_shift(context); 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /kernel/kernel/subsystems/terminal/terminal_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "kstdlib.h" 5 | 6 | 7 | void set_terminal_start(void (*new_terminal_start)(void*)); 8 | void set_terminal_end(void (*new_terminal_end)(void*)); 9 | void set_terminal_process_command(void (*new_terminal_process_command)(void*)); 10 | void set_terminal_shift(void (*new_terminal_shift)(void*)); 11 | 12 | 13 | void run_terminal_start(void* context); 14 | void run_terminal_end(void* context); 15 | void run_terminal_process_command(void* context); 16 | void run_terminal_shift(void* context); 17 | -------------------------------------------------------------------------------- /kernel/kernel/synchronization_primitives/int_lock.c: -------------------------------------------------------------------------------- 1 | #include "int_lock.h" 2 | 3 | 4 | void disable_hwint(size_t* rflags); 5 | void enable_hwint(size_t* rflags); 6 | 7 | 8 | void int_lock(struct int_lock* lock); 9 | void int_unlock(struct int_lock* lock); 10 | 11 | -------------------------------------------------------------------------------- /kernel/kernel/synchronization_primitives/int_lock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | inline void disable_hwint(size_t *const rflags) { 11 | asm volatile("pushf; pop %0; cli;" : "=g" (*rflags)); 12 | } 13 | 14 | inline void enable_hwint(size_t *const rflags) { 15 | asm volatile("push %0; popf; " :: "g" (*rflags)); 16 | } 17 | 18 | // interrupt lock, disables and enables interrupts, does *not* do memory synchronization 19 | struct int_lock { 20 | size_t rflags; 21 | }; 22 | 23 | inline void int_lock(struct int_lock *const lock) { 24 | disable_hwint(&lock->rflags); 25 | } 26 | inline void int_unlock(struct int_lock *const lock) { 27 | enable_hwint(&lock->rflags); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /kernel/kernel/synchronization_primitives/spinlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void acquire_spinlock(mutex_t *const mutex) { 4 | bool expected = false; 5 | while(!__atomic_compare_exchange_n(mutex, &expected, true, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 6 | __atomic_clear(&expected, __ATOMIC_RELAXED); 7 | asm volatile("pause"); 8 | } 9 | } 10 | 11 | void release_spinlock(mutex_t *const mutex) { 12 | __atomic_clear(mutex, __ATOMIC_RELEASE); 13 | } 14 | -------------------------------------------------------------------------------- /kernel/kernel/synchronization_primitives/spinlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | typedef volatile bool mutex_t; 7 | 8 | void acquire_spinlock(mutex_t* mutex); 9 | void release_spinlock(mutex_t* mutex); 10 | -------------------------------------------------------------------------------- /kernel/kernel/tar_fs/tar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kstring.h" 8 | #include "kstdio.h" 9 | #include "kassert.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #include "acpi.h" 15 | 16 | 17 | struct file_header { 18 | uint32_t size; //includes both the file and header, a value of `0` indicates the end of the file list 19 | char filename[100]; //null terminated 20 | char reserved[24]; //should just be zeroed out 21 | char file[]; 22 | }; 23 | 24 | 25 | typedef uint32_t Elf32_Addr; 26 | typedef uint16_t Elf32_Half; 27 | typedef uint32_t Elf32_Off; 28 | typedef int32_t Elf32_Sword; 29 | typedef uint32_t Elf32_Word; 30 | 31 | #define EI_NIDENT 16 32 | 33 | struct Elf32_Ehdr { 34 | unsigned char e_ident[EI_NIDENT]; 35 | Elf32_Half e_type; 36 | Elf32_Half e_machine; 37 | Elf32_Word e_version; 38 | Elf32_Addr e_entry; 39 | Elf32_Off e_phoff; 40 | Elf32_Off e_shoff; 41 | Elf32_Word e_flags; 42 | Elf32_Half e_ehsize; 43 | Elf32_Half e_phentsize; 44 | Elf32_Half e_phnum; 45 | Elf32_Half e_shentsize; 46 | Elf32_Half e_shnum; 47 | Elf32_Half e_shstrndx; 48 | }; 49 | 50 | enum Elf32_Type { 51 | ET_NONE = 0, 52 | ET_REL = 1, 53 | ET_EXEC = 2, 54 | ET_DYN = 3, 55 | ET_CORE = 4, 56 | ET_LOPROC = 0xFF00, 57 | ET_HIPROC = 0xFFFF, 58 | }; 59 | 60 | enum Elf32_Machine { 61 | EM_NONE = 0, 62 | EM_M32 = 1, 63 | EM_SPARC = 2, 64 | EM_386 = 3, 65 | EM_68K = 4, 66 | EM_88K = 5, 67 | EM_860 = 7, 68 | EM_MIPS = 8, 69 | }; 70 | 71 | enum Elf32_Version { 72 | EV_NONE = 0, 73 | EV_CURRENT = 1, 74 | }; 75 | 76 | enum Elf32_Identification_Index { 77 | EI_MAG0 = 0, 78 | EI_MAG1 = 1, 79 | EI_MAG2 = 2, 80 | EI_MAG3 = 3, 81 | EI_CLASS = 4, 82 | EI_DATA = 5, 83 | EI_VERSION = 6, 84 | EI_PAD = 7, 85 | }; 86 | 87 | #define ELFMAG0 0x7F 88 | #define ELFMAG1 'E' 89 | #define ELFMAG2 'L' 90 | #define ELFMAG3 'F' 91 | 92 | #define ELFCLASSNONE 0 93 | #define ELFCLASS32 1 94 | #define ELFCLASS64 2 95 | 96 | #define ELFDATANONE 0 97 | #define ELFDATA2LSB 1 98 | #define ELFDATA2MSB 2 99 | 100 | enum Elf32_Special_Section { 101 | SHN_UNDEF = 0, 102 | SHN_LORESERVE = 0xFF00, 103 | SHN_LOPROC = 0xFF00, 104 | SHN_HIPROC = 0xFF1F, 105 | SHN_ABS = 0xFFF1, 106 | SHN_COMMON = 0xFFF2, 107 | SHN_HIRESERVE = 0xFFFF, 108 | }; 109 | 110 | struct Elf32_Shdr { 111 | Elf32_Word sh_name; 112 | Elf32_Word sh_type; 113 | Elf32_Word sh_flags; 114 | Elf32_Addr sh_addr; 115 | Elf32_Off sh_offset; 116 | Elf32_Word sh_size; 117 | Elf32_Word sh_link; 118 | Elf32_Word sh_info; 119 | Elf32_Word sh_addralign; 120 | Elf32_Word sh_entsize; 121 | }; 122 | 123 | enum Elf32_Section_Type { 124 | SHT_NULL = 0, 125 | SHT_PROGBITS = 1, 126 | SHT_SYMTAB = 2, 127 | SHT_STRTAB = 3, 128 | SHT_RELA = 4, 129 | SHT_HASH = 5, 130 | SHT_DYNAMIC = 6, 131 | SHT_NOTE = 7, 132 | SHT_NOBITS = 8, 133 | SHT_REL = 9, 134 | SHT_SHLIB = 10, 135 | SHT_DYNSYM = 11, 136 | }; 137 | 138 | #define SHT_LOPROC 0x70000000u, 139 | #define SHT_HIPROC 0x7FFFFFFFu, 140 | #define SHT_LOUSER 0x80000000u, 141 | #define SHT_HIUSER 0xFFFFFFFFu, 142 | 143 | enum Elf32_Section_Attribute_Flags { 144 | SHF_WRITE = 0x1, 145 | SHF_ALLOC = 0x2, 146 | SHF_EXECINSTR = 0x4, 147 | }; 148 | 149 | #define SHF_MASKPROC 0xF0000000 150 | 151 | #define STN_UNDEF 0 152 | 153 | struct Elf32_Sym { 154 | Elf32_Word st_name; 155 | Elf32_Addr st_value; 156 | Elf32_Word st_size; 157 | unsigned char st_info; 158 | unsigned char st_other; 159 | Elf32_Half st_shndx; 160 | }; 161 | 162 | enum ELF32_ST_BIND { 163 | STB_LOCAL = 0, 164 | STB_GLOBAL = 1, 165 | STB_WEAK = 2, 166 | STB_LOPROC = 13, 167 | STB_HIPROC = 15, 168 | }; 169 | 170 | enum ELF32_ST_TYPE { 171 | STT_NOTYPE = 0, 172 | STT_OBJECT = 1, 173 | STT_FUNC = 2, 174 | STT_SECTION = 3, 175 | STT_FILE = 4, 176 | STT_LOPROC = 13, 177 | STT_HIPROC = 15, 178 | }; 179 | 180 | struct Elf32_Rel { 181 | Elf32_Addr r_offset; 182 | Elf32_Word r_info; 183 | }; 184 | 185 | struct Elf32_Rela { 186 | Elf32_Addr r_offset; 187 | Elf32_Word r_info; 188 | Elf32_Sword r_addend; 189 | }; 190 | 191 | #define ELF32_R_SYM(info) ((info) >> 8) 192 | #define ELF32_R_TYPE(info) ((unsigned char) (info)) 193 | #define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char) (type)) 194 | 195 | struct Elf32_Phdr { 196 | Elf32_Word p_type; 197 | Elf32_Off p_offset; 198 | Elf32_Addr p_vaddr; 199 | Elf32_Addr p_paddr; 200 | Elf32_Word p_filesz; 201 | Elf32_Word p_memsz; 202 | Elf32_Word p_flags; 203 | Elf32_Word p_align; 204 | }; 205 | 206 | enum Elf32_Program_Header_Type { 207 | PT_NULL = 0, 208 | PT_LOAD = 1, 209 | PT_DYNAMIC = 2, 210 | PT_INTERP = 3, 211 | PT_NOTE = 4, 212 | PT_SHLIB = 5, 213 | PT_PHDR = 6, 214 | }; 215 | 216 | #define PT_LOPROC 0x70000000, 217 | #define PT_HIPROC 0x7FFFFFFF, 218 | 219 | struct Elf32_Dyn { 220 | Elf32_Sword d_tag; 221 | union { 222 | Elf32_Word d_val; 223 | Elf32_Addr d_ptr; 224 | } d_un; 225 | }; 226 | 227 | extern struct Elf32_Dyn DYNAMIC[]; 228 | 229 | 230 | bool is_valid_elf_sig(struct Elf32_Ehdr* elf_header); 231 | void parse_headers(uint32_t address); 232 | 233 | GENERATE_OPTIONAL(uint32_t) 234 | struct OPTIONAL_NAME(uint32_t) parse_elf_file(const char* filename); 235 | 236 | struct file_header* get_file_header_from_list(const char* filename, struct file_header *const * file_list, uint8_t file_list_len); 237 | struct file_header* get_file_header(const char* filename); 238 | void print_file(const char* filename); 239 | void print_elf_file(const char* filename); 240 | 241 | 242 | 243 | bool load_elf_file_in_process(struct process_t* process, const char* filename); 244 | -------------------------------------------------------------------------------- /kernel/kernel/utils/algorithms/comparison.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define min(a,b) ((a)<(b)?(a):(b)) 4 | #define max(a,b) ((a)>(b)?(a):(b)) 5 | -------------------------------------------------------------------------------- /kernel/kernel/utils/algorithms/sort/quicksort.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | static uint32_t partition_array(uint32_t *const array, const uint32_t lo_index, const uint32_t hi_index) { 5 | const uint32_t pivot = array[hi_index]; 6 | uint32_t i = lo_index - 1u; 7 | for(uint32_t j = lo_index; j < hi_index; j++) { 8 | if(array[j] <= pivot) { 9 | ++i; 10 | swap(&array[i], &array[j], sizeof(uint32_t)); 11 | } 12 | } 13 | ++i; 14 | swap(&array[i], &array[hi_index], sizeof(uint32_t)); 15 | return i; 16 | } 17 | void quicksort_array(uint32_t *const array, const uint32_t lo_index, const uint32_t hi_index) { 18 | if(lo_index >= hi_index) { 19 | return; 20 | } 21 | const uint32_t p = partition_array(array, lo_index, hi_index); 22 | quicksort_array(array, lo_index, p-1u); 23 | quicksort_array(array, p+1u, hi_index); 24 | } 25 | -------------------------------------------------------------------------------- /kernel/kernel/utils/algorithms/sort/quicksort.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | //TODO: implement these two interfaces and remove the current one 11 | //void kqsort(void* ptr, size_t count, size_t size, int (*comp)(const void*, const void*)); 12 | //void kqsort_range(void* ptr, uint32_t lo_index, uint32_t hi_index, size_t size, int (*comp)(const void*, const void*)); 13 | 14 | void quicksort_array(uint32_t* array, uint32_t lo_index, uint32_t hi_index); 15 | -------------------------------------------------------------------------------- /kernel/kernel/utils/algorithms/swap.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void swap(void* a, void* b, size_t size); 4 | -------------------------------------------------------------------------------- /kernel/kernel/utils/algorithms/swap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | inline void swap(void *const a, void *const b, const size_t size) { 7 | char *const a_ptr = a; 8 | char *const b_ptr = b; 9 | for(size_t i = 0u; i < size; ++i) { 10 | const char tmp = a_ptr[i]; 11 | a_ptr[i] = b_ptr[i]; 12 | b_ptr[i] = tmp; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /kernel/kernel/utils/allocators/bitmap/bitmap_allocator.c: -------------------------------------------------------------------------------- 1 | #include "bitmap_allocator.h" 2 | 3 | 4 | void bitmap_allocator_init(uint32_t *const bitset, const uint32_t n, int32_t *const bitset_cache, const uint32_t cache_n, bool *const has_filled_bitset_cache) { 5 | kmemset(bitset, 0u, n/32 * sizeof(uint32_t)); 6 | *has_filled_bitset_cache = false; 7 | for(int32_t i = 0; i < cache_n; i++) { 8 | bitset_cache[i] = -1; 9 | } 10 | } 11 | 12 | static int32_t allocate_impl(uint32_t *const bookkeeping_bitset, const size_t number_of_entries, int32_t *const bitset_cache, const uint32_t num_of_cache_entries, bool *const has_searched_cache) { 13 | for(int32_t i = 0; i < num_of_cache_entries; ++i) { 14 | const int32_t current_entry = bitset_cache[i]; 15 | if(current_entry != -1) { 16 | bitset_cache[i] = -1; 17 | bookkeeping_bitset[current_entry/32] |= 1u << (current_entry%32); 18 | *has_searched_cache = false; 19 | //kprintf("allocated index: %i\n", current_entry); 20 | return current_entry; 21 | } 22 | } 23 | 24 | 25 | //we have already tried to allocate entries and failed 26 | if(*has_searched_cache) { 27 | *has_searched_cache = false; //we will try to allocate next time this function is called 28 | return -1; 29 | } 30 | 31 | //bitset table cache is empty, must do expensive allocation: 32 | for(uint32_t i = 0u, number_of_free_entries = 0u; i < number_of_entries && number_of_free_entries < num_of_cache_entries; ++i) { 33 | const uint32_t current_entries = bookkeeping_bitset[i]; 34 | //at least one bit is 0 35 | if(current_entries != 0xFFFFFFFF) { 36 | for(uint8_t j = 0u; j < 32u && number_of_free_entries < num_of_cache_entries; ++j) { 37 | if(!bitset_at((i*32u)+j, bookkeeping_bitset)) { 38 | bitset_cache[number_of_free_entries++] = (int32_t) ((i*32u)+j); 39 | } 40 | } 41 | } 42 | } 43 | //we store this to be able to detect if we are out of memory 44 | *has_searched_cache = true; //it might not have filled the bitset cache if there is no free memory or not enough freed memory 45 | 46 | 47 | return allocate_impl(bookkeeping_bitset, number_of_entries, bitset_cache, num_of_cache_entries, has_searched_cache); //grabs the first entry from bitset_cache and triggers the early return. 48 | } 49 | 50 | uint32_t bitmap_allocate(uint32_t *const bitset, const uint32_t n, int32_t *const bitset_cache, const uint32_t cache_n, bool *const has_filled_bitset_cache) { 51 | const int32_t allocated_page = allocate_impl(bitset, n, bitset_cache, cache_n, has_filled_bitset_cache); 52 | //TODO: don't use signed integers at all. This -1 to 0 conversion is also broken for other reasons. 53 | return (allocated_page == -1) ? 0u : allocated_page; //turn -1 into NULL 54 | } 55 | 56 | void bitmap_free(uint32_t *const bitset, const uint32_t n, const uint32_t index) { 57 | if(n*sizeof(uint32_t) > index) { //make sure we don't index out of bounds 58 | bitset_set_at(index, bitset, 0u); 59 | } 60 | } 61 | 62 | 63 | 64 | uint32_t bitmap_find_first_zero_bit(uint32_t *const bitset, const uint32_t n) { 65 | for(uint32_t i = 0u; i < n; ++i) { 66 | const uint32_t current_entries = bitset[i]; 67 | //at least one bit is 0 68 | if(current_entries != 0xFFFFFFFF) { 69 | for(uint8_t j = 0u; j < 32u; ++j) { 70 | if(!bitset_at((i*32u)+j, bitset)) { 71 | return ((i*32u)+j); 72 | } 73 | } 74 | } 75 | } 76 | return n; 77 | } 78 | -------------------------------------------------------------------------------- /kernel/kernel/utils/allocators/bitmap/bitmap_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | //TODO: consider whether or not to have a `;` on the end of the struct declaration **inside** of the macro 12 | #define GENERATE_BITMAP(NAMESPACE, N, ALIGNMENT) \ 13 | struct NAMESPACE##_bitmap_allocator { \ 14 | uint32_t bitset[N/32u] __attribute__((aligned(ALIGNMENT))); \ 15 | bool has_filled_bitset_cache; \ 16 | int32_t bitset_cache[20u]; \ 17 | }; 18 | 19 | //TODO: consider whether or not to put `struct` **inside** of the macro 20 | #define BITMAP_TYPENAME(NAMESPACE) NAMESPACE##_bitmap_allocator 21 | 22 | 23 | void bitmap_allocator_init(uint32_t* bitset, uint32_t n, int32_t* bitset_cache, uint32_t cache_n, bool* has_filled_bitset_cache); 24 | //returns index into bitmap allocator 25 | uint32_t bitmap_allocate(uint32_t* bitset, uint32_t n, int32_t* bitset_cache, uint32_t cache_n, bool* has_filled_bitset_cache); 26 | void bitmap_free(uint32_t* bitset, uint32_t n, uint32_t index); 27 | 28 | 29 | //returns index just like `bitmap_allocate` 30 | uint32_t bitmap_find_first_zero_bit(uint32_t* bitset, uint32_t n); 31 | -------------------------------------------------------------------------------- /kernel/kernel/utils/allocators/buddy/buddy_memory_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | bool binary_buddy_memory_allocator_init(uint32_t* allocator, size_t allocator_type_size); 12 | // `num_of_lowest_order_blocks` is the number of bits for the entry for the lowest size memory blocks 13 | /* expected layout of `allocator` type: 14 | struct alloc { 15 | uint32_t highest_mem_size[num_of_lowest_mem_size_in_allocator/4]; // index 2 16 | uint32_t medium_mem_size[num_of_lowest_mem_size_in_allocator/2]; // index 1 17 | uint32_t lowest_mem_size[num_of_lowest_mem_size_in_allocator]; // index 0 18 | }; 19 | */ 20 | bool binary_buddy_memory_allocator_reserve(uint32_t* allocator, uint32_t start_index, uint32_t end_index, const uint32_t num_of_elements_in_level, uint32_t level_in_allocator, uint32_t number_of_levels); 21 | void* binary_buddy_memory_allocator_allocate(uint32_t* allocator, uint32_t lowest_mem_size, uint32_t num_of_lowest_mem_size_in_allocator, uint32_t number_of_levels, uint32_t amount_to_allocate); // `amount_to_allocate` is in terms of `lowest_mem_size` 22 | bool binary_buddy_memory_allocator_free(uint32_t* allocator, uint32_t lowest_mem_size, uint32_t num_of_lowest_mem_size_in_allocator, uint32_t number_of_levels, void* address_to_free, uint32_t amount_to_free); // `amount_to_free` is in terms of `lowest_mem_size` 23 | 24 | -------------------------------------------------------------------------------- /kernel/kernel/utils/bitset/bitset.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #define NUMBER_OF_BITS_IN_TYPE 8u 5 | 6 | 7 | //use `void*` instead of `unsigned char` to allow implicit pointer conversions 8 | 9 | bool bitset_at(const uint32_t index, const void *const bitset) { 10 | const unsigned char *const byte_bitset = bitset; 11 | 12 | return byte_bitset[index/NUMBER_OF_BITS_IN_TYPE] & (1u << (index%NUMBER_OF_BITS_IN_TYPE)); 13 | } 14 | 15 | void bitset_set_at(const uint32_t index, void *const bitset, const bool value) { 16 | unsigned char *const byte_bitset = bitset; 17 | 18 | if(value) { 19 | byte_bitset[index/NUMBER_OF_BITS_IN_TYPE] |= (unsigned char)(1u << (index%NUMBER_OF_BITS_IN_TYPE)); 20 | } else { 21 | byte_bitset[index/NUMBER_OF_BITS_IN_TYPE] &= (unsigned char)(0xFEu << (index%NUMBER_OF_BITS_IN_TYPE)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /kernel/kernel/utils/bitset/bitset.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kassert.h" 8 | 9 | 10 | //index = which number bit you want (0-indexed) 11 | //size = number of uint32_t's, NOT number of bits 12 | bool bitset_at(uint32_t index, const void* bitset); 13 | 14 | void bitset_set_at(uint32_t index, void* bitset, bool value); 15 | -------------------------------------------------------------------------------- /kernel/kernel/utils/data_structures/hashmap/default_hashmap_functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | uint32_t str_hash_function(const char *const str_to_hash) { 5 | uint32_t hash = 0u; 6 | 7 | const size_t str_len = kstrlen(str_to_hash); 8 | for(uint32_t i = 0u; i < str_len; ++i) { 9 | hash ^= (uint32_t)str_to_hash[i]; 10 | } 11 | 12 | return hash; 13 | } 14 | 15 | bool str_comp(const char *const str1, const char *const str2) { 16 | return kstrcmp(str1, str2) == 0; 17 | } 18 | -------------------------------------------------------------------------------- /kernel/kernel/utils/data_structures/hashmap/default_hashmap_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kstring.h" 9 | 10 | 11 | uint32_t str_hash_function(const char* str_to_hash); 12 | bool str_comp(const char* str1, const char* str2); 13 | -------------------------------------------------------------------------------- /kernel/kernel/utils/data_structures/string/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | 4 | struct string string_new(const char* data) { 5 | return string_new_with_len(data, kstrlen(data)); 6 | } 7 | 8 | struct string string_new_with_len(const char* data, size_t len) { 9 | kassert(data != NULL, ((struct string){ NULL, 0u })); 10 | 11 | char *const str = kmalloc(len + 1); 12 | 13 | if(str == NULL) return (struct string){ NULL, 0u }; 14 | 15 | kmemcpy(str, data, len); 16 | str[len] = '\0'; 17 | 18 | return (struct string){ str, len }; 19 | } 20 | 21 | bool assign_string(struct string* str, const char* data) { 22 | return assign_string_with_len(str, data, kstrlen(data)); 23 | } 24 | 25 | bool assign_string_with_len(struct string* str, const char* data, size_t len) { 26 | kassert(str != NULL, false); 27 | 28 | if(!destroy_string(str)) return false; 29 | 30 | struct string new_str = string_new_with_len(data, len); 31 | 32 | if(new_str.data == NULL) return false; 33 | 34 | *str = new_str; 35 | 36 | return true; 37 | } 38 | 39 | bool assign_string_from_string(struct string* str, const struct string* other) { 40 | return assign_string_with_len(str, other->data, other->length); 41 | } 42 | 43 | bool destroy_string(struct string* str) { 44 | kassert(str != NULL, false); 45 | 46 | kfree(str->data); 47 | str->data = NULL; 48 | str->length = 0u; 49 | 50 | return true; 51 | } 52 | -------------------------------------------------------------------------------- /kernel/kernel/utils/data_structures/string/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | struct string { 12 | char* data; 13 | size_t length; 14 | }; 15 | 16 | 17 | struct string string_new(const char* data); 18 | struct string string_new_with_len(const char* data, size_t len); 19 | bool assign_string(struct string* str, const char* data); 20 | bool assign_string_with_len(struct string* str, const char* data, size_t len); 21 | bool assign_string_from_string(struct string* str, const struct string* other); 22 | bool destroy_string(struct string* str); 23 | -------------------------------------------------------------------------------- /kernel/kernel/utils/data_structures/vector/vector.c: -------------------------------------------------------------------------------- 1 | #include "vector.h" 2 | 3 | 4 | struct vector { 5 | void* d; 6 | size_t data_size; 7 | size_t capacity; 8 | size_t len; 9 | }; 10 | 11 | struct vector* create_vector(const size_t data_size) { 12 | struct vector *const ret = kmalloc(sizeof(struct vector)); 13 | if(ret == NULL) return NULL; 14 | 15 | *ret = (struct vector){ NULL, data_size, 0u, 0u }; 16 | return ret; 17 | } 18 | 19 | struct vector* copy_vector(const struct vector* v) { 20 | kassert(v != NULL, NULL); 21 | 22 | struct vector *const ret = create_vector(v->data_size); 23 | if(ret == NULL) return NULL; 24 | 25 | ret->capacity = v->capacity; 26 | ret->len = v->len; 27 | 28 | ret->d = kmalloc(v->capacity * v->data_size); 29 | if(ret->d == NULL) { 30 | destroy_vector(ret); 31 | return NULL; 32 | } 33 | 34 | kmemcpy(ret->d, v->d, v->len * v->data_size); 35 | 36 | return ret; 37 | } 38 | 39 | bool push_back(struct vector *const v, const void *const data) { 40 | //kprintf("v: %p, data: %p\n", v, data); 41 | kassert(v != NULL && data != NULL, false); 42 | 43 | const unsigned char *const d = data; 44 | 45 | if(v->d == NULL) { 46 | kassert(v->capacity == 0u && v->len == 0u, false); 47 | 48 | void *const new_d = kmalloc(2 * v->data_size); 49 | if(new_d == NULL) return false; 50 | 51 | v->d = new_d; 52 | kmemcpy(v->d, d, v->data_size); 53 | v->capacity = 2; 54 | v->len = 1; 55 | return true; 56 | } 57 | 58 | kassert(v->len <= v->capacity, false); 59 | if(v->len < v->capacity) { 60 | kmemcpy((void*)(((uintptr_t)v->d) + (v->len++ * v->data_size)), data, v->data_size); 61 | return true; 62 | } 63 | kprintf("before krealloc\n"); 64 | void *const new_d = krealloc(v->d, 2 * v->len * v->data_size); 65 | if(new_d == NULL) return false; 66 | 67 | v->d = new_d; 68 | kmemcpy((void*)(((uintptr_t)v->d) + (v->len++ * v->data_size)), data, v->data_size); 69 | v->capacity *= 2; 70 | 71 | return true; 72 | } 73 | 74 | void* at(struct vector *const v, const size_t index) { 75 | kassert(v != NULL && index < v->len, NULL); 76 | 77 | return (void*)(((uintptr_t)v->d) + (index * v->data_size)); 78 | } 79 | 80 | const void* at_const(const struct vector *const v, const size_t index) { 81 | kprintf("v: %p, index: %u\n", v, index); 82 | kassert(v != NULL && index < v->len, NULL); 83 | 84 | return (void*)(((uintptr_t)v->d) + (index * v->data_size)); 85 | } 86 | 87 | size_t size(const struct vector* v) { 88 | kassert(v != NULL, 0u); 89 | 90 | //kprintf("size(): v->len: %u\n", v->len); 91 | 92 | return v->len; 93 | } 94 | 95 | bool erase(struct vector *const v, const size_t index) { 96 | kassert(v != NULL && v->d != NULL && v->capacity <= v->len && index < v->len, false); 97 | 98 | for(size_t i = index; i < v->len - 1; ++i) { 99 | kmemcpy((void*)(((uintptr_t)v->d) + (i * v->data_size)), (const void*)(((uintptr_t)v->d) + ((i+1) * v->data_size)), v->data_size); 100 | } 101 | --v->len; 102 | 103 | return true; 104 | } 105 | 106 | bool clear(struct vector *const v) { 107 | kassert(v != NULL, false); 108 | 109 | if(v->d == NULL) { 110 | kassert(v->capacity == 0 && v->len == 0, false); 111 | return true; 112 | } 113 | 114 | v->len = 0; 115 | 116 | return true; 117 | } 118 | 119 | bool destructive_clear(struct vector *const v) { 120 | kassert(v != NULL, false); 121 | 122 | kfree(v->d); 123 | v->d = NULL; 124 | v->capacity = 0; 125 | v->len = 0; 126 | 127 | return true; 128 | } 129 | 130 | bool destroy_vector(struct vector *const v) { 131 | kassert(v != NULL, false); 132 | 133 | kfree(v->d); 134 | 135 | kfree(v); 136 | 137 | return true; 138 | } 139 | -------------------------------------------------------------------------------- /kernel/kernel/utils/data_structures/vector/vector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | struct vector; 13 | 14 | struct vector* create_vector(size_t data_size); 15 | struct vector* copy_vector(const struct vector* v); 16 | bool push_back(struct vector* v, const void* data); 17 | void* at(struct vector* v, size_t index); 18 | const void* at_const(const struct vector* v, size_t index); 19 | size_t size(const struct vector* v); 20 | bool erase(struct vector* v, size_t index); 21 | bool clear(struct vector* v); 22 | bool destructive_clear(struct vector* v); 23 | bool destroy_vector(struct vector* v); 24 | 25 | typedef struct vector* vector_type_t; // can be used similar to CTAD 26 | #define vector_type(T) struct vector* // Python style type hint to increase readability of code using this type 27 | -------------------------------------------------------------------------------- /kernel/kernel/utils/wrappers/physical_pointer.c: -------------------------------------------------------------------------------- 1 | #include "physical_pointer.h" 2 | 3 | 4 | struct physical_pointer create_physical_pointer(const size_t phys_p, const size_t pages_p) { 5 | if(pages_p > 0) { 6 | void *const virt = kernel_virt_allocator_allocate_pages(pages_p); 7 | 8 | if(virt) { 9 | if(!map_pages_in_kernel_addr(virt, phys_p, pages_p, PT_PRESENT | PT_RW, PD_PRESENT | PD_RW)) { 10 | return (struct physical_pointer){ phys_p, pages_p, 0 }; 11 | } 12 | return (struct physical_pointer){ phys_p, pages_p, (size_t)virt }; 13 | } 14 | return (struct physical_pointer){ phys_p, pages_p, 0 }; 15 | } 16 | return (struct physical_pointer){ phys_p, 0, 0 }; 17 | } 18 | 19 | bool free_physical_pointer(struct physical_pointer *const physical_pointer) { 20 | void *const virt = (void*)physical_pointer->virt; 21 | unmap_pages_in_kernel_addr(virt, physical_pointer->pages); 22 | if(!kernel_virt_allocator_free_pages(virt, physical_pointer->pages)) { 23 | return false; 24 | } 25 | 26 | physical_pointer->virt = 0; 27 | physical_pointer->pages = 0; 28 | 29 | return true; 30 | } 31 | -------------------------------------------------------------------------------- /kernel/kernel/utils/wrappers/physical_pointer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | struct physical_pointer { 12 | size_t phys; ///< The physical memory address, DO NOT MODIFY YOURSELF (not marked `const` since it is mutated by the below functions) 13 | size_t pages; ///< The number of pages, DO NOT MODIFY YOURSELF (not marked `const` since it is mutated by the below functions) 14 | size_t virt; ///< The virtual memory 15 | }; 16 | 17 | 18 | struct physical_pointer create_physical_pointer(size_t phys_p, size_t pages_p); 19 | 20 | // frees resources allocated in `create_physical_pointer`, it does NOT free the physical memory 21 | bool free_physical_pointer(struct physical_pointer* physical_pointer); 22 | -------------------------------------------------------------------------------- /kernel/libk/kassert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "kstdio.h" 4 | #include 5 | 6 | 7 | #ifndef NDEBUG 8 | #define kassert(cond, return_code) do { \ 9 | if(!(cond)) { \ 10 | kprintf("[file: %s :: line: %i]: ", __FILE__, __LINE__); \ 11 | kprintf("Condition Failed: %s\n", #cond); \ 12 | return return_code; \ 13 | } \ 14 | } while(0) 15 | 16 | #define kassert_void(cond) do { \ 17 | if(!(cond)) { \ 18 | kprintf("[file: %s :: line: %i]: ", __FILE__, __LINE__); \ 19 | kprintf("Condition Failed: %s\n", #cond); \ 20 | return; \ 21 | } \ 22 | } while(0) 23 | 24 | #define kassert_message(cond, message, return_code) do { \ 25 | if(!(cond)) { \ 26 | kprintf("%s\n", message); \ 27 | return return_code; \ 28 | } \ 29 | } while(0) 30 | 31 | #define kassert_message_void(cond, message) do { \ 32 | if(!(cond)) { \ 33 | kprintf("%s\n", message); \ 34 | return; \ 35 | } \ 36 | } while(0) 37 | /* 38 | #define kassert(cond, return_code) do { \ 39 | if(!(cond)) { \ 40 | kprintf("%4[file: %s :: line: %i]: ", __FILE__, __LINE__); \ 41 | terminal_context_writestring_color("Condition Failed: ", VGA_COLOR_RED); \ 42 | terminal_context_writestring_color(#cond, VGA_COLOR_RED); \ 43 | terminal_context_putchar_color('\n', VGA_COLOR_RED); \ 44 | return return_code; \ 45 | } \ 46 | } while(0) 47 | 48 | #define kassert_void(cond) do { \ 49 | if(!(cond)) { \ 50 | kprintf("%4[file: %s :: line: %i]: ", __FILE__, __LINE__); \ 51 | terminal_context_writestring_color("Condition Failed: ", VGA_COLOR_RED); \ 52 | terminal_context_writestring_color(#cond, VGA_COLOR_RED); \ 53 | terminal_context_putchar_color('\n', VGA_COLOR_RED); \ 54 | return; \ 55 | } \ 56 | } while(0) 57 | 58 | #define kassert_message(cond, message, return_code) do { \ 59 | if(!(cond)) { \ 60 | terminal_context_writestring_color(message, VGA_COLOR_RED); \ 61 | terminal_context_putchar_color('\n', VGA_COLOR_RED); \ 62 | return return_code; \ 63 | } \ 64 | } while(0) 65 | 66 | #define kassert_message_void(cond, message) do { \ 67 | if(!(cond)) { \ 68 | terminal_context_writestring_color(message, VGA_COLOR_RED); \ 69 | terminal_context_putchar_color('\n', VGA_COLOR_RED); \ 70 | return; \ 71 | } \ 72 | } while(0) 73 | */ 74 | #else 75 | 76 | #define kassert(cond, return_code) 77 | 78 | #define kassert_void(cond) 79 | 80 | #define kasser_message(cond, message, return_code) 81 | 82 | #define kassert_message_void(cond, message) 83 | #endif 84 | -------------------------------------------------------------------------------- /kernel/libk/kctype.c: -------------------------------------------------------------------------------- 1 | #include "kctype.h" 2 | 3 | 4 | int32_t kisalnum(const int32_t ch) { 5 | return kisalpha(ch) || kisdigit(ch); 6 | } 7 | 8 | int32_t kisalpha(const int32_t ch) { 9 | return kisupper(ch) || kislower(ch); 10 | } 11 | 12 | int32_t kislower(const int32_t ch) { 13 | return 'a' <= ch && ch <= 'z'; 14 | } 15 | 16 | int32_t kisupper(const int32_t ch) { 17 | return 'A' <= ch && ch <= 'Z'; 18 | } 19 | 20 | int32_t kisdigit(const int32_t ch) { 21 | return '0' <= ch && ch <= '9'; 22 | } 23 | 24 | int32_t kisxdigit(const int32_t ch) { 25 | return kisdigit(ch) || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F'); 26 | } 27 | 28 | int32_t kiscntrl(const int32_t ch) { 29 | return (0 <= ch && ch <= 31) || (ch == 127); 30 | } 31 | 32 | int32_t kisgraph(const int32_t ch) { 33 | return 33 <= ch && ch <= 126; 34 | } 35 | 36 | int32_t kisspace(const int32_t ch) { 37 | return (9 <= ch && ch <= 13) || (ch == 32); 38 | } 39 | 40 | int32_t kisblank(const int32_t ch) { 41 | return ch == 9 || ch == 32; 42 | } 43 | 44 | int32_t kisprint(const int32_t ch) { 45 | return ch == ' ' || kisgraph(ch); 46 | } 47 | 48 | int32_t kispunct(const int32_t ch) { 49 | return (33 <= ch && ch <= 47) || (58 <= ch && ch <= 64) || (91 <= ch && ch <= 96) || (123 <= ch && ch <= 126); 50 | } 51 | 52 | int32_t ktolower(const int32_t ch) { 53 | if(kisupper(ch)) { 54 | return ch - 32; 55 | } 56 | return ch; 57 | } 58 | 59 | int32_t ktoupper(const int32_t ch) { 60 | if(kislower(ch)) { 61 | return ch + 32; 62 | } 63 | return ch; 64 | } 65 | -------------------------------------------------------------------------------- /kernel/libk/kctype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | int32_t kisalnum(int32_t ch); 7 | int32_t kisalpha(int32_t ch); 8 | int32_t kislower(int32_t ch); 9 | int32_t kisupper(int32_t ch); 10 | int32_t kisdigit(int32_t ch); 11 | int32_t kisxdigit(int32_t ch); 12 | int32_t kiscntrl(int32_t ch); 13 | int32_t kisgraph(int32_t ch); 14 | int32_t kisspace(int32_t ch); 15 | int32_t kisblank(int32_t ch); 16 | int32_t kisprint(int32_t ch); 17 | int32_t kispunct(int32_t ch); 18 | int32_t ktolower(int32_t ch); 19 | int32_t ktoupper(int32_t ch); 20 | -------------------------------------------------------------------------------- /kernel/libk/kerrno.c: -------------------------------------------------------------------------------- 1 | int errno = 0; /// This is technically not compliant with C11 (standard says errno *has* to be a macro), but I don't care that much 2 | -------------------------------------------------------------------------------- /kernel/libk/kerrno.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define EPERM 1 /* Operation not permitted */ 4 | #define ENOENT 2 /* No such file or directory */ 5 | #define ENOFILE 2 /* Microsoft legacy alias for ENOENT */ 6 | #define ESRCH 3 /* No such process */ 7 | #define EINTR 4 /* Interrupted function call */ 8 | #define EIO 5 /* Input/output error */ 9 | #define ENXIO 6 /* No such device or address */ 10 | #define E2BIG 7 /* Arg list too long */ 11 | #define ENOEXEC 8 /* Exec format error */ 12 | #define EBADF 9 /* Bad file descriptor */ 13 | #define ECHILD 10 /* No child processes */ 14 | #define EAGAIN 11 /* Resource temporarily unavailable */ 15 | #define ENOMEM 12 /* Not enough space */ 16 | #define EACCES 13 /* Permission denied */ 17 | #define EFAULT 14 /* Bad address */ 18 | 19 | /* 15 - Unknown Error */ 20 | 21 | #define EBUSY 16 /* Device or resource busy */ 22 | #define EEXIST 17 /* File exists */ 23 | #define EXDEV 18 /* Improper link (cross-device link) */ 24 | #define ENODEV 19 /* No such device */ 25 | #define ENOTDIR 20 /* Not a directory */ 26 | #define EISDIR 21 /* Is a directory */ 27 | 28 | /* Microsoft's non-standard _get_errno() and _set_errno(), which are 29 | * declared in , and for which we provide in-line support on 30 | * legacy Windows versions, (also in ), demand exposure of 31 | * EINVAL within , (for legacy support), regardless of the 32 | * state of _ERRNO_H. 33 | */ 34 | #define EINVAL 22 /* Invalid argument */ 35 | 36 | /* The remaining error codes are to be exposed only when has 37 | * been included explicitly. 38 | */ 39 | #define ENFILE 23 /* Too many open files in system */ 40 | #define EMFILE 24 /* Too many open files */ 41 | #define ENOTTY 25 /* Inappropriate I/O control operation */ 42 | 43 | /* 26 - Unknown Error */ 44 | 45 | #define EFBIG 27 /* File too large */ 46 | #define ENOSPC 28 /* No space left on device */ 47 | #define ESPIPE 29 /* Invalid seek (seek on a pipe?) */ 48 | #define EROFS 30 /* Read-only file system */ 49 | #define EMLINK 31 /* Too many links */ 50 | #define EPIPE 32 /* Broken pipe */ 51 | #define EDOM 33 /* Domain error (math functions) */ 52 | #define ERANGE 34 /* Result too large (possibly too small) */ 53 | 54 | /* 35 - Unknown Error */ 55 | 56 | #define EDEADLK 36 /* Resource deadlock avoided (non-Cyg) */ 57 | #define EDEADLOCK 36 /* Microsoft legacy alias for EDEADLK */ 58 | 59 | /* 37 - Unknown Error */ 60 | 61 | #define ENAMETOOLONG 38 /* Filename too long (91 in Cyg?) */ 62 | #define ENOLCK 39 /* No locks available (46 in Cyg?) */ 63 | #define ENOSYS 40 /* Function not implemented (88 in Cyg?) */ 64 | #define ENOTEMPTY 41 /* Directory not empty (90 in Cyg?) */ 65 | #define EILSEQ 42 /* Illegal byte sequence */ 66 | 67 | extern int errno; 68 | -------------------------------------------------------------------------------- /kernel/libk/kmath.c: -------------------------------------------------------------------------------- 1 | #include "kmath.h" 2 | 3 | int8_t ksignbit(const int8_t val) { 4 | return !(val >= 0); 5 | } 6 | 7 | uint32_t kabs(const int32_t val) { 8 | return (uint32_t) ((val >= 0) ? val : -val); 9 | } 10 | 11 | int8_t ksign(const int8_t val) { 12 | if(val == 0) return 0; 13 | return (kabs(val) > 0) ? 1 : -1; 14 | } 15 | 16 | int64_t kmin(const int64_t x, const int64_t y) { 17 | return (x < y) ? x : y; 18 | } 19 | 20 | int64_t kmax(const int64_t x, const int64_t y) { 21 | return (x > y) ? x : y; 22 | } 23 | 24 | int64_t kmod(int64_t x, int64_t y) { 25 | return x - (y * (x/y)); 26 | } 27 | 28 | int64_t kpow(int64_t base, int64_t exponent) { 29 | int64_t result = 1; 30 | for(int64_t i = 0; i < exponent; ++i) { 31 | result *= base; 32 | } 33 | return result; 34 | } 35 | 36 | uint64_t kpow_u(uint64_t base, uint64_t exponent) { 37 | uint64_t result = 1; 38 | for(uint64_t i = 0; i < exponent; ++i) { 39 | result *= base; 40 | } 41 | return result; 42 | } 43 | -------------------------------------------------------------------------------- /kernel/libk/kmath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | int8_t ksignbit(int8_t val); 7 | int8_t ksign(int8_t val); 8 | uint32_t kabs(int32_t val); 9 | int64_t kmin(int64_t x, int64_t y); 10 | int64_t kmax(int64_t x, int64_t y); 11 | int64_t kmod(int64_t x, int64_t y); 12 | //currently does not support negative exponents 13 | int64_t kpow(int64_t base, int64_t exponent); 14 | uint64_t kpow_u(uint64_t base, uint64_t exponent); 15 | -------------------------------------------------------------------------------- /kernel/libk/kstdio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | //#include 11 | #include 12 | 13 | int32_t kprintf_implementation(const char* format, va_list* pargs); 14 | int32_t kprintf(const char *format, ...); 15 | int32_t kputs(const char* str); 16 | -------------------------------------------------------------------------------- /kernel/libk/kstdlib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | //#include "paging.h" 8 | //#include "initialize_kernel_memory.h" 9 | #include "kstring.h" 10 | 11 | #include 12 | #include 13 | 14 | 15 | inline uint32_t bytes_to_words(const uint32_t bytes) { 16 | return (bytes/4u) + (bytes%4u > 0); 17 | } 18 | 19 | inline uint32_t round_up_to_nearest_n_power(const uint32_t num_to_round, const uint32_t multiple) { 20 | if(multiple == 0u) return num_to_round; 21 | 22 | uint32_t remainder = num_to_round % multiple; 23 | if(remainder == 0u) { 24 | return num_to_round; 25 | } 26 | 27 | return num_to_round + multiple - remainder; 28 | } 29 | 30 | inline uint32_t get_size(const uint32_t size_word) { 31 | return size_word & 0x7fffffff; 32 | } 33 | inline bool get_allocated_bit(const uint32_t size_word) { 34 | return (size_word & 0x80000000) > 0; 35 | } 36 | 37 | 38 | void kdynamic_memory_init(void); 39 | void* kmalloc(size_t size); 40 | void* zeroed_out_kmalloc(size_t size); 41 | void kfree(const void* payload_ptr); 42 | void* krealloc(void* ptr, size_t new_size); 43 | void* zeroed_out_krealloc(void* ptr, size_t new_size); 44 | void* kcalloc(size_t num, size_t size); 45 | void* uninitialized_kcalloc(size_t num, size_t size); 46 | 47 | uint32_t* get_head(void); 48 | -------------------------------------------------------------------------------- /kernel/libk/kstring.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kassert.h" 8 | 9 | 10 | void* kmemcpy(void* restrict destination, const void* restrict source, size_t num); 11 | void* kmemmove(void* destination, const void* source, size_t num); 12 | void* kmemchr(void* ptr, int32_t value, size_t num); 13 | int32_t kmemcmp(const void* ptr1, const void* ptr2, size_t num); 14 | void* kmemset(void* ptr, uint32_t value, size_t num); 15 | char* kstrcat(char* destination, const char* source); 16 | char* kstrncat(char* destination, const char* source, size_t num); 17 | char* kstrchr(char* str, int32_t character); //searches from start of string 18 | char* kstrrchr(char* str, int32_t character); //searches from end of string 19 | int32_t kstrcmp(const char* lhs, const char* rhs); 20 | int32_t kstrncmp(const char* const lhs, const char* rhs, size_t sz); 21 | char* kstrcpy(char* destination, const char* source); 22 | char* kstrncpy(char* destination, const char* source, size_t num); 23 | int32_t kstrspn(const char* str1, const char* str2); 24 | size_t kstrlen(const char* str); 25 | char* kint_to_string(int64_t input, char* string_ret, size_t ret_size, uint32_t base, bool lowercase); 26 | char kint_to_char(int8_t input); 27 | int8_t kchar_to_int(char c); 28 | -------------------------------------------------------------------------------- /kernel/libk/optional.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define GENERATE_OPTIONAL(T) \ 6 | struct optional_##T { \ 7 | T data; \ 8 | bool has_value; \ 9 | }; 10 | 11 | #define OPTIONAL_NAME(T) optional_##T 12 | 13 | -------------------------------------------------------------------------------- /kernel/libk/sys/kstdlib_constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define BYTES_IN_WORD 4 4 | #define MIN_BLOCK_SIZE 8 //4 words for bookkeeping and 4 word payload 5 | #define WORDS_IN_PAGE (PAGE_SIZE/BYTES_IN_WORD) 6 | -------------------------------------------------------------------------------- /make.config: -------------------------------------------------------------------------------- 1 | HOST := i686 2 | 3 | TOOLCHAIN_NAME := ${HOST}-elf 4 | 5 | AR := ${TOOLCHAIN_NAME}-ar 6 | CC := ${TOOLCHAIN_NAME}-gcc 7 | 8 | AS := nasm -felf32 9 | 10 | WARNING_FLAGS := -Wall -Wextra -Wundef -Wshadow -Wpointer-arith -Wcast-align \ 11 | -Wstrict-prototypes -Wcast-qual -Wconversion -Wunreachable-code \ 12 | -Wwrite-strings -Wnested-externs -Winline \ 13 | -Wno-long-long -Wpedantic #-Werror 14 | 15 | KERNEL_FLAGS := -std=gnu17 -ffreestanding -DRocketOS -mgeneral-regs-only 16 | 17 | RELEASE_LINK_FLAGS := -O3 -flto 18 | DEBUG_LINK_FLAGS := -O0 -g 19 | 20 | DEBUG_FLAGS := -fverbose-asm -O0 -g -DDEBUG -save-temps=obj 21 | RELEASE_FLAGS := -O3 -DNDEBUG 22 | 23 | 24 | PREFIX := /usr 25 | EXEC_PREFIX := ${PREFIX} 26 | BOOTDIR := /boot 27 | LIBDIR := ${EXEC_PREFIX}/lib 28 | INCLUDEDIR := ${PREFIX}/include 29 | 30 | CFLAGS := -O2 -g 31 | CPPFLAGS ?= 32 | 33 | # Configure the cross-compiler to use the desired system root. 34 | PWD_DIR != ../get_pwd.sh 35 | SYSROOT := ${PWD_DIR}/sysroot 36 | CC := ${CC} --sysroot=${SYSROOT} 37 | 38 | DESTDIR := ${SYSROOT} 39 | -------------------------------------------------------------------------------- /make_ramdisk.py: -------------------------------------------------------------------------------- 1 | import os 2 | import struct 3 | 4 | ram_disk_file_dir = "./ramdisk_files/" 5 | sizeof_header = 128 6 | 7 | with open("ramdisk.img", "wb") as ramdisk: 8 | for path, dirs, files in os.walk(ram_disk_file_dir): 9 | for filename in files: 10 | with open(path + '/' + filename, "rb") as file: 11 | data = file.read() 12 | ramdisk.write(struct.pack(' 4 | 5 | 6 | inline uint8_t inb(const uint16_t port) { 7 | unsigned char v; 8 | 9 | asm volatile ("inb %w1,%0":"=a" (v):"Nd" (port)); 10 | return v; 11 | } 12 | 13 | inline void outb(const uint16_t port, const uint8_t value) { 14 | asm volatile ("outb %b0,%w1": :"a" (value), "Nd" (port)); 15 | } 16 | -------------------------------------------------------------------------------- /ramdisk_files/serial.c: -------------------------------------------------------------------------------- 1 | #include "serial.h" 2 | 3 | uint8_t is_transmit_empty(void); 4 | 5 | void serial_putchar(char c); 6 | 7 | void serial_write(const char* text, size_t size); 8 | 9 | void serial_writestring(const char* text); 10 | -------------------------------------------------------------------------------- /ramdisk_files/serial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "strlen.h" 6 | #include "port_io.h" 7 | 8 | 9 | #define COM1 0x3F8 10 | 11 | inline uint8_t is_transmit_empty(void) { 12 | return inb(COM1 + 5) & 0x20u; 13 | } 14 | 15 | inline void serial_putchar(const char c) { 16 | while (is_transmit_empty() == 0); 17 | 18 | outb(COM1, (uint8_t)c); 19 | } 20 | 21 | inline void serial_write(const char *const text, const size_t size) { 22 | for(size_t i = 0u; i < size; ++i) { 23 | serial_putchar(text[i]); 24 | } 25 | } 26 | 27 | inline void serial_writestring(const char *const text) { 28 | serial_write(text, kstrlen(text)); 29 | } 30 | -------------------------------------------------------------------------------- /ramdisk_files/strlen.c: -------------------------------------------------------------------------------- 1 | #include "strlen.h" 2 | 3 | size_t kstrlen(const char *const str) { 4 | size_t len = 0; 5 | while (str != NULL && str[len]) { 6 | len++; 7 | } 8 | return len; 9 | } 10 | -------------------------------------------------------------------------------- /ramdisk_files/strlen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | size_t kstrlen(const char* str); 7 | -------------------------------------------------------------------------------- /ramdisk_files/test_program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OperatingSystemRocket/RocketOS/10a606a35eac806e17a1dac297ff8818525f07c1/ramdisk_files/test_program -------------------------------------------------------------------------------- /ramdisk_files/test_program.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | size_t kstrlen(const char *const str) { 6 | size_t len = 0; 7 | while (str != NULL && str[len]) { 8 | len++; 9 | } 10 | return len; 11 | } 12 | 13 | 14 | uint8_t inb(const uint16_t port) { 15 | unsigned char v; 16 | 17 | asm volatile ("inb %w1,%0":"=a" (v):"Nd" (port)); 18 | return v; 19 | } 20 | 21 | void outb(const uint16_t port, const uint8_t value) { 22 | asm volatile ("outb %b0,%w1": :"a" (value), "Nd" (port)); 23 | } 24 | 25 | 26 | #define COM1 0x3F8 27 | 28 | uint8_t is_transmit_empty(void) { 29 | return inb(COM1 + 5) & 0x20u; 30 | } 31 | 32 | void serial_putchar(const char c) { 33 | while (is_transmit_empty() == 0); 34 | 35 | outb(COM1, (uint8_t)c); 36 | } 37 | 38 | void serial_write(const char *const text, const size_t size) { 39 | for(size_t i = 0u; i < size; ++i) { 40 | serial_putchar(text[i]); 41 | } 42 | } 43 | 44 | void serial_writestring(const char *const text) { 45 | serial_write(text, kstrlen(text)); 46 | } 47 | 48 | 49 | void simple_program(void) { 50 | serial_writestring("simple_program called\n"); 51 | } 52 | 53 | void _start(void) { 54 | for(;;) { 55 | simple_program(); 56 | asm volatile("hlt"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/libc/Test-kstdlib.c: -------------------------------------------------------------------------------- 1 | #include "test_kernel_early.h" 2 | 3 | #include "unity.h" 4 | 5 | #include "kstdlib_constants.h" 6 | #include "kstdlib.h" 7 | #include "kstring.h" 8 | 9 | 10 | void setUp(void) {} 11 | void tearDown(void) {} 12 | 13 | 14 | static void test_kmalloced_block(uint32_t *const payload_ptr, const uint32_t payload_mem_magic_value, const uint32_t bytes_of_payload, const uint32_t number_of_allocated_words) { 15 | for(uint32_t i = 0; i < bytes_of_payload; ++i) { 16 | TEST_ASSERT_EQUAL_HEX8(payload_mem_magic_value, ((unsigned char*)payload_ptr)[i]); 17 | } 18 | 19 | const uint32_t first_word = payload_ptr[-3]; 20 | TEST_ASSERT_EQUAL_UINT32(1u, get_allocated_bit(first_word)); 21 | TEST_ASSERT_EQUAL_UINT32(number_of_allocated_words, get_size(first_word)); 22 | 23 | const uint32_t prev_ptr = payload_ptr[-2]; 24 | const uint32_t next_ptr = payload_ptr[-1]; 25 | TEST_ASSERT_EQUAL_UINT32(0u, prev_ptr); 26 | TEST_ASSERT_EQUAL_UINT32(0u, next_ptr); 27 | 28 | const uint32_t last_word = payload_ptr[get_size(first_word-4)]; 29 | TEST_ASSERT_EQUAL_UINT32(1u, get_allocated_bit(last_word)); 30 | TEST_ASSERT_EQUAL_UINT32(number_of_allocated_words, get_size(last_word)); 31 | } 32 | 33 | static uint32_t round_up_to_nearest_multiple_of_four(const uint32_t num) { 34 | return ((num+3)/4u)*4u; 35 | } 36 | 37 | static void test_kmalloc_allocation_and_block(const uint32_t num_of_bytes_to_allocate) { 38 | uint32_t *const payload_ptr = kmalloc(num_of_bytes_to_allocate); 39 | 40 | const uint32_t PAYLOAD_MEM_MAGIC_VALUE = 0xAAu; 41 | const uint32_t bytes_of_payload = round_up_to_nearest_multiple_of_four(num_of_bytes_to_allocate); 42 | 43 | kmemset(payload_ptr, PAYLOAD_MEM_MAGIC_VALUE, bytes_of_payload); 44 | test_kmalloced_block(payload_ptr, PAYLOAD_MEM_MAGIC_VALUE, bytes_of_payload, bytes_to_words(num_of_bytes_to_allocate)+4u); 45 | 46 | kfree(payload_ptr); 47 | } 48 | 49 | static void test_zeroed_out_kmalloc_allocation_and_block(const uint32_t num_of_bytes_to_allocate) { 50 | uint32_t *const payload_ptr = zeroed_out_kmalloc(num_of_bytes_to_allocate); 51 | 52 | test_kmalloced_block(payload_ptr, 0x00u, round_up_to_nearest_multiple_of_four(num_of_bytes_to_allocate), bytes_to_words(num_of_bytes_to_allocate)+4u); 53 | 54 | kfree(payload_ptr); 55 | } 56 | 57 | 58 | void test_kdynamic_memory_init_head_value(void) { 59 | const uint32_t *const head_ptr = get_head(); 60 | 61 | TEST_ASSERT_NOT_NULL(head_ptr); 62 | 63 | TEST_ASSERT_EQUAL_UINT32(WORDS_IN_PAGE, head_ptr[0]); 64 | TEST_ASSERT_EQUAL_UINT32(0u, head_ptr[1]); 65 | TEST_ASSERT_EQUAL_UINT32(0u, head_ptr[2]); 66 | TEST_ASSERT_EQUAL_UINT32(WORDS_IN_PAGE, head_ptr[WORDS_IN_PAGE-1]); 67 | } 68 | 69 | 70 | void test_kmalloc_size_zero(void) { 71 | const void *const ptr = kmalloc(0u); 72 | 73 | TEST_ASSERT_NULL(ptr); 74 | 75 | kfree(ptr); 76 | } 77 | 78 | void test_kmalloc_size_one(void) { 79 | test_kmalloc_allocation_and_block(1u); 80 | } 81 | 82 | void test_kmalloc_size_four(void) { 83 | test_kmalloc_allocation_and_block(4u); 84 | } 85 | 86 | void test_kmalloc_size_seventeen(void) { 87 | test_kmalloc_allocation_and_block(17u); 88 | } 89 | 90 | 91 | void test_zeroed_out_kmalloc_size_zero(void) { 92 | const void *const ptr = kmalloc(0u); 93 | 94 | TEST_ASSERT_NULL(ptr); 95 | 96 | kfree(ptr); 97 | } 98 | 99 | void test_zeroed_out_kmalloc_size_one(void) { 100 | test_zeroed_out_kmalloc_allocation_and_block(1u); 101 | } 102 | 103 | void test_zeroed_out_kmalloc_size_four(void) { 104 | test_zeroed_out_kmalloc_allocation_and_block(4u); 105 | } 106 | 107 | void test_zeroed_out_kmalloc_size_seventeen(void) { 108 | test_zeroed_out_kmalloc_allocation_and_block(17u); 109 | } 110 | 111 | 112 | void test_kfree_null(void) { 113 | kfree(NULL); //cannot test for invalid memory access/corruption, so testing if it hangs or crashes 114 | } 115 | 116 | void test_kfree_single_kmalloced_four_byte_block(void) { 117 | uint32_t *const payload_ptr = kmalloc(4u); 118 | 119 | const uint32_t first_word = payload_ptr[-3]; 120 | const uint32_t last_word = payload_ptr[get_size(first_word-4)]; 121 | 122 | 123 | kfree(payload_ptr); 124 | 125 | TEST_ASSERT_NOT_EQUAL_UINT32(first_word, payload_ptr[-3]); 126 | 127 | TEST_ASSERT_EQUAL_UINT32(0u, payload_ptr[-2]); 128 | TEST_ASSERT_EQUAL_UINT32(0u, payload_ptr[-1]); 129 | 130 | TEST_ASSERT_NOT_EQUAL_UINT32(last_word, payload_ptr[get_size(first_word-4)]); 131 | } 132 | 133 | //TODO: finish implementing this function and test multiple kmalloc allocations in one test 134 | void test_kfree_two_kmalloced_four_byte_blocks(void) { 135 | uint32_t *const first_allocation_payload_ptr = kmalloc(4u); 136 | uint32_t *const second_allocation_payload_ptr = kmalloc(4u); 137 | (void) second_allocation_payload_ptr; 138 | 139 | 140 | kfree(first_allocation_payload_ptr); 141 | 142 | const uint32_t first_word_first_allocation = first_allocation_payload_ptr[-3]; 143 | TEST_ASSERT_EQUAL_UINT32(0u, get_allocated_bit(first_word_first_allocation)); 144 | TEST_ASSERT_EQUAL_UINT32(5u, get_size(first_word_first_allocation)); 145 | 146 | kfree(second_allocation_payload_ptr); 147 | 148 | const uint32_t prev_first_allocation = first_allocation_payload_ptr[-2]; 149 | TEST_ASSERT_EQUAL_UINT32(0u, prev_first_allocation); 150 | 151 | const uint32_t next_first_allocation = first_allocation_payload_ptr[-1]; 152 | TEST_ASSERT_EQUAL_UINT32(0u, next_first_allocation); 153 | } 154 | 155 | 156 | void kernel_main(void) { 157 | serial_init(); 158 | 159 | gdt_init(); 160 | gdt_load(); 161 | 162 | pic_init(); 163 | isr_install(); 164 | 165 | write_tss(); 166 | 167 | initialize_kernel_memory(); 168 | kdynamic_memory_init(); 169 | 170 | UNITY_BEGIN(); 171 | 172 | 173 | RUN_TEST(test_kdynamic_memory_init_head_value); 174 | 175 | RUN_TEST(test_kmalloc_size_zero); 176 | RUN_TEST(test_kmalloc_size_one); 177 | RUN_TEST(test_kmalloc_size_four); 178 | RUN_TEST(test_kmalloc_size_seventeen); 179 | 180 | RUN_TEST(test_zeroed_out_kmalloc_size_zero); 181 | RUN_TEST(test_zeroed_out_kmalloc_size_one); 182 | RUN_TEST(test_zeroed_out_kmalloc_size_four); 183 | RUN_TEST(test_zeroed_out_kmalloc_size_seventeen); 184 | 185 | RUN_TEST(test_kfree_null); 186 | RUN_TEST(test_kfree_single_kmalloced_four_byte_block); 187 | RUN_TEST(test_kfree_two_kmalloced_four_byte_blocks); 188 | 189 | 190 | UNITY_END(); 191 | 192 | outb(0xf4, 0x10); 193 | } 194 | -------------------------------------------------------------------------------- /test/libc/Test-kstring4.c: -------------------------------------------------------------------------------- 1 | #include "test_kernel_early.h" 2 | 3 | #include "unity.h" 4 | 5 | #include "kstring.h" 6 | 7 | 8 | void setUp(void) {} 9 | void tearDown(void) {} 10 | 11 | 12 | void test_kint_to_char_normal_3(void) { 13 | const char c = kint_to_char(3); 14 | 15 | TEST_ASSERT_EQUAL_HEX8('3', c); 16 | } 17 | 18 | void test_kint_to_char_normal_7(void) { 19 | const char c = kint_to_char(7); 20 | 21 | TEST_ASSERT_EQUAL_HEX8('7', c); 22 | } 23 | 24 | void test_kint_to_char_normal_0(void) { 25 | const char c = kint_to_char(0); 26 | 27 | TEST_ASSERT_EQUAL_HEX8('0', c); 28 | } 29 | 30 | void test_kint_to_char_normal_9(void) { 31 | const char c = kint_to_char(9); 32 | 33 | TEST_ASSERT_EQUAL_HEX8('9', c); 34 | } 35 | 36 | void test_kint_to_char_out_of_range_minus_1(void) { 37 | const char c = kint_to_char(-1); 38 | 39 | TEST_ASSERT_EQUAL_HEX8('\0', c); 40 | } 41 | 42 | void test_kint_to_char_out_of_range_10(void) { 43 | const char c = kint_to_char(10); 44 | 45 | TEST_ASSERT_EQUAL_HEX8('\0', c); 46 | } 47 | 48 | 49 | void kernel_main(void) { 50 | serial_init(); 51 | 52 | UNITY_BEGIN(); 53 | 54 | 55 | RUN_TEST(test_kint_to_char_normal_3); 56 | RUN_TEST(test_kint_to_char_normal_7); 57 | RUN_TEST(test_kint_to_char_normal_0); 58 | RUN_TEST(test_kint_to_char_normal_9); 59 | RUN_TEST(test_kint_to_char_out_of_range_minus_1); 60 | RUN_TEST(test_kint_to_char_out_of_range_10); 61 | 62 | 63 | UNITY_END(); 64 | 65 | outb(0xf4, 0x10); 66 | } 67 | -------------------------------------------------------------------------------- /test/test_kernel_early.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "serial_driver.h" 10 | 11 | 12 | void kernel_early(const uint32_t mboot_magic, const multiboot_info_t *const mboot_header) { 13 | (void) mboot_header; //needed for calling convention reasons, but currently unused 14 | 15 | if(serial_init()) { //fails if serial is faulty 16 | serial_writestring("Serial driver works\n"); 17 | } 18 | 19 | terminal_context_initialize(); 20 | 21 | if (mboot_magic != MULTIBOOT_BOOTLOADER_MAGIC) { 22 | terminal_context_writestring_color("Invalid Multiboot Magic!\n", VGA_COLOR_RED); 23 | } else { 24 | terminal_context_writestring("The multiboot structure was loaded properly\n"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/unity_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "serial_driver.h" 4 | 5 | #define UNITY_EXCLUDE_SETJMP_H 6 | #define UNITY_EXCLUDE_MATH_H 7 | #define UNITY_EXCLUDE_FLOAT 8 | #define UNITY_EXCLUDE_DOUBLE 9 | #define UNITY_OUTPUT_CHAR(a) serial_putchar(a) 10 | -------------------------------------------------------------------------------- /test/utils/data_structures/hashmap/Test-hashmap.c: -------------------------------------------------------------------------------- 1 | #include "test_kernel_early.h" 2 | 3 | #include "unity.h" 4 | 5 | #include "default_hashmap_functions.h" 6 | #include "hashmap.h" 7 | 8 | 9 | void setUp(void) {} 10 | void tearDown(void) {} 11 | 12 | 13 | void kernel_main(void) { 14 | serial_init(); 15 | 16 | gdt_init(); 17 | gdt_load(); 18 | 19 | pic_init(); 20 | isr_install(); 21 | 22 | write_tss(); 23 | 24 | initialize_kernel_memory(); 25 | kdynamic_memory_init(); 26 | 27 | UNITY_BEGIN(); 28 | 29 | 30 | 31 | 32 | 33 | UNITY_END(); 34 | 35 | outb(0xf4, 0x10); 36 | } 37 | -------------------------------------------------------------------------------- /toolchain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Set the versions we will be using. 5 | binutils_version="2.36" 6 | gcc_version="10.2.0" 7 | 8 | # This script expects the target triplet (e.g. i786-pc-elf) as command line argument. 9 | target="i686-elf" 10 | 11 | # The tools will be installed in ~/cross/$target. 12 | prefix=~/cross/$target 13 | 14 | 15 | # Install prerequisite software using the package manager 16 | # Package manager installed gcc is used to build the cross compiler gcc 17 | sudo apt install git xorriso grub-pc-bin build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo qemu qemu-system-i386 gcc nasm -y 18 | 19 | 20 | # First check whether the toolchain was already built on a previous run of this script. 21 | if [ ! -d $prefix ] 22 | then 23 | mkdir -p /tmp/toolchain 24 | cd /tmp/toolchain 25 | 26 | # Download gcc sources if they are not yet downloaded. 27 | if [ ! -f gcc-$gcc_version.tar.gz ] 28 | then 29 | wget -c -O gcc-$gcc_version.tar.gz ftp://ftp.gnu.org/gnu/gcc/gcc-$gcc_version/gcc-$gcc_version.tar.gz 30 | tar -xf gcc-$gcc_version.tar.gz 31 | fi 32 | 33 | # Download binutils sources if they are not yet downloaded. 34 | if [ ! -f binutils-$binutils_version.tar.bz2 ] 35 | then 36 | wget -c -O binutils-$binutils_version.tar.bz2 ftp://ftp.gnu.org/gnu/binutils/binutils-$binutils_version.tar.bz2 37 | tar -xf binutils-$binutils_version.tar.bz2 38 | fi 39 | 40 | # Create build paths. 41 | mkdir -p /tmp/toolchain/build-binutils 42 | mkdir -p /tmp/toolchain/build-gcc 43 | 44 | # Build binutils. 45 | cd /tmp/toolchain/build-binutils 46 | sudo rm -rf * 47 | /tmp/toolchain/binutils-$binutils_version/configure --target=$target --prefix=$prefix --disable-nls 2>&1 48 | make all 2>&1 49 | make install 2>&1 50 | sudo rm -rf * 51 | 52 | # Build gcc and libgcc. 53 | cd /tmp/toolchain/build-gcc 54 | /tmp/toolchain/gcc-$gcc_version/configure --target=$target --prefix=$prefix --disable-nls --enable-languages=c --without-headers 2>&1 55 | make all-gcc 2>&1 56 | make install-gcc 2>&1 57 | make all-target-libgcc 2>&1 58 | make install-target-libgcc 2>&1 59 | 60 | # Make sure that our cross compiler will be found by creating links. 61 | # Alternative: Add the $prefix/bin directory to your $PATH. 62 | sudo ln -s -f $prefix/bin/* /usr/local/bin/ 63 | fi 64 | 65 | # Also if the cross compiler has not been freshly build, link it so that it will be found. 66 | sudo ln -s -f $prefix/bin/* /usr/local/bin/ 67 | -------------------------------------------------------------------------------- /userspace/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local 2 | EXEC_PREFIX ?= $(PREFIX) 3 | INCLUDEDIR ?= $(PREFIX)/include 4 | LIBDIR ?= $(EXEC_PREFIX)/lib 5 | 6 | CFLAGS := $(CFLAGS) -ffreestanding -Wall -Wextra 7 | CPPFLAGS := $(CPPFLAGS) -I../sysroot/usr/include/userspace -I../sysroot/usr/include/kernel/kernel -I../sysroot/usr/include/kernel/arch/i686 8 | LIBC_CFLAGS := $(CFLAGS) 9 | LIBC_CPPFLAGS := $(CPPFLAGS) -D__is_libc 10 | 11 | include ../make.config 12 | 13 | KERNEL_FLAGS ?= -std=gnu17 -ffreestanding -DRocketOS -mgeneral-regs-only 14 | 15 | ifdef RELEASE 16 | IMAGE_FLAGS := -ffreestanding $(RELEASE_LINK_FLAGS) -nostdlib 17 | else 18 | IMAGE_FLAGS := -ffreestanding $(DEBUG_LINK_FLAGS) -nostdlib 19 | endif 20 | 21 | 22 | BINARIES = libc.a 23 | 24 | 25 | #libc 26 | LIBC_C_NAMES = $(shell find libc/ -name '*.c') 27 | LIBC_H_NAMES = $(shell find libc/ -name '*.h') 28 | 29 | #sysroot 30 | INCLUDE_HEADERS = $(shell find include/ -name '*.h') 31 | 32 | LIBC_OBJS = $(LIBC_C_NAMES:.c=.libc.o) 33 | 34 | 35 | .PHONY: all clean install install-headers install-libs 36 | .SUFFIXES: .o .libc.o .c .S 37 | 38 | all: $(BINARIES) 39 | 40 | libc.a: $(LIBC_OBJS) 41 | $(AR) rcs $@ $(LIBC_OBJS) -lgcc 42 | 43 | .c.o: 44 | $(CC) -MD -c $< -o $@ $(KERNEL_FLAGS) $(WARNING_FLAGS) $(FLAGS) 45 | 46 | .c.S: 47 | $(CC) -MD -c $< -o $@ $(CFLAGS) $(CPPFLAGS) 48 | 49 | .c.libc.o: 50 | $(CC) -MD -c $< -o $@ $(LIBC_CFLAGS) $(LIBC_CPPFLAGS) 51 | 52 | .S.libc.o: 53 | $(CC) -MD -c $< -o $@ $(LIBC_CFLAGS) $(LIBC_CPPFLAGS) 54 | 55 | clean: 56 | -rm libc.a 57 | -rm $(shell find -name '*.o') 58 | -rm $(shell find -name '*.d') 59 | -rm -r $(DESTDIR)$(INCLUDEDIR)/userspace/ 60 | 61 | install: install-headers install-libs 62 | 63 | install-headers: 64 | mkdir -p $(DESTDIR)$(INCLUDEDIR)/userspace 65 | cp -R --preserve=timestamps libc/include/. $(DESTDIR)$(INCLUDEDIR)/userspace/. 66 | 67 | install-libs: $(BINARIES) 68 | mkdir -p $(DESTDIR)$(LIBDIR) 69 | cp $(BINARIES) $(DESTDIR)$(LIBDIR) 70 | --------------------------------------------------------------------------------