├── .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 |
3 |
4 |
5 | # RocketOS
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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