├── .circleci └── config.yml ├── .config ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── pull_request_template.md ├── .gitignore ├── CHANGELOG.md ├── Kconfig ├── LICENSE ├── Makefile ├── README.md ├── docs ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── arch.md ├── arch │ ├── aarch64 │ │ ├── rpi4.jpg │ │ └── rpi4.md │ ├── new-arch │ │ ├── Making-A-Console-Driver.md │ │ └── Making-A-New-Arch.md │ └── x86 │ │ └── pc.md ├── drivers │ ├── clock │ │ ├── i8254.md │ │ └── rtc-cmos.md │ └── console │ │ ├── 16550_uart.md │ │ └── vga.md ├── index.md ├── make.md └── roadmap.md ├── rpi4.config ├── scripts ├── common.ld ├── grub-isocreate.sh ├── helper.mk ├── rpi4-isocreate.sh ├── target-hosted.mk ├── target-rpi4.mk └── target-x86.mk ├── src ├── adt │ ├── Makefile │ ├── bitmap.c │ ├── buddy.c │ ├── ringbuf.c │ └── testing │ │ ├── Makefile │ │ └── test_ringbuf.c ├── arch │ ├── Kconfig │ ├── rpi4 │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── atomic.S │ │ ├── boot.S │ │ ├── bringup.c │ │ ├── hal │ │ │ ├── Makefile │ │ │ └── console.c │ │ └── link.ld │ └── x86 │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── bringup.c │ │ ├── free_memory.c │ │ ├── gdt.c │ │ ├── hal │ │ ├── Makefile │ │ ├── console.c │ │ └── timekeeping.c │ │ ├── idt.c │ │ ├── include │ │ ├── gdt.h │ │ └── idt.h │ │ ├── irq.c │ │ ├── ivt.s │ │ ├── link.ld │ │ ├── multiboot.s │ │ ├── ports.c │ │ ├── start.s │ │ └── vmm.c ├── core │ ├── Makefile │ ├── devices.c │ ├── early_pmm.c │ ├── hal.c │ ├── kmain.c │ ├── locking.c │ ├── main.c │ ├── resource.c │ └── testing │ │ ├── Makefile │ │ └── interrupt_test.c ├── drivers │ ├── Kconfig │ ├── base │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── bcm2711_gpio.c │ │ ├── include │ │ │ └── bcm2711_gpio.h │ │ └── qemu_shutdown.c │ ├── clock │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── i8254.c │ │ ├── i8254_test.c │ │ ├── include │ │ │ ├── i8254.h │ │ │ └── rtc_cmos.h │ │ └── rtc-cmos.c │ ├── console │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── hosted_console.c │ │ ├── include │ │ │ └── vga.h │ │ ├── serial │ │ │ ├── 16550_uart.c │ │ │ ├── Kconfig │ │ │ ├── Makefile │ │ │ └── include │ │ │ │ └── 16550_uart.h │ │ └── vga_console.c │ ├── framebuffer │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── include │ │ │ └── vga.h │ │ ├── vga.c │ │ └── vga_fonts.c │ └── irqchip │ │ ├── 8259_pic.c │ │ ├── Kconfig │ │ ├── Makefile │ │ ├── include │ │ └── 8259_pic.h │ │ └── irqchip.c ├── include │ ├── adt │ │ ├── bitmap.h │ │ ├── buddy.h │ │ └── ringbuf.h │ ├── arch │ │ ├── hosted │ │ │ └── hal.h │ │ ├── rpi4 │ │ │ ├── hal.h │ │ │ └── regs.h │ │ └── x86 │ │ │ ├── hal.h │ │ │ ├── mmap.h │ │ │ └── regs.h │ ├── assert.h │ ├── errno.h │ ├── math.h │ ├── stdio.h │ ├── stdlib.h │ ├── string.h │ ├── sys │ │ ├── device.h │ │ ├── hal.h │ │ ├── interrupts.h │ │ ├── irqchip.h │ │ ├── mmap.h │ │ ├── multiboot.h │ │ ├── resource.h │ │ ├── testing.h │ │ └── timekeeping.h │ └── types.h ├── libc │ ├── Kconfig │ ├── Makefile │ ├── math.c │ ├── stdio.c │ └── string.c ├── subsys │ ├── Kconfig │ ├── Makefile │ └── kernel_console.c ├── test │ ├── Kconfig │ ├── Makefile │ └── testing.c └── third_party │ └── unity │ ├── LICENSE.txt │ ├── include │ ├── unity.h │ ├── unity_config.h │ ├── unity_fixture.h │ ├── unity_fixture_internals.h │ ├── unity_fixture_malloc_overrides.h │ └── unity_internals.h │ ├── unity.c │ └── unity_fixture.c └── x86.config /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Use the latest 2.1 version of CircleCI pipeline process engine. 2 | # See: https://circleci.com/docs/2.0/configuration-reference 3 | version: 2.1 4 | 5 | # Define a job to be invoked later in a workflow. 6 | # See: https://circleci.com/docs/2.0/configuration-reference/#jobs 7 | jobs: 8 | build: 9 | parameters: 10 | platform: 11 | type: string 12 | environment: 13 | PLATFORM: << parameters.platform >> 14 | docker: 15 | - image: primis11/gcc-cross:latest 16 | steps: 17 | - checkout 18 | - run: 19 | name: "Compilation" 20 | command: | 21 | cp $PLATFORM.config .config 22 | make 23 | - run: 24 | name: "Persist Artifact" 25 | working_directory: ~/build 26 | command: | 27 | gzip ~/project/build-$PLATFORM/apollo.iso 28 | cp ~/project/build-$PLATFORM/apollo.iso.gz $PLATFORM.iso.gz 29 | - persist_to_workspace: 30 | root: ~/build 31 | paths: 32 | - . 33 | - store_artifacts: 34 | path: ~/build/<< parameters.platform >>.iso.gz 35 | 36 | release: 37 | docker: 38 | - image: cimg/go:1.17.5 39 | steps: 40 | - attach_workspace: 41 | at: ~/build 42 | - checkout 43 | - run: 44 | name: Install Github Release Tool 45 | command: "go get github.com/tcnksm/ghr" 46 | - run: 47 | name: Generate Release Notes 48 | command: | 49 | FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD) 50 | GIT_TAGS=($(git tag -l --sort=-version:refname)) 51 | LATEST_TAG=${GIT_TAGS[0]} 52 | PREVIOUS_TAG=${GIT_TAGS[1]:-${FIRST_COMMIT}} 53 | COMMITS=$(git log $PREVIOUS_TAG..$LATEST_TAG --pretty=format:"%H") 54 | RELEASE_NOTES="${LATEST_TAG}\n" 55 | for COMMIT in $COMMITS; do 56 | SUBJECT=$(git log -1 ${COMMIT} --pretty=format:"%s") 57 | PULL_REQUEST_SUBJECT=$(echo -n $SUBJECT | grep -Eo "Merge pull request #[0-9]+" || true) 58 | if [[ $PULL_REQUEST_SUBJECT ]]; then 59 | PULL_REQUEST_NUM=${PULL_REQUEST_SUBJECT#"Merge pull request #"} 60 | DESCRIPTION=$(git log -1 ${COMMIT} --pretty=format:"%b" | sed -E 's/(\[){0,1}GOV\-[0-9]+(\]){0,1} *//') 61 | RELEASE_NOTES+='\n' 62 | RELEASE_NOTES+=" - #$PULL_REQUEST_NUM: $DESCRIPTION" 63 | fi 64 | done 65 | echo -e $RELEASE_NOTES > release_notes.md 66 | git diff $PREVIOUS_TAG $LATEST_TAG CHANGELOG.md | tail -n+5 | grep ^+ | cut -c 2- >> release_notes.md 67 | cat release_notes.md 68 | - run: 69 | name: Publish GitHub Release 70 | command: | 71 | ghr --token $GITHUB_TOKEN \ 72 | --username $CIRCLE_PROJECT_USERNAME \ 73 | --repository $CIRCLE_PROJECT_REPONAME \ 74 | --commitish $CIRCLE_SHA1 \ 75 | --name $(git describe --tags --abbrev=0) \ 76 | --body "$(cat release_notes.md)" \ 77 | --replace $(git describe --tags --abbrev=0) ~/build 78 | 79 | # Invoke jobs via workflows 80 | # See: https://circleci.com/docs/2.0/configuration-reference/#workflows 81 | workflows: 82 | build-workflow: 83 | jobs: 84 | - build: 85 | filters: 86 | tags: 87 | only: /.*/ 88 | matrix: 89 | parameters: 90 | platform: 91 | - x86 92 | - rpi4 93 | - release: 94 | requires: 95 | - build 96 | filters: 97 | branches: 98 | ignore: /.*/ 99 | tags: 100 | only: /^v.*/ 101 | -------------------------------------------------------------------------------- /.config: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Apollo Kernel Configuration 4 | # 5 | 6 | # 7 | # Architecture 8 | # 9 | CONFIG_TARGET="x86" 10 | CONFIG_X86_BASE=y 11 | 12 | # 13 | # Subsystems 14 | # 15 | CONFIG_TIMEKEEPING=y 16 | CONFIG_CONSOLE=y 17 | CONFIG_FRAMEBUFFER=y 18 | CONFIG_IRQ=y 19 | # CONFIG_BASE_SYSTEM is not set 20 | 21 | # 22 | # Drivers 23 | # 24 | 25 | # 26 | # Timekeeping 27 | # 28 | CONFIG_CLOCK_RTC_CMOS=y 29 | CONFIG_CLOCK_8254=y 30 | 31 | # 32 | # Console Drivers 33 | # 34 | CONFIG_CONSOLE_VGA=y 35 | CONFIG_CONSOLE_SERIAL_16550_UART=y 36 | 37 | # 38 | # IRQ Chips 39 | # 40 | CONFIG_IRQCHIP_8259=y 41 | 42 | # 43 | # Framebuffer Drivers 44 | # 45 | CONFIG_FRAMEBUFFER_VGA=y 46 | CONFIG_LIBC=y 47 | CONFIG_LIBC_MATH=y 48 | CONFIG_LIBC_STDIO=y 49 | CONFIG_LIBC_STRING=y 50 | # CONFIG_TESTING is not set 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: primis 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 4. See error 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | If applicable, also try to get a dump of CPU registers 24 | 25 | **Environment (please complete the following information):** 26 | - Machine type: [e.g. Baremetal CPU type, qemu, virtualbox, etc] 27 | - Version [e.g. 0.1.0] 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature Request]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | (Thanks for sending a pull request! Please make sure you click the link above to view the contribution guidelines, then fill out the blanks below.) 2 | 3 | What does this implement/fix? Explain your changes. 4 | --------------------------------------------------- 5 | … 6 | 7 | Does this close any currently open issues? 8 | ------------------------------------------ 9 | … 10 | 11 | Any other comments? 12 | ------------------- 13 | … 14 | 15 | Where has this been tested? 16 | --------------------------- 17 | **Platform:** … 18 | **Target Platform:** .. 19 | **Tool-chain version:** .. 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User Setting files 2 | .vscode*/ 3 | 4 | # Prereq files 5 | *.d 6 | 7 | # Object Files 8 | *.o 9 | 10 | # Misc 11 | *.patch 12 | 13 | # The build trees 14 | build*/ 15 | html*/ 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 4 | and this project adheres to 5 | [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ### Added 10 | - Documentation for existing Code 11 | - Spinlock Support 12 | 13 | ### Removed 14 | - Remove `make doc` functionality. 15 | - Removal of unused linker sections 16 | - Removal of code to handle c++ ctors (we're not using them) 17 | 18 | ### Changed 19 | - Rewrite of docs/ subdirectory 20 | - Rewrite of linker files (Fixes gcc warning) 21 | - Move "modules" & "drivers" sections to ".modules" & ".drivers" respectively 22 | 23 | 24 | ## [0.0.5] - 2022-09-10 25 | ### Added 26 | - Raspberry Pi 4 Support (In Progress) 27 | - Driver Subsystem 28 | - Resource Management API 29 | - CircleCI Artifacts and Releases 30 | 31 | ### Changed 32 | - Serial driver (16550) rewrite 33 | - Change existing driver code to be platform agnostic 34 | - Makefile Changes to facilitate multi-arch 35 | - Markdown to HTML Generation with `markdown` instead of `pandoc` 36 | 37 | ### Bugfixes 38 | - x86 IDT code working properly 39 | 40 | ## [0.0.4] - 2022-07-30 41 | ### Added 42 | - Fancy VGA support (8x8 Font) 43 | - iso creation in makefile 44 | - kmain() Now displays system information 45 | - `debug=y` parsing turns on kernel debugging messages 46 | 47 | ### Changed 48 | - HAL: `get_num_processors()` now reports 1 as default 49 | - Standardized naming of kernel (always kernel.mod now) 50 | - VGA Console code cleanup 51 | - IDT Triple fault fix 52 | 53 | ### Removed 54 | - pre-compiled binaries and images from bin/ directory 55 | 56 | ## [0.0.3] - 2022-04-30 57 | ### Added 58 | - ipxe iso image 59 | - Kconfig files 60 | - Modular Makefile system 61 | - Qemu-specific shutdown driver 62 | - Shutdown function in HAL 63 | ### Changed 64 | - Rewrote Multiboot code 65 | - Modified Code Struture 66 | - Changed build system entirely 67 | 68 | ## [0.0.2] - 2018-12-12 69 | ### Added 70 | - MIT License tag for README.md 71 | - Testing autoload just like modules 72 | - Tests for Ringbuffer and Interrupts 73 | - Menu for iPXE boot 74 | ### Changed 75 | - Moved Testing into a seperate directory 76 | - Testing is seamlessly ran now thanks to core/testing.c and macro magic 77 | 78 | ### Changed 79 | - Changelog spec to 1.0.0 from 0.3.0. (Visibility changes) 80 | ## [0.0.1] - 2018-12-08 81 | ### Added 82 | - Semantic Versioning starting at 0.0.1 83 | - This CHANGELOG file 84 | - CONTRIBUTING.md for contributors to follow our guides 85 | 86 | ## [0.0.0] - Before 2018-12-08 87 | This is documenting the state of the kernel before CHANGELOG was implemented 88 | 89 | ### Added 90 | - Makefile system that allows for multiple platforms and targets 91 | - x86 target for kernel 92 | - Drivers for PIC, PIT, UARTS, and a VGA Text Console 93 | - Modules for Interrupts, the GDT, and I/O ports 94 | - hosted target for kernel 95 | - Driver for Text Console 96 | - Core System 97 | - Module auto loading system 98 | - Hardware Abstraction Layer API declaration 99 | - Console Driver 100 | - Testing System implemented by port of 101 | [Unity](http://www.throwtheswitch.org/unity) 102 | - Standard Library 103 | - Implemented most of `string.c` 104 | - Implemented `printf()`, `putchar()`, and `puts()` from stdio 105 | - Abstract Data Types 106 | - Ring Buffer 107 | 108 | [Unreleased]: https://github.com/primis/apollo/compare/v0.0.5...HEAD 109 | [0.0.5]: https://github.com/primis/apollo/compare/0.0.4...v0.0.5 110 | [0.0.4]: https://github.com/primis/apollo/compare/0.0.3...0.0.4 111 | [0.0.3]: https://github.com/primis/apollo/compare/0.0.2...0.0.3 112 | [0.0.2]: https://github.com/primis/apollo/compare/0.0.1...0.0.2 113 | [0.0.1]: https://github.com/primis/apollo/compare/0.0.0...0.0.1 114 | [0.0.0]: https://github.com/primis/apollo/releases/tag/0.0.0 115 | -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | mainmenu "Apollo Kernel Configuration" 2 | 3 | 4 | source "src/arch/Kconfig" 5 | 6 | source "src/subsys/Kconfig" 7 | 8 | source "src/drivers/Kconfig" 9 | 10 | source "src/libc/Kconfig" 11 | 12 | source "src/test/Kconfig" 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Apollo Developers 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ############################# 2 | ## Apollo Project Makefile ## 3 | ############################# 4 | .PHONY: all clean link iso 5 | 6 | # Git revision number 7 | GIT_REV != git rev-parse --short HEAD 2>/dev/null |tr '[:lower:]' '[:upper:]' 8 | 9 | INCLUDEDIR != find src -type d -name "include" -printf "-I%p " 10 | 11 | include .config 12 | TARGETL != echo $(CONFIG_TARGET) | tr '[:upper:]' '[:lower:]' 13 | BUILD := build-$(TARGETL) 14 | BIN := kernel.mod 15 | include $(shell pwd)/scripts/target-$(TARGETL).mk 16 | 17 | WARNINGS := -Wall -Wextra -Wno-unused-parameter 18 | CFLAGS := $(INCLUDEDIR) -fbuiltin -DGITREV="\"$(GIT_REV)\"" 19 | 20 | HELPER_MK := $(shell pwd)/scripts/helper.mk 21 | MK_FLAGS := --no-print-directory -s 22 | SUBDIRS := $(shell find . -name Makefile) 23 | SUBDIRS := $(patsubst %Makefile,%,$(SUBDIRS)) 24 | SUBDIRS := $(patsubst %./,%,$(SUBDIRS)) 25 | OBJECTS := $(shell for dir in $(SUBDIRS); do\ 26 | TOP_DIR=`pwd` $(MAKE) $(MK_FLAGS) -f $(HELPER_MK) -C $$dir;\ 27 | done;) 28 | 29 | ifeq ($(CONFIG_TESTING),y) 30 | CFLAGS += -DTEST_HARNESS=1 31 | endif 32 | 33 | OBJECTS := $(patsubst %.o,$(BUILD)/%.o,$(OBJECTS)) 34 | SRCDIR != find src/ -type d | tr '\n' ' ' 35 | 36 | all: $(BUILD)/apollo.iso 37 | 38 | # C files are compiled universally the same, assembler targets are defined in 39 | # The target specific makefiles 40 | $(BUILD)/%.c.o: %.c 41 | @printf "\033[1mCC\033[0m $<\n" 42 | @mkdir -p $(@D) 43 | @$(CC) -c $< -o $@ $(CFLAGS) $(TARGET_CFLAGS) $(WARNINGS) 44 | 45 | $(BUILD)/apollo/$(BIN): $(OBJECTS) 46 | @printf "\033[1mLINK\033[0m $@\n" 47 | @mkdir -p $(BUILD)/apollo 48 | @$(CC) $(LDFLAGS) $(TARGET_LDFLAGS) -o $(BUILD)/apollo/$(BIN) $(OBJECTS) 49 | 50 | link: $(BUILD)/apollo/$(BIN) 51 | 52 | clean: 53 | @printf "\033[1mCLEAN\033[0m \n" 54 | @find . -type d -name "build*" -exec rm -rf {} + 55 | @rm -rf $(HTMLDIR) 56 | 57 | menuconfig: 58 | @kconfig-mconf Kconfig 59 | 60 | iso: $(BUILD)/apollo.iso 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The Apollo Project 2 | ================= 3 | _(C) 2013 - 2024 Primis Computers (Allie Sargente et al)_ 4 | 5 | Requirements: 6 | -------------------------------------------------- 7 | 8 | X86 requirements are 9 | * [GNU Make](https://www.gnu.org/software/make/) (Or Compatible) 10 | * [NASM](https://www.nasm.us/), The Netwide Assembler 11 | * [GCC cross compiler](https://wiki.osdev.org/GCC_Cross-Compiler) targeting 12 | i586-elf or i686-elf 13 | * [grub-mkrescue](https://manpages.ubuntu.com/manpages/bionic/man1/grub-mkrescue.1.html) 14 | 15 | RPI4 requirements are 16 | * [GNU Make](https://www.gnu.org/software/make/) (Or Compatible) 17 | * [GCC cross compiler](https://wiki.osdev.org/GCC_Cross-Compiler) targeting 18 | i586-elf or i686-elf 19 | * [MTools](https://www.gnu.org/software/mtools/) 20 | 21 | Optionally, for customizing builds, any application capable of reading Kconfig 22 | files will work. If on debian based systems, the package `kconfig-frontends` 23 | is suggested. 24 | 25 | The kernel is written mostly in ANSI-C, with assembly only being used on arch 26 | specific bringup. 27 | 28 | This software is licensed under the MIT License. 29 | (see License) 30 | 31 | Supported Architectures: 32 | -------------------------------------------------- 33 | - IBM-PC Compatible Pentium+ PC's (x86) 34 | - Raspberry Pi Model 4B (rpi4) 35 | 36 | Notable Features to Consider: 37 | -------------------------------------------------- 38 | This kernel is in development, and is therefore subject to major changes. 39 | The API is in a state of flux. If developing applications, stick to 40 | functions from the standard c library. All others may be deprecated / 41 | removed without notice. 42 | 43 | Running 44 | -------------------------------------------------- 45 | All targets generate a bootable apollo.iso file. 46 | This file can be used with a virtual machine, burnt to a flash drive or other 47 | bootable media. Please note that for some targets, the iso file is actually a 48 | generic image file, and should not be burned to a CD (for example, for the rpi4) 49 | 50 | Configuration 51 | -------------------------------------------------- 52 | Once all the pre-requisites software has been aquired for a specific 53 | archetecture, copy the architecture .config file to `.config` at the root of the 54 | project. The provided configuration files are examples only, and can be 55 | customized by running `make menuconfig` if you have a `kconfig` editor installed 56 | on your machine. Debian provides a package called `kconfig-frontends` that fits 57 | this role. You can also edit the .config file by hand, assuming you know what 58 | kernel compilation options you desire. 59 | 60 | Building 61 | -------------------------------------------------- 62 | You can build the kernel simply by `make`. 63 | After compilation is done, a file called `apollo.iso` will be generated within 64 | the build directory. 65 | 66 | History: 67 | -------------------------------------------------- 68 | This kernel descends from several failed kernel projects; 69 | * ScorchOS; by Bob Moss and Allie Sargente. Circa 2010 70 | * Mercury/SaturnOS; by Brandon Cornell and Allie Sargente. Circa 2012 71 | * Apollo Kernel Project; Circa 2009-2011. Allie Sargente. 72 | 73 | This kernel takes base code from Bkerndev and James Molloy's Tutorials: 74 | * http://www.osdever.net/bkerndev/Docs/title.htm 75 | * http://www.jamesmolloy.co.uk/tutorial_html/index.html 76 | 77 | Greets to the OSDev Community at OSdev.org. 78 | 79 | -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | allie@sargente.org. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you 4 | wish to make via an issue, email to the maintainers, or any other method 5 | with the maintainers of this repository before making a change. 6 | 7 | Please note we have a code of conduct, please follow it in all your 8 | interactions with the project. 9 | 10 | ## Submitting an issue. 11 | 12 | 1. Create a clear and concise title for your issue. 13 | 2. Issue should include a concise summary. Include a screenshot, output, or 14 | relevant data for the issue. 15 | 3. Include steps to reproduce the issue in a step by step text process. 16 | 4. Any other relevant information to the issue being reported. Explain why 17 | you consider this an issue. 18 | 19 | ## Pull Request Process 20 | 21 | 1. Update CHANGELOG.md with details of the changes implemented. This includes 22 | any tests created as well. 23 | 2. Don't break any old tests or functionality when updating unless the test has 24 | been determined to be wrong. (requires discussion beforehand) 25 | 3. Add tests for any new functionality in the appropriate `test` folder 26 | in the source tree. Tests should be comprehensive to make sure the kernel 27 | does not lose stability. 28 | 4. Any commits *must* be gpg signed with a key associated with your account. 29 | This keeps a chain of custody to allow proper back tracking of commits. 30 | 5. Pull requests should be flattened into a single commit where relevant. 31 | 6. Recognize that all code will be considered under the license found in 32 | LICENSE.md, any code which cannot be legally distributed under this license 33 | will not be considered for pull requests. 34 | 35 | ## Coding style 36 | All code should follow the standard coding style enforced herein. 37 | 38 | 1. 80 column lines. This should be practiced as a semi-hard rule. If there are 39 | commands that break this, consider rewriting them, or splitting them between 40 | two lines if possible. 41 | 2. K&R style bracing should be used consistently. 42 | 3. Comments should be used, but not overused for obvious content. Comments 43 | should use the c++ `//` style except for file descriptors at the beginning 44 | of each file, and function description blocks, following the doxygen 45 | standard. Comments should not include any inappropriate or offensive 46 | language. 47 | 4. Avoid monolithic functions. Indented code should never drop below 4 indents. 48 | Consider exposing that to a separate function or rewriting the logic at that 49 | point. 50 | 51 | ## Code of Conduct 52 | 53 | ### Our Pledge 54 | 55 | In the interest of fostering an open and welcoming environment, we as 56 | contributors and maintainers pledge to make participation in our project and 57 | community a harassment-free zone for everyone, regardless of age, disability, 58 | ethnicity, gender identity and expression, level of experience, nationality, 59 | appearance, race, religion, or sexual identify and orientation. Please note that 60 | this is not an exhaustive list. Any harassment of any kind will not be allowed 61 | or tolerated. 62 | 63 | ### Our Standards 64 | Examples of behavior that contributes to creating a positive environment 65 | include: 66 | 67 | * Using welcoming and inclusive language 68 | * Being respectful of differing viewpoints and experiences 69 | * Gracefully accepting constructive criticism 70 | * Focusing on what is best for the community 71 | * Showing empathy towards other community members 72 | 73 | Examples of unacceptable behavior by participants include: 74 | 75 | * The use of sexualized language or imagery and unwelcome sexual attention or 76 | advances 77 | * Trolling, insulting/derogatory comments, and personal or political attacks 78 | * Public or private harassment 79 | * Publishing others' private information, such as a physical or electronic 80 | address, without explicit permission 81 | * Other conduct which could reasonably be considered inappropriate in a 82 | professional setting 83 | 84 | ### Our Responsibilities 85 | 86 | Project maintainers are responsible for clarifying the standards of acceptable 87 | behavior and are expected to take appropriate and fair corrective action in 88 | response to any instances of unacceptable behavior. 89 | 90 | Project maintainers have the right and responsibility to remove, edit, or 91 | reject comments, commits, code, wiki edits, issues, and other contributions 92 | that are not aligned to this Code of Conduct, or to ban temporarily or 93 | permanently any contributor for other behaviors that they deem inappropriate, 94 | threatening, offensive, or harmful. 95 | 96 | ### Scope 97 | 98 | This Code of Conduct applies both within project spaces and in public spaces 99 | when an individual is representing the project or its community. Examples of 100 | representing a project or community include using an official project e-mail 101 | address, posting via an official social media account, or acting as an appointed 102 | representative at an online or offline event. Representation of a project may be 103 | further defined and clarified by project maintainers. 104 | 105 | ### Enforcement 106 | 107 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 108 | reported by contacting the project team at allie@sargente.org. All complaints 109 | will be reviewed and investigated and will result in a response that is deemed 110 | necessary and appropriate to the circumstances. The project team is obligated to 111 | maintain confidentiality with regard to the reporter of an incident. Further 112 | details of specific enforcement policies may be posted separately. 113 | 114 | Project maintainers who do not follow or enforce the Code of Conduct in good 115 | faith may face temporary or permanent repercussions as determined by other 116 | members of the project's leadership. 117 | 118 | ### Attribution 119 | 120 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 121 | version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 122 | 123 | [homepage]: http://contributor-covenant.org 124 | [version]: http://contributor-covenant.org/version/1/4/ 125 | -------------------------------------------------------------------------------- /docs/arch.md: -------------------------------------------------------------------------------- 1 | Architectures 2 | ============= 3 | 4 | Tier 1 Support 5 | -------------- 6 | Tier 1 support architectures are platforms which active development is 7 | considered vital to the movement of progress of the kernel. 8 | 9 | * [x86-pc](arch/x86/pc) 10 | * [Raspberry Pi 4](arch/aarch64/rpi4) 11 | 12 | Tier 2 Support 13 | -------------- 14 | Tier 2 support architectures are platforms which develop on their own time. 15 | These are not needed to be feature complete for a release of the kernel. 16 | 17 | * There are no Tier 2 Support architectures currently 18 | 19 | Tier 3 Support 20 | -------------- 21 | Tier 3 support architectures are platforms which are "on life support" so to 22 | speak. These are architectures which aren't currently compiling and have had no 23 | progress in that direction in over a year. 24 | 25 | * There are no Tier 3 Support architectures currently 26 | 27 | Create a New Architecture 28 | ------------------------- 29 | * If there is a platform in which you want added to the apollo kernel support list 30 | please follow the [Create Your Own](arch/new-arch/Making-A-New-Arch) 31 | Architecture guide. 32 | -------------------------------------------------------------------------------- /docs/arch/aarch64/rpi4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/primis/Apollo/974f96b6676829fd683fff526895861cabe27b5c/docs/arch/aarch64/rpi4.jpg -------------------------------------------------------------------------------- /docs/arch/aarch64/rpi4.md: -------------------------------------------------------------------------------- 1 | Raspberry Pi 4 2 | ============== 3 | 4 | ![Raspberry Pi 4](rpi4.jpg) 5 | 6 | Introduction 7 | ------------ 8 | 9 | The Rasberry Pi 4 board is based on the BCM2711 System on a chip. It features 10 | a 1.5 GHz 64-bit quad core ARM Cortex-A72 processor, and 1-8 gigabytes of ram 11 | depending on the model. 12 | There are currently two Models being produced, The model B (shown above), and 13 | the mode 400, which is built into a keyboard case. 14 | 15 | 16 | Availible Drivers 17 | ----------------- 18 | 19 | * [16550 Compatible UART](../../../drivers/console/16550_uart/) 20 | - This is available via the GPIO header's UART0 on pins 8 and 10 21 | 22 | -------------------------------------------------------------------------------- /docs/arch/new-arch/Making-A-Console-Driver.md: -------------------------------------------------------------------------------- 1 | Creating a Console Driver 2 | ========================== 3 | 4 | Introduction 5 | ------------- 6 | One of the essential parts of the boot process is a console terminal driver. 7 | This driver allows the kernel to output early debug information before the 8 | system comes online. The console driver is part of the kernel. The kernel 9 | defines access to logging functions but it is up to the architecture to create 10 | a console driver and initialize it. 11 | 12 | Initialization 13 | --------------- 14 | Calling `register_console()` is how you register a new console with the kernel. 15 | The only functions required to implement are `init()` and `write()`. 16 | 17 | Control Charecters 18 | ------------------- 19 | The kernel internally accepts ascii data for logging, but it also uses several 20 | ASCII control codes which should be implemented by your console: 21 | 22 | \t Tab. This should move the cursor to the next tab indent. 23 | We recommend using 8 space tabs, though this is left up to 24 | the implementation. 25 | 26 | \n Newline. This should drop to a new line, and also perform a 27 | carriage return back to Column 0. 28 | 29 | \f Form feed. This should either clear the screen, or on a non-screen 30 | console, create some sort of page break like a horizontal rule 31 | does in html. 32 | 33 | \b Backspace. This should move the cursor backwards one character but not null 34 | out the character glyph at that location. 35 | 36 | Color Codes 37 | ----------- 38 | Parts of the kernel use ANSI escape codes for colors. If your console supports 39 | color codes, try to support them. If your console does not, these codes may need 40 | to be stripped out of the data stream. 41 | -------------------------------------------------------------------------------- /docs/arch/new-arch/Making-A-New-Arch.md: -------------------------------------------------------------------------------- 1 | Apollo Architectures : Creating a New one 2 | ========================================== 3 | 4 | Introduction 5 | ------------ 6 | 7 | So You've decided to create a new architecture support for the Apollo kernel? 8 | There is a few tasks to complete on your platform before Apollo will happily 9 | run on top of it. 10 | 11 | Prerequisites 12 | ------------- 13 | 14 | In order for Apollo to work happily on your platform, it needs to have a few 15 | items availible. 16 | 17 | * Your platform has to be a 32 or 64 bit system. Apollo won't support 16 bit 18 | without massive core arch change. 19 | * A console device of some kind for boot messages, be it serial, a screen 20 | buffer, or even a line printer. 21 | * Interrput capability. Without this, the system can't do syscalls from 22 | usermode. 23 | * A timer. The kernel uses this for scheduling, and timekeeping. High 24 | precision isn't needed, just at least 1KHz. 25 | 26 | Boot time 27 | --------- 28 | It is a requirement that you set up your system into a well known state. 29 | In your start function you should set up a stack, preferably at least 4k large. 30 | It is also start's task to set up the stack, stop interrupts, and call main. 31 | 32 | The stack should be aligned to a 32 byte boundary, in accordance to the SYSV 33 | ABI. 34 | 35 | Drivers To Implement 36 | -------------------- 37 | 38 | After main has been called, Apollo enumerates all modules compiled within it and 39 | runs their init functions. The bare minimum a platform should support is: 40 | 41 | * A [Console Module](Making-A-Console-Driver.html), implementing a console 42 | driver. This device used to output the status of the kernel during bootup. 43 | 44 | * An interrupt vector module. This driver should expose a function for creating 45 | interrupt functions for syscalls. The actual syscall interface is handled 46 | by the kernel. 47 | 48 | * A time keeping module. This should be a system timer that exposes functions to 49 | help with scheduling such as alarm() and getTicks(). 50 | 51 | * Memory handler driver. This driver basically should give the kernel 4k pages 52 | when requested. This is used internally to power malloc(). 53 | -------------------------------------------------------------------------------- /docs/arch/x86/pc.md: -------------------------------------------------------------------------------- 1 | x86 PC 2 | ====== 3 | 4 | Introduction 5 | ------------ 6 | 7 | The IBM compatible PC has been around since the 80's. In respect to the Apollo 8 | kernel, this architecture specifically refers to 32 bit processors. Apollo 9 | currently targets i686+ processors. This places a lower bound on machines to 10 | around 1995 with the Pentium Pro. 11 | 12 | Standard Porting Base 13 | --------------------- 14 | Due to the ubiquity of this platform, it has been determined that the Apollo 15 | kernel shall be developed with it as it's porting base. This makes the x86 PC 16 | architecture a Tier 1 supported platform. 17 | 18 | Availible Drivers 19 | ----------------- 20 | 21 | * [VGA Console](../../../drivers/console/vga/) 22 | * [16550 Compatible UART](../../../drivers/console/16550_uart/) 23 | * [Real Time Clock](../../../drivers/clock/rtc-cmos) 24 | * [Intel 8254 PIC](../../../drivers/clock/i8254) 25 | -------------------------------------------------------------------------------- /docs/drivers/clock/i8254.md: -------------------------------------------------------------------------------- 1 | Intel Programmable Interrupt Timer 2 | ================================== 3 | 4 | Introduction 5 | ------------ 6 | The Intel i8254 is a chip that has been included in every IBM PC compatible 7 | since the original PC. It contains 3 channels which can generate pulses based 8 | on programming. Traditionally on a PC, Channel 0 is connected to an IRQ, 9 | Channel 1 is connected to the PC Speaker, and Channel 2 was for DRAM refresh. 10 | Channel 2 is not connected nor implemented in most modern PC's. 11 | 12 | This driver contains configuration of the chip only. It does not handle 13 | interrupts or controlling of the PC Beeper. 14 | 15 | Modes 16 | ----- 17 | The i8254 channels support 5 modes of operation: 18 | 19 | | Mode | Description 20 | |------|-------------- 21 | | 0 | Interrupt on Terminal count (Use internal counter to trigger pulse) 22 | | 1 | Hardware One Shot (Gate sets trigger, timer goes low for N+1 cycles) 23 | | 2 | Pulse Rate Generator (Generate periodic interrupt) 24 | | 3 | Square Wave (50% duty cycle square wave output) 25 | | 4 | Software triggered strobe (Timer goes low for N+1 cycles after trigger) 26 | 27 | Frequency 28 | --------- 29 | The i8254 Driver uses the `timekeeping_state_t` struct to control the frequency 30 | it is passed as part of the driver initialization. 31 | -------------------------------------------------------------------------------- /docs/drivers/clock/rtc-cmos.md: -------------------------------------------------------------------------------- 1 | CMOS Real Time Clock 2 | ==================== 3 | 4 | Introduction 5 | ------------ 6 | The CMOS RTC driver utilizes the x86 standard real time clock register set. 7 | It exposes an implementation of `get_epoch_time()` for the kernel subsystem. 8 | -------------------------------------------------------------------------------- /docs/drivers/console/16550_uart.md: -------------------------------------------------------------------------------- 1 | 16550 UART 2 | ========== 3 | 4 | Introduction 5 | ------------ 6 | 7 | The 16550 UART is a widely used integrated circuit first released by National 8 | Semiconductor is 1987. Most IBM compatible personal computers have a 16550 9 | compatible serial port, even modern ones via a motherboard header. This makes 10 | it a wonderful debugging interface. 11 | 12 | Raspberry Pi 13 | ------------ 14 | The Raspberry Pi series of single board computers also feature a 16550 15 | *like* miniUART, which is available on the GPIO header. 16 | It does not feature proper full handshaking or many other features, however it 17 | is a compatible enough implementation that the same driver can be used in 18 | the Apollo kernel. 19 | 20 | Baud Rate and Line Discipline 21 | ----------------------------- 22 | The 16550 has a standard maximum baud rate of 115200 bits per second. This is 23 | therefore a very standard baudrate which is compatible with a wide variety of 24 | serial-to-USB adapters, and other RS-232 based equipment. By default, all 25 | platforms default on apollo default to a baud rate of 115200 BPS. 26 | 27 | The line discipline of the 16550 is fixed at 8-N-1 (8 data bits / No parity / 28 | 1 stop bit). This was chosen as it is the most standard line discipline in use 29 | today. 30 | -------------------------------------------------------------------------------- /docs/drivers/console/vga.md: -------------------------------------------------------------------------------- 1 | VGA Console 2 | =========== 3 | 4 | Introduction 5 | ------------ 6 | The VGA console driver is a simple text mode driver that utilizes 80 column 7 | text mode found on VGA hardware. It supports hardware cursor movement, and 8 | several ANSI Escape codes. Of most note is color. 9 | 10 | Screen Appearance 11 | ------------------ 12 | When first initialized, The VGA screen is set with a White-on-Blue text mode, 13 | 80x50 text mode with an 8x8 font. 14 | 15 | Two Drivers in One 16 | ------------------ 17 | As VGA is not only used for text mode, the VGA driver was split between 18 | framebuffer and console. The VGA framebuffer driver handles mode selection, 19 | font switching, and hardware cursor movement. This console driver is only 20 | responsible for text mode operations to the screen. 21 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | Sections 2 | -------- 3 | 4 | - [The Architechture](arch) 5 | - [Drivers](drivers) 6 | - [Compilation](make) 7 | 8 | Introduction 9 | ------------ 10 | The Apollo Project is a hobbyist operating system with the goal to be a 11 | usable tool for developing applications and working with low-level 12 | system interfaces. 13 | 14 | We will take hints from Unix, however will not be another 15 | Unix clone like GNU/Linux. We do not plan on porting any GNU utilities 16 | however we do plan on being self-hosting via a GCC port sometime in the 17 | future. 18 | 19 | The Future 20 | ---------- 21 | [Roadmap](roadmap) 22 | -------------------------------------------------------------------------------- /docs/make.md: -------------------------------------------------------------------------------- 1 | The Makefile 2 | =========== 3 | 4 | Introduction 5 | ---------- 6 | 7 | The Apollo Project uses a makefile build system. This makefile is designed to be 8 | extendable for every archetechture. 9 | 10 | The makefile requires a TARGET be set to compile, otherwise it'll fail. 11 | Current targets are described in the [arch document.](arch) 12 | 13 | Current options for the makefile are: 14 | 15 | * `all` - Comiles the current TARGET. 16 | * `clean` - Removes the object files. 17 | * `iso` - Generate an iso image for the target platform. 18 | * `menuconfig` - Run configuration of the kernel. Requires kconfig be installed 19 | 20 | Each target requires a seperate makefile stub. This has to be in the format 21 | "target-.mk" and has to contain the following: 22 | 23 | ### Variables 24 | * BIN - Binary file name in the format "-sys.mod" 25 | * TARGET_DEFS - Target specific flags for gcc 26 | * TARGET_LDFLAGS - Target specific flags to pass to the linker 27 | * CSOURCES - A list of the C sources. This must also include the variable 28 | $(CSOURCES_TI) which is platform agnostic sources. 29 | 30 | ### Optional additions 31 | * CC - variable containing the name of the c compiler for the platform 32 | * any additional target building (such as target for assembly) 33 | -------------------------------------------------------------------------------- /docs/roadmap.md: -------------------------------------------------------------------------------- 1 | Release Schedule 2 | ================ 3 | 4 | Release 0.1.0 5 | ------------- 6 | *"Zeno's Paradox"* 7 | 8 | - [ ] Multitasking 9 | - [ ] File Handling 10 | - [ ] File System Drivers 11 | - [ ] FAT 12 | - [ ] ISO 9660 13 | - [ ] Hardware Storage Drivers 14 | - [ ] ATA 15 | - [ ] Floppy Disk Controller 16 | - [ ] Basic I/O Support 17 | - [ ] PS/2 Keyboard 18 | - [X] Serial I/O 19 | - [ ] Parallel Port 20 | - [ ] Some Standard Library Implemented 21 | - [ ] All of String.h 22 | - [ ] Memory Allocation 23 | - [ ] All of stdio.h 24 | - [ ] Timekeeping 25 | - [X] Programmable Interval Timer 26 | - [ ] Real-Time Clock 27 | - [ ] Memory Management 28 | - [ ] Heap 29 | - [ ] alloc() 30 | - [ ] free() 31 | - [ ] Virtual Address spaces 32 | - [ ] Paging 33 | - [ ] Inter-Process Communication 34 | - [ ] Message Passing 35 | - [ ] Semaphores 36 | -------------------------------------------------------------------------------- /rpi4.config: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Apollo Kernel Configuration 4 | # 5 | 6 | # 7 | # Architecture 8 | # 9 | CONFIG_TARGET="rpi4" 10 | CONFIG_RPI4_BASE=y 11 | 12 | # 13 | # Subsystems 14 | # 15 | # CONFIG_TIMEKEEPING is not set 16 | CONFIG_CONSOLE=y 17 | # CONFIG_FRAMEBUFFER is not set 18 | # CONFIG_IRQ is not set 19 | CONFIG_BASE_SYSTEM=y 20 | 21 | # 22 | # Drivers 23 | # 24 | 25 | # 26 | # Base System Drivers 27 | # 28 | CONFIG_BCM2711_GPIO=y 29 | 30 | # 31 | # Console Drivers 32 | # 33 | # CONFIG_CONSOLE_VGA is not set 34 | CONFIG_CONSOLE_SERIAL_16550_UART=y 35 | CONFIG_LIBC=y 36 | CONFIG_LIBC_MATH=y 37 | CONFIG_LIBC_STDIO=y 38 | CONFIG_LIBC_STRING=y 39 | # CONFIG_TESTING is not set 40 | -------------------------------------------------------------------------------- /scripts/common.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * Common link file (Things that are shared across all architectures) 5 | */ 6 | 7 | SECTIONS 8 | { 9 | . = INIT_OFFSET; 10 | 11 | .init : 12 | { 13 | PROVIDE (__start = .); 14 | *(.init) 15 | } : init 16 | 17 | .init.bss ALIGN(4096) : 18 | { 19 | *(.init.bss) 20 | } : init.bss 21 | /* Higher half stuff, add 3GB to all addresses below */ 22 | . += VIRT_OFFSET; 23 | 24 | .text ALIGN(4096) : AT(ADDR(.text) - VIRT_OFFSET) 25 | { 26 | *(.mboot) 27 | *(.text .stub .text.* .gnu.linkonce.t.*) 28 | } : text 29 | 30 | .rodata ALIGN(4096) : AT(ADDR(.rodata) - VIRT_OFFSET) 31 | { 32 | *(.rodata .rodata.* .gnu.linkonce.r.*) 33 | } : rodata 34 | 35 | .data ALIGN(4096) : AT(ADDR(.data) - VIRT_OFFSET) 36 | { 37 | *(.data .data.* .gnu.linkonce.d) 38 | } : data 39 | 40 | .structured ALIGN(4096) : AT(ADDR(.structured) - VIRT_OFFSET) 41 | { 42 | PROVIDE( __modules_begin = .); 43 | *(.modules) 44 | PROVIDE (__modules_end = .); 45 | PROVIDE(__drivers_begin = .); 46 | *(.drivers) 47 | PROVIDE(__drivers_end = .); 48 | } : data 49 | 50 | .bss ALIGN(4096) : AT(ADDR(.bss) - VIRT_OFFSET) 51 | { 52 | PROVIDE(__bss_begin = . - VIRT_OFFSET); 53 | *(.bss .bss.* .gnu.linkonce.b.*) 54 | *(COMMON) 55 | PROVIDE(__bss_end = . - VIRT_OFFSET); 56 | PROVIDE(__end = . - VIRT_OFFSET); 57 | } : data 58 | 59 | /* end of kernel symbol */ 60 | __kernel_end = .; 61 | } 62 | 63 | PHDRS 64 | { 65 | init PT_LOAD FLAGS(5); 66 | init.bss PT_LOAD FLAGS(6); 67 | text PT_LOAD FLAGS(5); 68 | rodata PT_LOAD FLAGS(4); 69 | data PT_LOAD FLAGS(6); 70 | } 71 | -------------------------------------------------------------------------------- /scripts/grub-isocreate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | mkdir -p isodir/boot/grub 6 | 7 | cp $1 isodir/boot/kernel.mod 8 | 9 | cat > isodir/boot/grub/grub.cfg << EOF 10 | menuentry "Apollo" { 11 | multiboot /boot/kernel.mod 12 | } 13 | 14 | menuentry "Apollo Debugging" { 15 | multiboot /boot/kernel.mod debug=y 16 | } 17 | EOF 18 | 19 | grub-mkrescue -o apollo.iso isodir 20 | -------------------------------------------------------------------------------- /scripts/helper.mk: -------------------------------------------------------------------------------- 1 | include $(TOP_DIR)/.config 2 | include Makefile 3 | 4 | CUR_DIR := $(shell pwd) 5 | CUR_DIR := $(patsubst $(TOP_DIR)/%,./%, $(CUR_DIR)) 6 | 7 | ifeq ($(CONFIG_TESTING),y) 8 | obj_y += $(test_y) 9 | endif 10 | 11 | obj_y := $(patsubst %,$(CUR_DIR)/%.o,$(obj_y)) 12 | 13 | all: 14 | @echo $(obj_y) 15 | -------------------------------------------------------------------------------- /scripts/rpi4-isocreate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | rpi_url=https://github.com/raspberrypi/firmware/blob/master/boot 5 | rpi_boot_files=("start4.elf" "bootcode.bin" "fixup4.dat" "bcm2711-rpi-4-b.dtb") 6 | 7 | mkdir -p isodir 8 | 9 | cp $1 isodir/kernel8.img 10 | 11 | # Grab Raspberry Pi 4 required boot files 12 | for FILE in ${rpi_boot_files[@]}; do 13 | if [ ! -f isodir/$FILE ]; then 14 | wget $rpi_url/$FILE\?raw=true -O isodir/$FILE 15 | else 16 | echo "Cached $FILE" 17 | fi 18 | done 19 | 20 | cat > isodir/config.txt << EOF 21 | enable_uart=1 22 | core_freq_min=500 23 | arm_64bit=1 24 | EOF 25 | 26 | cat > isodir/cmdline.txt << EOF 27 | debug=y 28 | EOF 29 | 30 | # Create a 128 Megabyte iso file 31 | dd if=/dev/zero of=apollo.iso bs=1M count=128 32 | # Format it as FAT 33 | mformat -i apollo.iso -v Apollo :: 34 | # Copy all the files in isodir to the iso 35 | for FILE in isodir/*; do 36 | mcopy -i apollo.iso $FILE :: 37 | done 38 | -------------------------------------------------------------------------------- /scripts/target-hosted.mk: -------------------------------------------------------------------------------- 1 | # Hosted Makefile for doing testing on hosted systems 2 | 3 | STRIP := $(shell which strip) 4 | TARGET_DEFS := -DHOSTED=1 5 | 6 | $(BUILD)/%.iso : $(BUILD)/apollo/$(BIN) 7 | @printf "Dummy ISO Creation\n" 8 | @touch $@ 9 | 10 | # That's it! 11 | -------------------------------------------------------------------------------- /scripts/target-rpi4.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 Apollo Developers 2 | # For terms, see LICENSE 3 | # Makefile for Apollo Project 4 | # Target is the Raspberry Pi 4 5 | 6 | # Check for different Cross compilers in reverse order 7 | # We need to make the shell bash for "command -v" to work 8 | SHELL := $(shell which bash) 9 | CC := $(shell command -v aarch64-elf-gcc) 10 | OBJCOPY := $(shell command -v aarch64-elf-objcopy) 11 | 12 | TARGET_CFLAGS := -DRPI4=1 -ffreestanding -nostdlib -O2 13 | TARGET_LDFLAGS ?= -Tsrc/arch/rpi4/link.ld -nostdlib -lgcc -z max-page-size=4096 14 | 15 | $(BUILD)/%.S.o: %.S 16 | @printf "\033[1mAS\033[0m $<\n" 17 | @mkdir -p $(@D) 18 | @$(CC) $(ASFLAGS) -c $< -o $@ 19 | 20 | $(BUILD)/%.iso: $(BUILD)/apollo/$(BIN) 21 | @$(OBJCOPY) $(BUILD)/apollo/$(BIN) -O binary $(BUILD)/kernel8.img 22 | @cd $(BUILD) && ../scripts/rpi4-isocreate.sh kernel8.img 23 | -------------------------------------------------------------------------------- /scripts/target-x86.mk: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 Apollo Developers 2 | # For terms, see LICENSE 3 | # Makefile for Apollo Project 4 | # Target is x86 5 | 6 | # Check for different Cross compilers in reverse order 7 | # We need to make the shell bash for "command -v" to work 8 | SHELL := $(shell which bash) 9 | STRIP := $(shell which strip) 10 | CC := $(shell command -v i586-elf-gcc) 11 | ifndef CC 12 | CC := $(shell command -v i686-elf-gcc) 13 | endif 14 | 15 | # Fall back case to regular GCC 16 | ifndef CC 17 | CC := gcc 18 | TARGET_LDFLAGS := -m32 -Tsrc/arch/x86/x86-link.ld -nostdlib 19 | $(warning Using default GCC, please consider installing a cross compiler!) 20 | endif 21 | 22 | AS := nasm 23 | ASFLAGS := -felf 24 | TARGET_CFLAGS := -DX86=1 -m32 -masm=intel -ffreestanding -nostdlib -Os 25 | TARGET_LDFLAGS ?= -m32 -Tsrc/arch/x86/link.ld -nostdlib -lgcc 26 | 27 | $(BUILD)/%.s.o: %.s 28 | @printf "\033[1mAS\033[0m $<\n" 29 | @mkdir -p $(@D) 30 | @$(AS) $(ASFLAGS) $< -o $@ 31 | 32 | $(BUILD)/%.iso: $(BUILD)/apollo/$(BIN) 33 | @$(STRIP) -s $< 34 | @cd $(BUILD) && ../scripts/grub-isocreate.sh apollo/$(BIN) 35 | -------------------------------------------------------------------------------- /src/adt/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # ADT Code Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | obj_y := buddy.c bitmap.c ringbuf.c 8 | -------------------------------------------------------------------------------- /src/adt/bitmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2019 Apollo Developers 3 | * For terms, see LICENSE 4 | * bitmap.c - ADT for bitmap storage 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Return index of lsb that is set in byte. byte==0 undefined. 13 | 14 | static int lsb_set(uint8_t byte) 15 | { 16 | int i = 0; 17 | while ((byte & 1) == 0) { 18 | i++; 19 | byte >>= 1; 20 | } 21 | return i; 22 | } 23 | 24 | void bitmap_init(bitmap_t *xb, uint8_t *storage, int64_t max_extent) 25 | { 26 | xb->max_extent = max_extent; 27 | xb->data = storage; 28 | memset(xb->data, 0, max_extent / 8 + 1); 29 | } 30 | 31 | void bitmap_set(bitmap_t *xb, unsigned idx) 32 | { 33 | xb->data[idx/8] |= (1 << (idx % 8)); 34 | assert(bitmap_isset(xb, idx)); 35 | } 36 | 37 | void bitmap_clear(bitmap_t *xb, unsigned idx) 38 | { 39 | xb->data[idx/8] &= ~(1 << (idx % 8)); 40 | } 41 | 42 | int bitmap_isset(bitmap_t *xb, unsigned idx) 43 | { 44 | return (xb->data[idx/8] & (1 << (idx % 8))) ? 1 : 0; 45 | } 46 | 47 | int bitmap_isclear(bitmap_t *xb, unsigned idx) 48 | { 49 | return !bitmap_isset(xb, idx); 50 | } 51 | 52 | int64_t bitmap_first_set(bitmap_t *xb) 53 | { 54 | uint64_t i; 55 | int64_t idx; 56 | for (i = 0; i < (xb->max_extent >> 3) + 1ULL; i++) { 57 | if (xb->data[i] == 0) { 58 | continue; 59 | } 60 | idx = i * 8 + lsb_set(xb->data[i]); 61 | return (idx > xb->max_extent) ? -1 : idx; 62 | } 63 | return -1; 64 | } 65 | -------------------------------------------------------------------------------- /src/adt/buddy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2019 Apollo Developers 3 | * For terms, see LICSENSE 4 | * buddy allocator 5 | * Allocation: log(n) Free: log(n) 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define BUDDY(x) (x ^ 1) 14 | #define INC_ORDER(x) (x << 1) 15 | #define DEC_ORDER(x) (x >> 1) 16 | 17 | size_t buddy_calc_overhead(range_t r) 18 | { 19 | size_t accum = 0; 20 | unsigned i; 21 | for (i = MIN_BUDDY_SZ_LOG2; i <= MAX_BUDDY_SZ_LOG2; i++) { 22 | accum += (r.extent >> i) / 8 + 1; 23 | } 24 | return accum; 25 | } 26 | 27 | int buddy_init(buddy_t *bd, uint8_t *overhead_store, range_t r, int start_freed) 28 | { 29 | unsigned i, nbits; 30 | bd->start = r.start; 31 | bd->size = r.extent; 32 | 33 | for(i = 0; i < NUM_BUDDY_BUCKETS; i++) { 34 | nbits = bd->size >> (MIN_BUDDY_SZ_LOG2 + i); 35 | bitmap_init(&bd->orders[i], overhead_store, nbits); 36 | overhead_store += nbits / 8 + 1; 37 | } 38 | 39 | if (start_freed != 0) { 40 | buddy_free_range(bd, r); 41 | } 42 | return 0; 43 | } 44 | 45 | uint64_t buddy_alloc(buddy_t *bd, unsigned sz) 46 | { 47 | unsigned log_sz = log2_roundup(sz); 48 | if(log_sz > MAX_BUDDY_SZ_LOG2) { 49 | panic("buddy_alloc had request that was too large to handle"); 50 | } 51 | unsigned orig_log_sz = log_sz; 52 | // Search for a free block -- we may need to increase the size of the block 53 | // to find a free one 54 | int64_t idx; 55 | while (log_sz <= MAX_BUDDY_SZ_LOG2) { 56 | idx = bitmap_first_set(&bd->orders[log_sz - MIN_BUDDY_SZ_LOG2]); 57 | if(idx != -1) { 58 | // we found a block 59 | break; 60 | } 61 | log_sz++; 62 | } 63 | 64 | if (idx == -1) { 65 | // No free blocks 66 | return ~0ULL; 67 | } 68 | // Split blocks to get a block of minimum size 69 | for(; log_sz != orig_log_sz; log_sz--) { 70 | int order_idx = log_sz - MIN_BUDDY_SZ_LOG2; 71 | // splitting a block, so deallocate it first. 72 | bitmap_clear(&bd->orders[order_idx], idx); 73 | 74 | // Set both children as free. 75 | idx = INC_ORDER(idx); 76 | bitmap_set(&bd->orders[order_idx - 1], idx); 77 | bitmap_set(&bd->orders[order_idx - 1], idx + 1); 78 | } 79 | int order_idx = log_sz - MIN_BUDDY_SZ_LOG2; 80 | bitmap_clear(&bd->orders[order_idx], idx); 81 | 82 | uint64_t addr = bd->start + ((uint64_t)idx << log_sz); 83 | return addr; 84 | } 85 | 86 | static int aligned_for(uint64_t addr, uintptr_t lg2) 87 | { 88 | uintptr_t mask = ~( ~0ULL << lg2 ); 89 | return (addr & mask) == 0; 90 | } 91 | 92 | void buddy_free(buddy_t *bd, uint64_t addr, unsigned sz) 93 | { 94 | uint64_t offs = addr - bd->start; 95 | unsigned log_sz = log2_roundup(sz); 96 | unsigned idx = offs >> log_sz; 97 | 98 | while (log_sz >= MIN_BUDDY_SZ_LOG2) { 99 | int order_idx = log_sz - MIN_BUDDY_SZ_LOG2; 100 | // Mark node free 101 | bitmap_set(&bd->orders[order_idx], idx); 102 | // Can we coalese up another level? 103 | if (log_sz == MAX_BUDDY_SZ_LOG2) { 104 | break; 105 | } 106 | if (bitmap_isset(&bd->orders[order_idx], BUDDY(idx)) == 0) { 107 | // guess not... 108 | break; 109 | } 110 | // Mark both non-free 111 | bitmap_clear(&bd->orders[order_idx], idx); 112 | bitmap_clear(&bd->orders[order_idx], BUDDY(idx)); 113 | 114 | // Move up an order 115 | idx = DEC_ORDER(idx); 116 | log_sz++; 117 | } 118 | } 119 | 120 | void buddy_free_range(buddy_t *bd, range_t range) 121 | { 122 | unsigned i; 123 | uint64_t old_start, start; 124 | uintptr_t sz, min_sz; 125 | min_sz = 1 << MIN_BUDDY_SZ_LOG2; 126 | if (aligned_for(range.start, MIN_BUDDY_SZ_LOG2) == 0) { 127 | if (range.extent < min_sz) { 128 | return; 129 | } 130 | old_start = range.start; 131 | range.start &= ~0ULL << MIN_BUDDY_SZ_LOG2; 132 | range.start += min_sz; 133 | range.extent -= range.start - old_start; 134 | } 135 | while (range.extent >= min_sz && 136 | aligned_for(range.start, MIN_BUDDY_SZ_LOG2)) { 137 | for(i = MAX_BUDDY_SZ_LOG2; i >= MIN_BUDDY_SZ_LOG2; i--) { 138 | sz = 1 << i; 139 | start = range.start - bd->start; 140 | if (sz > range.extent || aligned_for(start, i) == 0) { 141 | continue; 142 | } 143 | range.extent -= sz; 144 | range.start += sz; 145 | buddy_free(bd, start + bd->start, sz); 146 | break; 147 | } 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /src/adt/ringbuf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2018 Apollo Project Developers 3 | * adt/ringbuf.c - Ring Buffer implementation 4 | * History: 5 | * 10/8/18 - First implementation - Char ringbuffer only 6 | */ 7 | 8 | #include 9 | 10 | char_ringbuf_t make_char_ringbuf(char *buf, int len) 11 | { 12 | char_ringbuf_t temp; 13 | temp.buffer = temp.buffer_start = temp.buffer_end = buf; 14 | temp.buffer_length = len; 15 | return temp; 16 | } 17 | 18 | 19 | int char_ringbuf_read(char_ringbuf_t *state, char *buf, int len) { 20 | if (state->buffer_start == state->buffer_end) { 21 | return 0; 22 | } 23 | 24 | int n = 0; 25 | while (state->buffer_start != state->buffer_end && n < len) { 26 | buf[n++] = *state->buffer_start++; 27 | 28 | if (state->buffer_start >= (state->buffer+state->buffer_length)) { 29 | state->buffer_start -= state->buffer_length; 30 | } 31 | } 32 | return n; 33 | } 34 | 35 | void char_ringbuf_write(char_ringbuf_t *state, const char *buf, int len) { 36 | for (int i = 0; i < len; ++i) { 37 | *state->buffer_end++ = buf[i]; 38 | 39 | // Reset to the start if we're approaching the end 40 | if(state->buffer_end >= (state->buffer+state->buffer_length)) { 41 | state->buffer_end -= state->buffer_length; 42 | } 43 | } 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/adt/testing/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # ADT Test Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | test_y := test_ringbuf.c 8 | -------------------------------------------------------------------------------- /src/adt/testing/test_ringbuf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2018 Apollo Developers 3 | * test_ringbuf.c - Testing the ringbuffer 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | static char_ringbuf_t test_buf; 10 | static char buffer[9]; 11 | static char buff2[9]; 12 | 13 | TEST_GROUP(ringbuf_test); 14 | 15 | TEST_SETUP(ringbuf_test) 16 | { 17 | test_buf = make_char_ringbuf(buffer, 9); 18 | } 19 | TEST_TEAR_DOWN(ringbuf_test) 20 | { 21 | 22 | } 23 | 24 | TEST(ringbuf_test, readWriteTest) 25 | { 26 | char_ringbuf_write(&test_buf, "Hello", 6); 27 | char_ringbuf_read(&test_buf, buff2, 6); 28 | TEST_ASSERT_EQUAL_STRING("Hello", buff2); 29 | } 30 | -------------------------------------------------------------------------------- /src/arch/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Architecture" 2 | 3 | config TARGET 4 | string "Target Definition" 5 | default x86 6 | help 7 | This selects what build type will be used to compile the kernel 8 | Available platforms are: 9 | - hosted 10 | - x86 11 | - rpi4 12 | 13 | if TARGET=hosted 14 | config HOSTED_BASE 15 | bool "Hosted Base Functionality" 16 | default y 17 | select LIBC 18 | help 19 | This package should always be selected when building for hosted 20 | enviorments. Without it dependencies will not be met. 21 | endif 22 | 23 | if TARGET=x86 24 | source "src/arch/x86/Kconfig" 25 | endif 26 | 27 | if TARGET=rpi4 28 | source "src/arch/rpi4/Kconfig" 29 | endif 30 | 31 | endmenu 32 | -------------------------------------------------------------------------------- /src/arch/rpi4/Kconfig: -------------------------------------------------------------------------------- 1 | config RPI4_BASE 2 | bool "Raspberry Pi Model 4B Base Functionality" 3 | default y 4 | help 5 | This package should always be selected when building for the Raspberry 6 | Pi Model 4B. It contains the bootup code as well as functional drivers. 7 | 8 | -------------------------------------------------------------------------------- /src/arch/rpi4/Makefile: -------------------------------------------------------------------------------- 1 | #################################### 2 | # Apollo Project # 3 | # Raspberry Pi 4 specific Makefile # 4 | # (c) 2022 Apollo Developers # 5 | #################################### 6 | 7 | obj_$(CONFIG_RPI4_BASE) := boot.S atomic.S 8 | obj_$(CONFIG_RPI4_BASE) += bringup.c 9 | -------------------------------------------------------------------------------- /src/arch/rpi4/atomic.S: -------------------------------------------------------------------------------- 1 | .globl __aarch64_cas4_sync 2 | 3 | __aarch64_cas4_sync: 4 | mov w16, w0 5 | ldxr w0, [x2] 6 | cmp w0, w16 7 | 0: bne 1f 8 | 9 | stlxr w17, w1, [x2] 10 | cbnz w17, 0b 11 | 1: ret 12 | -------------------------------------------------------------------------------- /src/arch/rpi4/boot.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * Entry point for the rpi4 architecture port 5 | */ 6 | 7 | .section ".init" 8 | .globl _start 9 | // Entry Point for the kernel. The Pi provides the following: 10 | // x0 -> 32 bit pointer to DTB in memory (primary core) / 0 (secondary cores) 11 | // x1 -> 0 12 | // x2 -> 0 13 | // x3 -> 0 14 | // x4 -> 32 bit kernel entry point (_start's address) 15 | 16 | // With latest firmware, primary core runs this code, while all the secondairy 17 | // cores sit in a spinloop. 18 | 19 | _start: 20 | // Set up the stack below our code 21 | ldr x5, =_start 22 | mov sp, x5 23 | 24 | // Zero out the BSS section 25 | ldr x5, =__bss_begin// Start Address of .bss segment 26 | ldr x6, =__bss_end // End Address of .bss segment 27 | sub x6, x6, x5 // Size = start - end 28 | 29 | 1: cbz x6, 2f // Quit loop if counter is 0 30 | str xzr, [x5], #8 // Store 0 at address X5 , then add 8 bytes to x5 31 | sub x6, x6, #1 // Decrement loop counter 32 | cbnz x6, 1b // Loop back around if counter isn't 0 33 | 34 | 2: bl arch_init // Jump to C code 35 | b 1b // In the event of return, halt 36 | -------------------------------------------------------------------------------- /src/arch/rpi4/bringup.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern int main(int argc, char **argv); 4 | 5 | #include 6 | extern module_t __start_modules, __stop_modules; 7 | 8 | void arch_init(void) 9 | { 10 | char *argc[] = {"debug=y"}; 11 | const int argv = 1; 12 | 13 | main(argv, argc); 14 | while (1) { 15 | 16 | } 17 | } 18 | 19 | int get_num_processors() 20 | { 21 | return 4; 22 | } 23 | 24 | uint32_t free_memory_get_megs() 25 | { 26 | return 1024; // All Raspi4's have at least 1GB ram. 27 | } 28 | -------------------------------------------------------------------------------- /src/arch/rpi4/hal/Makefile: -------------------------------------------------------------------------------- 1 | #################################### 2 | # Apollo Project # 3 | # rpi4 HAL Implementation Makefile # 4 | # (c) 2022 Apollo Developers # 5 | #################################### 6 | ifeq ($(CONFIG_TARGET), "rpi4") 7 | 8 | obj_$(CONFIG_CONSOLE) += console.c 9 | 10 | endif 11 | -------------------------------------------------------------------------------- /src/arch/rpi4/hal/console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * console.c - rpi4 console initialization. 5 | * Attempts to bring up Serial Driver for console output 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define UART_BAUD 115200 13 | #define AUX_ENABLES 0x01 14 | #define AUX_UART_CLOCK (500000000) 15 | #define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1) 16 | 17 | // RPI4 GPIO 18 | static resource_t gpio = { 19 | .name = "gpio", 20 | .start = 0xFE200000, 21 | .end = 0xFE2000FF, 22 | .flags = RESOURCE_MEM | RESOURCE_WIDTH_32 23 | }; 24 | 25 | // AUX Peripheral Base 26 | static resource_t aux_peripheral = { 27 | .name = "aux_peripheral", 28 | .start = 0xFE215000, 29 | .end = 0xFE2150FF, 30 | .flags = RESOURCE_MEM | RESOURCE_WIDTH_32 31 | }; 32 | 33 | // RPI4 Mini UART 34 | static resource_t mini_uart = { 35 | .name = "mini_uart", 36 | .start = 0xFE215040, 37 | .end = 0xFE21506F, 38 | .flags = RESOURCE_MEM | RESOURCE_WIDTH_32 39 | }; 40 | 41 | static device_t serial_console_device = { 42 | .name = "serial_console", 43 | .access = &mini_uart 44 | }; 45 | 46 | static device_t gpio_device = { 47 | .name = "gpio", 48 | .access = &gpio 49 | }; 50 | 51 | static int pincfg(uint32_t pin, uint32_t function) 52 | { 53 | uint32_t cfg[2]; 54 | cfg[0] = function; 55 | cfg[1] = pin; 56 | return device_api_call(&gpio_device, &cfg); 57 | } 58 | 59 | static int setup_mini_uart() 60 | { 61 | int ret; 62 | uint32_t baudrate = (AUX_MU_BAUD(UART_BAUD) * UART_BAUD); 63 | uint32_t cmd = 1; 64 | 65 | // Enable the Mini UART 66 | ret = resource_write(&cmd, &aux_peripheral, (AUX_ENABLES), 1); 67 | 68 | // Set up RX/TX Pins 69 | ret |= device_register(&gpio_device, base_device(), "gpio/bcm2711"); 70 | ret |= pincfg(14, 7); // Set Pin 14 to Alternate mode 5 (TX) 71 | ret |= pincfg(14, 8); // Turn off Pullup/Pulldown resistors 72 | ret |= pincfg(15, 7); // Set Pin 14 to Alternate mode 5 (TX) 73 | ret |= pincfg(15, 8); // Turn off Pullup/Pulldown resistors 74 | 75 | // Set up mini UART Proper 76 | ret |= device_register(&serial_console_device, base_device(), 77 | "console/serial/16550"); 78 | ret |= device_init(&serial_console_device, &baudrate); 79 | return ret; 80 | } 81 | 82 | static int mod_init() 83 | { 84 | return setup_mini_uart(); 85 | } 86 | 87 | static prereq_t prereqs[] = { {"console",NULL}, {NULL,NULL} }; 88 | MODULE = { 89 | .name = "rpi4/console", 90 | .required = prereqs, 91 | .load_after = NULL, 92 | .init = &mod_init, 93 | .fini = NULL 94 | }; 95 | -------------------------------------------------------------------------------- /src/arch/rpi4/link.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * x86 architecture specific linker script 5 | */ 6 | 7 | /* TODO: Higher half for 64-bit addressing */ 8 | VIRT_OFFSET = 0x0; 9 | 10 | /* Multiboot compliance dumps us here */ 11 | INIT_OFFSET = 0x80000; 12 | 13 | /* Defined in boot.S */ 14 | ENTRY(_start) 15 | 16 | /* Defines the actual sections */ 17 | INCLUDE scripts/common.ld 18 | -------------------------------------------------------------------------------- /src/arch/x86/Kconfig: -------------------------------------------------------------------------------- 1 | config X86_BASE 2 | bool "x86 Base Functionality" 3 | default y 4 | select LIBC 5 | select IRQCHIP_8259 6 | help 7 | This package should always be selected when building for 32 bit 8 | Intel machines that are IBM PC compatible. Unless you really 9 | know what you are doing do not turn this off. 10 | 11 | -------------------------------------------------------------------------------- /src/arch/x86/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # x86 Arch specific Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | obj_$(CONFIG_X86_BASE) := start.s multiboot.s 8 | obj_$(CONFIG_X86_BASE) += bringup.c ports.c 9 | obj_$(CONFIG_X86_BASE) += idt.c ivt.s irq.c 10 | obj_$(CONFIG_X86_BASE) += gdt.c 11 | obj_$(CONFIG_X86_BASE) += free_memory.c vmm.c 12 | -------------------------------------------------------------------------------- /src/arch/x86/bringup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * arch/x86/init.c - Initialization function for x86 platform. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | extern int main(int argc, char **argv); 12 | 13 | multiboot_info_t mboot; 14 | 15 | // 4k for early allocator - for multiboot and things 16 | #define EARLYALLOC_SZ 4096 17 | 18 | // Bump Allocator, used to store multiboot info to a safe location 19 | static uint32_t earlyalloc(unsigned len) 20 | { 21 | static uint8_t buf[EARLYALLOC_SZ]; 22 | static unsigned idx = 0; 23 | if (idx + len >= EARLYALLOC_SZ) { 24 | // We can't allocate, we ran outta room 25 | return NULL; 26 | } 27 | uint8_t *ptr = &buf[idx]; 28 | idx += len; 29 | 30 | return (uint32_t)ptr; 31 | } 32 | 33 | static int tokenize(char tok, char *in, char **out, int maxout) { 34 | int n = 0; 35 | 36 | while(*in && n < maxout) { 37 | out[n++] = in; 38 | 39 | /* Spool until the next instance of 'tok', or end of string. */ 40 | while (*in && *in != tok) 41 | ++in; 42 | /* If we exited because we saw a token, make it a NUL character 43 | and step over it.*/ 44 | if (*in == tok) 45 | *in++ = '\0'; 46 | } 47 | 48 | return n; 49 | } 50 | 51 | // Called by assembly. 52 | int arch_init(multiboot_info_t* mbt, unsigned int magic) 53 | { 54 | int argc, len; 55 | uint32_t i; 56 | static char *argv[256]; 57 | multiboot_module_t *mod_old, *mod_new; 58 | 59 | memcpy((uint8_t*)&mboot, (uint8_t*)(mbt), sizeof(multiboot_info_t)); 60 | // Now copy info inside to malloc()'d space 61 | 62 | // Command line first 63 | if (mboot.flags & MULTIBOOT_INFO_CMDLINE) { 64 | mbt->cmdline += 0xC0000000; 65 | len = strlen((char*)mbt->cmdline) + 1; 66 | mboot.cmdline = earlyalloc(len); 67 | if (mboot.cmdline) { 68 | memcpy((uint8_t*)mboot.cmdline, (uint8_t*)mbt->cmdline, len); 69 | } 70 | } 71 | 72 | if (mboot.flags & MULTIBOOT_INFO_MODS) { 73 | mbt->mods_addr += 0xC0000000; 74 | len = mboot.mods_count * sizeof(multiboot_module_t); 75 | mboot.mods_addr = earlyalloc(len); 76 | if(mboot.mods_addr) { 77 | memcpy((uint8_t*)mboot.mods_addr, (uint8_t*)mbt->mods_addr, len); 78 | // CLI string inside modules 79 | mod_old = (multiboot_module_t *) mbt->mods_addr; 80 | mod_new = (multiboot_module_t *) mboot.mods_addr; 81 | for (i = 0; i < mboot.mods_count; i++) 82 | { 83 | len = strlen((char*)mod_old[i].cmdline) + 1; 84 | mod_new[i].cmdline = earlyalloc(len); 85 | memcpy((uint8_t*)mod_new[i].cmdline, 86 | (uint8_t*)mod_old[i].cmdline, len); 87 | mod_new[i].mod_start += 0xC0000000; 88 | mod_new[i].mod_end += 0xC0000000; 89 | } 90 | } 91 | } 92 | if (mboot.flags & MULTIBOOT_INFO_ELF_SHDR) { 93 | mbt->u.elf_sec.addr += 0xC0000000; 94 | len = mboot.u.elf_sec.num * mboot.u.elf_sec.size; 95 | mboot.u.elf_sec.addr = earlyalloc(len); 96 | if (mboot.u.elf_sec.addr) { 97 | memcpy((uint8_t*)mboot.u.elf_sec.addr, 98 | (uint8_t*)mbt->u.elf_sec.addr, len); 99 | } 100 | } 101 | if (mboot.flags & MULTIBOOT_INFO_MEM_MAP) { 102 | mbt->mmap_addr += 0xC0000000; 103 | mboot.mmap_addr = earlyalloc(mboot.mmap_length + 4); 104 | if (mboot.mmap_addr) { 105 | memcpy((uint8_t*)mboot.mmap_addr, 106 | (uint8_t*)mbt->mmap_addr - 4, mboot.mmap_length+4); 107 | mboot.mmap_addr += 4; 108 | mboot.mmap_addr = mbt->mmap_addr; 109 | } 110 | } 111 | 112 | // Tokenize! 113 | argc = tokenize(' ', (char*)mboot.cmdline, argv, 256); 114 | 115 | (void)main(argc, argv); 116 | 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /src/arch/x86/free_memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2019 Apollo Developers 3 | * For terms, See LICENSE 4 | * free_memory.c - Multiboot header reading to find ranges of free memory 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | extern multiboot_info_t mboot; 11 | 12 | #define MBOOT_IS_MMAP_TYPE_RAM(x) (x == MULTIBOOT_MEMORY_AVAILABLE) 13 | #define MBOOT_MEM (1<<0) 14 | #define MBOOT_MMAP (1<<6) 15 | 16 | static uint32_t total_megabytes; 17 | 18 | static void remove_range(range_t *r, uint32_t start, uint32_t end) 19 | { 20 | // TODO: Stop assuming that a range exists which starts at 'start' and 21 | // extends to extent 22 | // Sanity check to make sure this is the right range 23 | 24 | if(r->start == start) { 25 | r->start += end; // Move range up past extent 26 | r->extent -= end; // lower extent 27 | } 28 | } 29 | 30 | static int free_memory() 31 | { 32 | extern uint32_t __start, __end; // Provided by linker 33 | 34 | // Store ranges in easy format, instead of multiboot 35 | range_t ranges[128], ranges_cpy[128]; 36 | uint32_t i = 0; 37 | unsigned n = 0; 38 | uint64_t extent = 0; 39 | multiboot_memory_map_t *entry; 40 | 41 | if ((mboot.flags & MBOOT_MMAP) == 0) { 42 | panic("Bootloader did not provide memory map info!"); 43 | } 44 | 45 | // Iterate until we're at the end of the mmap 46 | for (entry = (multiboot_memory_map_t *) mboot.mmap_addr; 47 | (uint32_t)entry < mboot.mmap_addr + mboot.mmap_length; 48 | entry = (multiboot_memory_map_t *) ((uint32_t) entry + entry->size + 49 | sizeof (entry->size))) { 50 | if (n >= 128) { // Allow 128 loops before a break, avoid looping errors 51 | break; 52 | } 53 | 54 | // Check for a non-sensical MMAP Type, assume that they're RAM 55 | if(entry->type > 5) 56 | { 57 | entry->type = MULTIBOOT_MEMORY_AVAILABLE; 58 | } 59 | 60 | // Is this ram? (Only ram is useful for us) 61 | if (MBOOT_IS_MMAP_TYPE_RAM(entry->type)) { 62 | // Make note of start and length of the range, then increment n. 63 | ranges[n].start = entry->addr; 64 | ranges[n++].extent = entry->len; 65 | 66 | // Does this new info move out how far RAM goes? Update the extent 67 | if (entry->addr + entry->len > extent) { 68 | extent = entry->addr + entry->len; 69 | } 70 | } 71 | i++; 72 | } 73 | 74 | // __end is size of our kernel from ld, we add some flags to it. 75 | uint32_t end = (((uint32_t)&__end) & ~get_page_mask()) + get_page_size(); 76 | // Run over the ranges, one of them has our kernel in it and shouldn't be 77 | // Marked as free (as our kernel would be overridden) 78 | for (i = 0; i < n; i++) 79 | { 80 | remove_range(&ranges[i], (uint32_t)&__start, end); 81 | } 82 | 83 | // Copy the ranges to a backup, as init_physical_memory mutates them and 84 | // init_cow_refcnts needs to run after init_physical_memory 85 | 86 | for (i = 0; i < n; i++) { 87 | ranges_cpy[i] = ranges[i]; 88 | } 89 | init_physical_memory_early(ranges, n, extent); 90 | init_virtual_memory(ranges, n); 91 | init_physical_memory(); 92 | init_cow_refcnts(ranges, n); 93 | total_megabytes = (mboot.mem_upper / 1024) + 2; 94 | return 0; 95 | } 96 | 97 | uint32_t free_memory_get_megs() 98 | { 99 | return total_megabytes; 100 | } 101 | 102 | MODULE = { 103 | .name = "x86/free_memory", 104 | .required = NULL, 105 | .load_after = NULL, 106 | .init = &free_memory, 107 | .fini = NULL 108 | }; 109 | -------------------------------------------------------------------------------- /src/arch/x86/gdt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2018 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * arch/x86/gdt.c - GDT & TSS 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "include/gdt.h" 12 | 13 | static gdt_ptr_t gdt_ptr; 14 | static gdt_entry_t entries[MAX_CORES+5]; 15 | static tss_entry_t tss_entries[MAX_CORES]; 16 | 17 | unsigned num_gdt_entries, num_tss_entries; 18 | 19 | static void set_gdt_entry(gdt_entry_t *e, uint32_t base, uint32_t limit, 20 | uint8_t type, uint8_t s, uint8_t dpl, uint8_t p, 21 | uint8_t l, uint8_t d, uint8_t g) 22 | { 23 | e->limit_low = limit & 0xFFFF; 24 | e->base_low = base & 0xFFFF; 25 | e->base_mid = (base >> 16) & 0xFF; 26 | e->type = type & 0xF; 27 | e->s = s & 0x1; 28 | e->dpl = dpl & 0x3; 29 | e->p = p & 0x1; 30 | e->limit_high = (limit >> 16) & 0xF; 31 | e->avail = 0; 32 | e->l = l & 0x1; 33 | e->d = d & 0x1; 34 | e->g = g & 0x1; 35 | e->base_high = (base >> 24) & 0xFF; 36 | } 37 | 38 | static void set_tss_entry(tss_entry_t *e) 39 | { 40 | // Zero out the entry. 41 | memset((uint8_t*)e, 0, sizeof(tss_entry_t)); 42 | // Set the segment registers to the ring 0 data (0x10) 43 | e->ss0 = e->ss = e->ds = e->es = e->fs = e->gs = 0x10; 44 | // Set code segment to ring 0 code (0x08) 45 | e->cs = 0x08; 46 | } 47 | 48 | // Returns the base address of a gdt entry. 49 | static uint32_t base(gdt_entry_t e) { 50 | return e.base_low | (e.base_mid << 16) | (e.base_high << 24); 51 | } 52 | 53 | // Returns the unobfuscated limit of a gdt entry. 54 | static uint32_t limit(gdt_entry_t e) { 55 | return e.limit_low | (e.limit_high << 16); 56 | } 57 | 58 | static void print_gdt_entry(unsigned i, gdt_entry_t e) 59 | { 60 | uint32_t *m = (uint32_t*) &e; 61 | printf("#%02d: %08x %08x\n", i, m[0], m[1]); 62 | printf("#%02d: Base %#08x Limit %#08x Type %d\n", 63 | i, base(e), limit(e), e.type); 64 | printf(" s %d dpl %d p %d l %d d %d g %d\n", 65 | e.s, e.dpl, e.p, e.l, e.d, e.g); 66 | } 67 | 68 | static void print_tss_entry(unsigned i, tss_entry_t e) { 69 | printf("#%02d: esp0 %#08x ss0 %#02x cs %#02x\n" 70 | "ss %#02x ds %#02x es %#02x fs %#02x gs %#02x\n", 71 | i, e.esp0, e.ss0, e.cs, e.ss, e.ds, e.es, e.fs, e.gs); 72 | } 73 | 74 | static void print_tss(const char *cmd, core_debug_state_t *states, int core) 75 | { 76 | unsigned i; 77 | for(i = 0; i < num_tss_entries; i++) { 78 | print_tss_entry(i, tss_entries[i]); 79 | } 80 | } 81 | 82 | static void print_gdt(const char *cmd, core_debug_state_t *states, int core) 83 | { 84 | unsigned i; 85 | for(i = 0; i < num_gdt_entries; i++) { 86 | print_gdt_entry(i, entries[i]); 87 | } 88 | } 89 | 90 | static int gdt_init() 91 | { 92 | int i; 93 | 94 | register_debugger_handler("print-gdt", "Print GDT Entries", &print_gdt); 95 | register_debugger_handler("print-tss", "Print TSS Entries", &print_tss); 96 | 97 | // Ring 0 and Ring 3 data/code gdt entries for full memory size 98 | // ~0u is shorthand for 0xFFFFFFFF (1's complement on unsigned 0) 99 | // Base Limit Type S DPL P L D G 100 | set_gdt_entry(&entries[0],0xFFF0, 0, 0, 0, 0, 0, 0, 0, 0); 101 | set_gdt_entry(&entries[1], 0, ~0u, TY_CODE|TY_READABLE, 1, 0, 1, 0, 1, 1); 102 | set_gdt_entry(&entries[2], 0, ~0u, TY_DATA_WRITABLE , 1, 0, 1, 0, 1, 1); 103 | set_gdt_entry(&entries[3], 0, ~0u, TY_CODE|TY_READABLE, 1, 3, 1, 0, 1, 1); 104 | set_gdt_entry(&entries[4], 0, ~0u, TY_DATA_WRITABLE , 1, 3, 1, 0, 1, 1); 105 | 106 | int num_processors = get_num_processors(); 107 | if (num_processors == -1) { 108 | num_processors = 1; // If get_num_processors hasn't been implemented. 109 | } 110 | for(i = 0; i < num_processors; i++) { 111 | set_tss_entry(&tss_entries[i]); 112 | set_gdt_entry(&entries[i+5], (uint32_t)&tss_entries[i], 113 | // Type S DPL P L D G 114 | sizeof(tss_entry_t)-1, TY_CODE|TY_ACCESSED, 0, 3, 1, 0, 0, 1); 115 | } 116 | num_gdt_entries = num_processors + 5; 117 | num_tss_entries = num_processors; 118 | 119 | // Set up the pointer for the GDT 120 | gdt_ptr.base = (uint32_t)&entries[0]; 121 | gdt_ptr.limit = sizeof(gdt_entry_t) * num_gdt_entries - 1; 122 | 123 | __asm__ volatile( "lgdt %0;" 124 | "mov ax, 0x10;" 125 | "mov ds, ax;" 126 | "mov es, ax;" 127 | "mov fs, ax;" 128 | "mov gs, ax;" 129 | "ljmp 0x08:$+7;" 130 | "1:" : : "m" (gdt_ptr) : "eax"); 131 | return 0; 132 | } 133 | 134 | static prereq_t prereqs[] = {{"debugger",NULL}, {"console",NULL}, {NULL,NULL}}; 135 | 136 | MODULE = { 137 | .name = "x86/gdt", 138 | .required = NULL, 139 | .load_after = prereqs, 140 | .init = &gdt_init, 141 | .fini = NULL 142 | }; 143 | -------------------------------------------------------------------------------- /src/arch/x86/hal/Makefile: -------------------------------------------------------------------------------- 1 | ################################### 2 | # Apollo Project # 3 | # x86 HAL Implementation Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ################################### 6 | ifeq ($(CONFIG_TARGET), "x86") 7 | 8 | obj_$(CONFIG_TIMEKEEPING) += timekeeping.c 9 | obj_$(CONFIG_CONSOLE) += console.c 10 | 11 | endif 12 | -------------------------------------------------------------------------------- /src/arch/x86/hal/console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * console.c - x86 console initialization. 5 | * Attempts to bring up VGA and Serial Drivers for console 6 | * output 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // x86 VGA 14 | static resource_t vga_resource = { 15 | .name = "vga", 16 | .start = 0xA0000, 17 | .end = 0xBFFFF, 18 | .flags = RESOURCE_META 19 | }; 20 | 21 | static resource_t vga_control = { 22 | .name = "control_base", 23 | .start = 0x3C0, 24 | .end = 0x3DF, 25 | .flags = RESOURCE_IO | RESOURCE_WIDTH_8 | RESOURCE_IO_INDEXED 26 | }; 27 | 28 | static resource_t vga_framebuffer = { 29 | .name = "framebuffer", 30 | .flags = RESOURCE_MEM 31 | }; 32 | 33 | static device_t vga_device = { 34 | .name = "vga", 35 | .access = &vga_resource 36 | }; 37 | 38 | static device_t vga_console_device = { 39 | .name = "vga_console", 40 | .access = &vga_framebuffer 41 | }; 42 | 43 | // x86 COM1 44 | static resource_t com1 = { 45 | .name = "COM1", 46 | .start = 0x3F8, 47 | .end = 0x3FF, 48 | .flags = RESOURCE_IO | RESOURCE_WIDTH_8 49 | }; 50 | 51 | static device_t serial_console_device = { 52 | .name = "serial_console", 53 | .access = &com1 54 | }; 55 | 56 | static int console_init() 57 | { 58 | int vgaRet, serialRet; 59 | // Serial Baudrate 60 | uint32_t baudrate = 115200; 61 | // Bios video mode 3h, 8 tall font, 50 lines, 80 columns of text. 62 | uint32_t vga_config[] = {0x3, 8, 50, 80}; 63 | 64 | // VGA Console First 65 | resource_register(&vga_resource, NULL); 66 | resource_register(&vga_control, &vga_resource); 67 | resource_register(&vga_framebuffer, &vga_resource); 68 | 69 | vgaRet = device_register(&vga_device, base_device(), "display/vga"); 70 | vgaRet |= device_register(&vga_console_device, &vga_device, "console/vga"); 71 | vgaRet |= device_init(&vga_device, &vga_config); 72 | vgaRet |= device_init(&vga_console_device, &vga_config[2]); 73 | 74 | // Serial Console Next 75 | resource_register(&com1, NULL); 76 | serialRet = device_register(&serial_console_device, base_device(), 77 | "console/serial/16550"); 78 | serialRet |= device_init(&serial_console_device, &baudrate); 79 | 80 | // If either console succeeds, we succeed 81 | return (vgaRet && serialRet); 82 | } 83 | 84 | static prereq_t prereqs[] = { {"console",NULL}, {NULL,NULL} }; 85 | MODULE = { 86 | .name = "x86/console", 87 | .required = prereqs, 88 | .load_after = NULL, 89 | .init = &console_init, 90 | .fini = NULL 91 | }; 92 | -------------------------------------------------------------------------------- /src/arch/x86/hal/timekeeping.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Developers 3 | * For terms, see LICENSE 4 | * timekeeping.c - Timekeeping functionality setup. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern int i8254_configure(timekeeping_state_t *chip, int channel, int mode); 13 | 14 | static resource_t i8254_chip = { 15 | .name = "at_pit_resource", 16 | .start = 0x40, 17 | .end = 0x43, 18 | .flags = RESOURCE_IO | RESOURCE_IO_SLOW | RESOURCE_WIDTH_8 19 | }; 20 | 21 | /* 22 | * With the below settings, we get: 23 | * ~1 KHz timer, with a period of 1.000685561ms 24 | * After driver corrections, this gives us an accuracy of 18 seconds 25 | * loss per year. 26 | */ 27 | static timekeeping_state_t state = { 28 | .name = "at_pit", 29 | .data = &i8254_chip, 30 | .frequency = 999, 31 | .us_per_tick = 1000, 32 | .ns_per_tick = 685, 33 | .priority = 100, 34 | .ns_count = 0, 35 | .base_frequency = 1193182 /* 1.193181666666666 MHz */ 36 | }; 37 | 38 | /* 39 | * Channel 0 is connected to the IRQ line, so configure that specifically 40 | * We want mode 2 (Rate Generator) to pulse the IRQ 41 | */ 42 | static int config[] = {0, 2}; 43 | 44 | static device_t at_pit = { 45 | .name = "at_pit", 46 | .data = &state 47 | }; 48 | 49 | static int timekeeping(struct regs *regs, void *p) 50 | { 51 | // Grab current timestamp so we can update it 52 | uint64_t ts = get_timestamp(); 53 | 54 | state.ns_count += state.ns_per_tick; 55 | if(state.ns_count >= 1000) { // Did we hit a microsecond? 56 | ts += (state.ns_count / 1000); 57 | state.ns_count %= 1000; 58 | } 59 | // Add Microseconds to the clock. 60 | ts += state.us_per_tick; 61 | set_timestamp(ts); 62 | return 0; 63 | } 64 | 65 | static int timekeeping_init() 66 | { 67 | int interrupt_state = get_interrupt_state(); 68 | 69 | // Re-init the timestamp. 70 | set_timestamp(0); 71 | 72 | // Atomic Section 73 | disable_interrupts(); 74 | 75 | if(device_register(&at_pit, base_device(), "clock/i8254")) { 76 | return -1; 77 | } 78 | if(device_init(&at_pit, config)) { 79 | return -1; 80 | } 81 | 82 | // IRQ 0 is mapped to interrupt 32. 83 | register_interrupt_handler(32, &timekeeping, NULL); 84 | 85 | // End Atomic Section 86 | set_interrupt_state(interrupt_state); 87 | return 0; 88 | } 89 | 90 | static prereq_t prereqs[] = {{"interrupts", NULL}, {NULL, NULL}}; 91 | 92 | MODULE = { 93 | .name = "timekeeping", 94 | .required = prereqs, 95 | .load_after = NULL, 96 | .init = &timekeeping_init, 97 | .fini = NULL, 98 | }; 99 | -------------------------------------------------------------------------------- /src/arch/x86/include/gdt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * gdt.h - x86 32 Bit GDT definitions. 4 | */ 5 | 6 | #ifndef __ARCH_X86_GDT_H 7 | #define __ARCH_X86_GDT_H 8 | 9 | #include 10 | 11 | typedef struct { 12 | uint16_t limit_low; 13 | uint16_t base_low; 14 | uint8_t base_mid; 15 | uint8_t type : 4; 16 | uint8_t s : 1; /* 's' should always be 1, except for */ 17 | uint8_t dpl : 2; /* the NULL segment. */ 18 | uint8_t p : 1; 19 | uint8_t limit_high : 4; 20 | uint8_t avail: 1; 21 | uint8_t l : 1; 22 | uint8_t d : 1; 23 | uint8_t g : 1; 24 | uint8_t base_high; 25 | } gdt_entry_t; 26 | 27 | typedef struct { 28 | uint16_t limit; 29 | uint32_t base; 30 | } __attribute__((packed)) gdt_ptr_t; 31 | 32 | typedef struct { 33 | uint32_t prev_tss; 34 | uint32_t esp0, ss0, esp1, ss1, esp2, ss2; 35 | uint32_t cr3, eip, eflags; 36 | uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi; 37 | uint32_t es, cs, ss, ds, fs, gs; 38 | uint32_t ldt; 39 | uint16_t trap, iomap_base; 40 | } tss_entry_t; 41 | 42 | extern void gdtFlush(); 43 | 44 | #define TY_CODE 8 45 | 46 | /* Applies to code segments */ 47 | #define TY_CONFORMING 4 48 | #define TY_READABLE 2 49 | 50 | /* Applies to data segments. */ 51 | #define TY_DATA_EXPAND_DIRECTION 4 52 | #define TY_DATA_WRITABLE 2 53 | 54 | /* Applies to both; set by the CPU. */ 55 | #define TY_ACCESSED 1 56 | 57 | 58 | 59 | /* 60 | * Here There Be Macros... Y'arr 61 | * 62 | * Each define is for a specific flag in the descriptor field. 63 | * Refer to the intel documentation for a description of what each is. 64 | */ 65 | 66 | #define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type 67 | #define SEG_PRES(x) ((x) << 0x07) // Present 68 | #define SEG_SAVL(x) ((x) << 0x0C) // Available for system use 69 | #define SEG_LONG(x) ((x) << 0x0D) // Long mode 70 | #define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32) 71 | #define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) 72 | #define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3) 73 | 74 | #define SEG_DATA_RD 0x00 // Read-Only 75 | #define SEG_DATA_RDA 0x01 // Read-Only, accessed 76 | #define SEG_DATA_RDWR 0x02 // Read/Write 77 | #define SEG_DATA_RDWRA 0x03 // Read/Write, accessed 78 | #define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down 79 | #define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed 80 | #define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down 81 | #define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed 82 | #define SEG_CODE_EX 0x08 // Execute-Only 83 | #define SEG_CODE_EXA 0x09 // Execute-Only, accessed 84 | #define SEG_CODE_EXRD 0x0A // Execute/Read 85 | #define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed 86 | #define SEG_CODE_EXC 0x0C // Execute-Only, conforming 87 | #define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed 88 | #define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming 89 | #define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed 90 | 91 | #define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 92 | SEG_PRIV(0) | SEG_CODE_EXRD 93 | 94 | #define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 95 | SEG_PRIV(0) | SEG_DATA_RDWR 96 | 97 | #define GDT_CODE_PL1 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 98 | SEG_PRIV(1) | SEG_CODE_EXRD 99 | 100 | #define GDT_DATA_PL1 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 101 | SEG_PRIV(1) | SEG_DATA_RDWR 102 | 103 | #define GDT_CODE_PL2 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 104 | SEG_PRIV(2) | SEG_CODE_EXRD 105 | 106 | #define GDT_DATA_PL2 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 107 | SEG_PRIV(2) | SEG_DATA_RDWR 108 | 109 | #define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 110 | SEG_PRIV(3) | SEG_CODE_EXRD 111 | 112 | #define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | \ 113 | SEG_PRIV(3) | SEG_DATA_RDWR 114 | 115 | #endif // __ARCH_X86_GDT_H 116 | -------------------------------------------------------------------------------- /src/arch/x86/include/idt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * idt.h - Headers for idt.c 4 | */ 5 | 6 | #ifndef __IDT_H 7 | #define __IDT_H 8 | 9 | #include // Types 10 | #include // memset 11 | #include 12 | 13 | extern void (*ack_irq)(unsigned); 14 | extern void (*enable_irq)(uint8_t, unsigned); 15 | 16 | typedef struct idt_entry { 17 | uint16_t base_low; 18 | uint16_t selector; 19 | uint8_t always0; 20 | uint8_t flags; 21 | uint16_t base_high; 22 | } __attribute__((packed)) idt_entry_t; 23 | 24 | typedef struct idt_ptr { 25 | uint16_t limit; 26 | uint32_t base; 27 | } __attribute__((packed)) idt_ptr_t; 28 | 29 | #define IDT_PRES(x) ((x) << 0x07) // Is the entry actually there? 30 | #define IDT_STORE(x) ((x) << 0x04) // Is this a data/code segment? 31 | #define IDT_PRIV(x) ((x) << 0x05) // CPU Ring Level 32 | 33 | #define IDT_GATE_TASK32 0x05 34 | #define IDT_GATE_INT16 0x06 35 | #define IDT_GATE_TRAP16 0x07 36 | #define IDT_GATE_INT32 0x0E 37 | #define IDT_GATE_TRAP32 0x0F 38 | 39 | #define IDT_INT32_PL0 IDT_PRES(1) | IDT_STORE(0) | IDT_PRIV(0) | \ 40 | IDT_GATE_INT32 41 | 42 | #define IDT_TRAP32_PL0 IDT_PRES(1) | IDT_STORE(0) | IDT_PRIV(0) | \ 43 | IDT_GATE_TRAP32 44 | 45 | #define IDT_TASK32_PL0 IDT_PRES(1) | IDT_STORE(0) | IDT_PRIV(0) | \ 46 | IDT_GATE_TASK32 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/arch/x86/irq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * irq.c - x86 specific IRQ driver bringup 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static resource_t at_pic0_resource = { 13 | .name = "irqchip/at_pic0", 14 | .start = 0x20, 15 | .end = 0x21, 16 | .flags = RESOURCE_IO | RESOURCE_IO_SLOW | RESOURCE_WIDTH_8, 17 | .parent = NULL, 18 | }; 19 | 20 | static resource_t at_pic1_resource = { 21 | .name = "irqchip/at_pic1", 22 | .start = 0xA0, 23 | .end = 0xA1, 24 | .flags = RESOURCE_IO | RESOURCE_IO_SLOW | RESOURCE_WIDTH_8, 25 | .parent = &at_pic0_resource, 26 | }; 27 | 28 | static irqchip_t at_pic0 = { 29 | .name = "at_pic0", 30 | .flags = IRQCHIP_CASCADE_PRIMARY, 31 | .isr_start = 32, 32 | .data = &at_pic0_resource 33 | }; 34 | 35 | static irqchip_t at_pic1 = { 36 | .name = "at_pic1", 37 | .flags = IRQCHIP_CASCADE_SECONDARY, 38 | .isr_start = 40, 39 | .data = &at_pic1_resource 40 | }; 41 | 42 | static int config[] = {0x4, 0x2}; 43 | 44 | static device_t at_pic0_dev = { 45 | .name = "at_pic0", 46 | .data = &at_pic0 47 | }; 48 | 49 | static device_t at_pic1_dev = { 50 | .name = "at_pic1", 51 | .data = &at_pic1 52 | }; 53 | 54 | int init_irq() 55 | { 56 | int i, ret; 57 | 58 | ret = device_register(&at_pic0_dev, base_device(), "irqchip/8254_pic"); 59 | ret |= device_register(&at_pic1_dev, base_device(), "irqchip/8254_pic"); 60 | ret |= device_init(&at_pic0_dev, &config[0]); 61 | ret |= device_init(&at_pic1_dev, &config[1]); 62 | 63 | // Mask all interrupts 64 | for(i = 32; i < 48; i++) { 65 | irqchip_mask(i); 66 | } 67 | // Unmask the cascade port for PIC 2 68 | irqchip_unmask(34); 69 | 70 | return ret; 71 | } 72 | -------------------------------------------------------------------------------- /src/arch/x86/ivt.s: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; (c) 2022 Apollo Project Developers ;; 3 | ;; ivt.s - x86 Interrupts - the asm part ;; 4 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 5 | 6 | [BITS 32] 7 | [EXTERN interrupt_handler] 8 | [GLOBAL idt_flush] 9 | [GLOBAL isr0] 10 | [GLOBAL isr1] 11 | 12 | %macro ISR_NOERRCODE 1 13 | isr%1: 14 | cli 15 | push %1 16 | jmp 0x08:isr_no_err_stub 17 | %endmacro 18 | 19 | %macro ISR_ERRCODE 1 20 | isr%1: 21 | cli 22 | push %1 23 | jmp 0x08:isr_common_stub 24 | %endmacro 25 | 26 | idt_flush: 27 | mov eax, [esp + 4] 28 | lidt [eax] 29 | ret 30 | 31 | isr_no_err_stub: 32 | push 0xDEADBEEF 33 | isr_common_stub: 34 | pusha 35 | mov eax, ds 36 | push eax ; Store Data Segment 37 | 38 | mov eax, 0x10 ; Kernel data selector 39 | mov ds, eax 40 | mov es, eax 41 | mov fs, eax 42 | mov gs, eax 43 | 44 | push esp 45 | 46 | call interrupt_handler 47 | add esp, 4 48 | pop eax ; get back the old data segment 49 | mov ds, eax 50 | mov es, eax 51 | mov fs, eax 52 | mov gs, eax 53 | popa 54 | add esp, 8 55 | iret 56 | 57 | ;===================; Type | Name 58 | ISR_NOERRCODE 0 ; Fault | Divide By Zero 59 | ISR_NOERRCODE 1 ; Trap | Debug 60 | ISR_NOERRCODE 2 ; Interrupt | Non-Maskable Interrupt 61 | ISR_NOERRCODE 3 ; Trap | Breakpoint 62 | ISR_NOERRCODE 4 ; Trap | Overflow 63 | ISR_NOERRCODE 5 ; Fault | Bound Range Exceeded 64 | ISR_NOERRCODE 6 ; Fault | Invalid Opcode 65 | ISR_NOERRCODE 7 ; Fault | Device Not Available 66 | ISR_ERRCODE 8 ; Abort | Double Fault 67 | ISR_NOERRCODE 9 ; Fault | Coprocesser Segment Overrun 68 | ISR_ERRCODE 10 ; Fault | Invalid TSS 69 | ISR_ERRCODE 11 ; Fault | Segment Not Present 70 | ISR_ERRCODE 12 ; Fault | Stack-Segment Fault 71 | ISR_ERRCODE 13 ; Fault | General Protection Fault 72 | ISR_ERRCODE 14 ; Fault | Page Fault 73 | ISR_NOERRCODE 15 ; | Reserved 74 | ISR_NOERRCODE 16 ; Fault | x87 Floating-Point Exception 75 | ISR_ERRCODE 17 ; Fault | Alignment Check 76 | ISR_NOERRCODE 18 ; Abort | Machine Check 77 | ISR_NOERRCODE 19 ; Fault | SIMD Floating Point Exception 78 | ISR_NOERRCODE 20 ; Fault | Virtualization Exception 79 | ISR_ERRCODE 21 ; Fault | Control Protection Exception 80 | ISR_NOERRCODE 22 ; | Reserved 81 | ISR_NOERRCODE 23 ; | Reserved 82 | ISR_NOERRCODE 24 ; | Reserved 83 | ISR_NOERRCODE 25 ; | Reserved 84 | ISR_NOERRCODE 26 ; | Reserved 85 | ISR_NOERRCODE 27 ; | Reserved 86 | ISR_NOERRCODE 28 ; Fault | Hypervisor Injection Exception 87 | ISR_ERRCODE 29 ; Fault | VMM Communication Exception 88 | ISR_NOERRCODE 30 ; Fault | Security Exception 89 | ISR_NOERRCODE 31 ; | Reserved 90 | 91 | ;; Repeat 223 times (to 255) for non-CPU generated Interrupt Vectors 92 | %assign i 32 93 | %rep 223 94 | ISR_NOERRCODE i 95 | %assign i i+1 96 | %endrep 97 | 98 | -------------------------------------------------------------------------------- /src/arch/x86/link.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * Entry point for the rpi4 architecture port 5 | */ 6 | 7 | OUTPUT_ARCH("i386") 8 | OUTPUT_FORMAT("elf32-i386") 9 | 10 | /* Higher half on 32 bit addressing */ 11 | VIRT_OFFSET = 0xC0000000; 12 | 13 | /* Multiboot compliance dumps us here */ 14 | INIT_OFFSET = 0x100000; 15 | 16 | /* Defined in multiboot.s */ 17 | ENTRY(_start) 18 | 19 | /* Defines the actual sections */ 20 | INCLUDE scripts/common.ld 21 | -------------------------------------------------------------------------------- /src/arch/x86/multiboot.s: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; (c) 2022 Apollo Project Developers ;; 3 | ;; For terms, see LICENSE ;; 4 | ;; multiboot.s - talk to multiboot ;; 5 | ;; This will eventually have multiboot 2 as well ;; 6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7 | 8 | [GLOBAL mboot_hdr] 9 | [EXTERN higherhalf] 10 | 11 | ; Multiboot Macro Definitions 12 | MULTIBOOT_PAGE_ALIGN equ 1<<0 13 | MULTIBOOT_MEMORY_INFO equ 1<<1 14 | MULTIBOOT_VIDEO_MODE equ 1<<2 15 | 16 | MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 17 | 18 | MULTIBOOT_HEADER_FLAGS equ ( MULTIBOOT_MEMORY_INFO) 19 | MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 20 | 21 | ; Multiboot Header 22 | ;================== 23 | section .init 24 | 25 | align 32 26 | ; This is the multiboot header. 27 | mboot_hdr: 28 | dd MULTIBOOT_HEADER_MAGIC 29 | dd MULTIBOOT_HEADER_FLAGS 30 | dd MULTIBOOT_CHECKSUM 31 | 32 | global _start:function _start.end-_start 33 | _start: 34 | mov eax, pd ; Move magic number into pd 35 | mov dword [eax], pt + 3 ; addrs 0 - 0x400000 = pt | WRITE | PRESENT 36 | mov dword [eax+0xC00], pt+3 ; addrs 0xC0000000 - 0xC0400000 37 | 38 | ;; Loop through all 1024 pages in pt, set them to identity mapped 39 | mov edx, pt ; 40 | mov ecx, 0 ; start a loop 41 | .loop: 42 | mov eax, ecx ; grab loop number 43 | shl eax, 12 ; basically add 0xC0000000 to the address 44 | or eax, 3 ; Bit twiddling (Write | Present) 45 | mov [edx+ecx*4], eax ; pt[ecx * sizeof(entry)] -> tmp 46 | 47 | inc ecx ; 48 | cmp ecx, 1024 ; End condition 49 | jnz .loop ; loop back otherwise 50 | 51 | mov eax, pd+3 ; load page directory 52 | mov cr3, eax ; load into cr3 53 | mov eax, cr0 ; grab cr0 54 | or eax, 0x80000000 ; set PG Bit 55 | mov cr0, eax ; push cr0 back 56 | jmp higherhalf ; start kernel proper 57 | .end: ; end of function 58 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 59 | 60 | ; Multiboot Padding 61 | section .init.bss nobits 62 | pd: resb 0x1000 ; Descriptors 63 | pt: resb 0x1000 ; Page table 64 | -------------------------------------------------------------------------------- /src/arch/x86/ports.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2024 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * ports.c - x86 I/O databus commends 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void iowait(void) 13 | { 14 | // Port 0x80 is used for POST checkpoints, so it's safe to use 15 | // As a "scrap" port to throw data to as a bus wait. 16 | // On a side note, port 0x80 shows up on certain MoBo's as a diagnostic 17 | // for POST Codes, so that's kinda cool. 18 | __asm__ __volatile__ ("outb 0x80, %0" : : "a" ((unsigned char)0)); 19 | } 20 | 21 | static void io_write_8(uint16_t port, void* data) 22 | { 23 | uint8_t value = *(uint8_t *)data; 24 | __asm__ __volatile__ ("outb %0, %1" : : "dN" (port), "a" (value)); 25 | } 26 | 27 | static void io_write_16(uint16_t port, void* data) 28 | { 29 | uint16_t value = *(uint16_t *)data; 30 | __asm__ __volatile__ ("outw %0, %1" : : "dN" (port), "a" (value)); 31 | } 32 | 33 | static void io_write_32(uint16_t port, void* data) 34 | { 35 | uint32_t value = *(uint32_t *)data; 36 | __asm__ __volatile__ ("out %0, %1" : : "dN" (port), "a" (value)); 37 | } 38 | 39 | static void io_read_8(uint16_t port, void* data) 40 | { 41 | uint8_t ret; 42 | __asm__ __volatile__ ("inb %0, %1" : "=a" (ret) : "dN" (port)); 43 | *(uint8_t*)data = ret; 44 | } 45 | 46 | static void io_read_16(uint16_t port, void* data) 47 | { 48 | uint16_t ret; 49 | __asm__ __volatile__ ("inw %0, %1" : "=a" (ret) : "dN" (port)); 50 | *(uint16_t*)data = ret; 51 | } 52 | 53 | static void io_read_32(uint16_t port, void* data) 54 | { 55 | uint32_t ret; 56 | __asm__ __volatile__ ("in %0, %1" : "=a" (ret) : "dN" (port)); 57 | *(uint32_t*)data = ret; 58 | } 59 | 60 | static int resource_io_data_op(void *src, resource_t *r, resource_type_t off, 61 | size_t n, int read) 62 | { 63 | int width; 64 | size_t i; 65 | void (*io_op)(uint16_t, void *); 66 | if(read == 1) 67 | { 68 | switch(r->flags & RESOURCE_WIDTH) 69 | { 70 | case RESOURCE_WIDTH_8: 71 | io_op = io_read_8; 72 | width = 1; 73 | break; 74 | case RESOURCE_WIDTH_16: 75 | io_op = io_read_16; 76 | width = 2; 77 | break; 78 | case RESOURCE_WIDTH_32: 79 | io_op = io_read_32; 80 | width = 4; 81 | break; 82 | default: 83 | return -EIO; 84 | } 85 | } 86 | 87 | else 88 | { 89 | switch (r->flags & RESOURCE_WIDTH) 90 | { 91 | case RESOURCE_WIDTH_8: 92 | io_op = io_write_8; 93 | width = 1; 94 | break; 95 | case RESOURCE_WIDTH_16: 96 | io_op = io_write_16; 97 | width = 2; 98 | break; 99 | case RESOURCE_WIDTH_32: 100 | io_op = io_write_32; 101 | width = 4; 102 | break; 103 | default: 104 | return -EIO; 105 | } 106 | } 107 | switch(r->flags & 0x0F) 108 | { 109 | case RESOURCE_IO_LINEAR: /* Standard linear addressing IO Write */ 110 | off += r->start; 111 | for(i = 0; i < n; i += width) 112 | { 113 | if(r->flags & RESOURCE_IO_SLOW) 114 | { 115 | iowait(); 116 | } 117 | io_op(off + i, (src + i)); 118 | } 119 | break; 120 | 121 | case RESOURCE_IO_FIFO: /* Write to the same port, over and over */ 122 | for(i = 0; i < n; i++) 123 | { 124 | if(r->flags & RESOURCE_IO_SLOW) 125 | { 126 | iowait(); 127 | } 128 | 129 | io_op(r->start, (src + i)); 130 | } 131 | break; 132 | 133 | case RESOURCE_IO_INDEXED: /* Write to the indexing port, then data */ 134 | for(i = 0; i < n; i++) 135 | { 136 | uint8_t index = (off + i); 137 | if(r->flags & RESOURCE_IO_SLOW) 138 | { 139 | iowait(); 140 | } 141 | io_write_8(r->start, &index); 142 | io_op(r->end, (src + i)); 143 | } 144 | break; 145 | 146 | default: 147 | return -ENOTSUPP; 148 | } 149 | 150 | return 0; 151 | } 152 | 153 | int resource_io_write(void *src, resource_t *r, resource_type_t off, size_t n) 154 | { 155 | return resource_io_data_op(src, r, off, n, 0); 156 | } 157 | 158 | int resource_io_read(void *dest, resource_t *r, resource_type_t off, size_t n) 159 | { 160 | return resource_io_data_op(dest, r, off, n, 1); 161 | } 162 | 163 | inline uint32_t read_cr0() 164 | { 165 | uint32_t ret; 166 | __asm__ __volatile__ ("mov %0, cr0" : "=r" (ret)); 167 | return ret; 168 | } 169 | 170 | inline uint32_t read_cr2() 171 | { 172 | uint32_t ret; 173 | __asm__ __volatile__ ("mov %0, cr2" : "=r" (ret)); 174 | return ret; 175 | } 176 | 177 | inline uint32_t read_cr3() 178 | { 179 | uint32_t ret; 180 | __asm__ __volatile__ ("mov %0, cr3" : "=r" (ret)); 181 | return ret; 182 | } 183 | 184 | inline void write_cr0(uint32_t val) 185 | { 186 | __asm__ __volatile__ ("mov cr0, %0" : : "r" (val)); 187 | } 188 | 189 | inline void write_cr2(uint32_t val) 190 | { 191 | __asm__ __volatile__ ("mov cr2, %0" : : "r" (val)); 192 | } 193 | 194 | inline void write_cr3(uint32_t val) 195 | { 196 | __asm__ __volatile__ ("mov cr3, %0" : : "r" (val)); 197 | } 198 | -------------------------------------------------------------------------------- /src/arch/x86/start.s: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; (c) 2018 - 2022 Apollo Project Developers ;; 3 | ;; For terms, see LICENSE ;; 4 | ;; start.s - x86 bootloader passover ;; 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | ; Kernel Stack size definition up here for visibility 8 | KERNEL_STACK_SIZE equ 0x4000 9 | 10 | [BITS 32] 11 | [GLOBAL start] 12 | [EXTERN arch_init] 13 | [GLOBAL KERNEL_STACK] 14 | [EXTERN code] 15 | [EXTERN bss] 16 | [EXTERN end] 17 | 18 | ;============================; 19 | ; Bootloader's dropoff point ; 20 | ; Dropped here from start ; 21 | ;============================; 22 | section .text 23 | global higherhalf:function higherhalf.end-higherhalf 24 | higherhalf: 25 | mov esp, stack ; Multiboot doesnt give us a valid stack 26 | xor ebp, ebp ; Clear the stack frame 27 | push ebx ; Should be multiboot header 28 | cli ; Make sure we don't get any errornous interrupts 29 | call arch_init ; Pass control to C 30 | cli ; 31 | jmp $ ; endless loop 32 | hlt ; Deadlock Stop. 33 | jmp $ ; In case we get an NMI 34 | .end: ; 35 | ;;;;;;;;;;;;;;;;;;;;;;;;; 36 | 37 | ; Stack 38 | ;======= 39 | section .bss 40 | ALIGN 8192 41 | global stack_base 42 | stack_base: 43 | resb KERNEL_STACK_SIZE 44 | stack: ; label for esp only (bottom of the stack) 45 | -------------------------------------------------------------------------------- /src/arch/x86/vmm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2019 Apollo Developers 3 | * For terms, see LICENSE 4 | * vmm.c - x86 virtual memory manager - requires a 486 or higher 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef DEBUG_vmm 13 | # define dbg(args...) printf("vmm: " args) 14 | #else 15 | # define dbg(args...) 16 | #endif 17 | 18 | // Defined in platform specific HAL 19 | static address_space_t *current = NULL; 20 | 21 | static spinlock_t global_vmm_lock = SPINLOCK_RELEASED; 22 | 23 | // Helper functions to map x86-specific page flags 24 | 25 | static int from_x86_flags(int flags) 26 | { 27 | int f = 0; 28 | if (flags & X86_WRITE) f |= PAGE_WRITE; 29 | if (flags & X86_EXECUTE) f |= PAGE_EXECUTE; 30 | if (flags & X86_USER) f |= PAGE_USER; 31 | if (flags & X86_COW) f |= PAGE_COW; 32 | return f; 33 | } 34 | 35 | static int to_x86_flags(int flags) 36 | { 37 | int f = 0; 38 | if (flags & PAGE_WRITE) f |= X86_WRITE; 39 | if (flags & PAGE_USER) f |= X86_USER; 40 | if (flags & PAGE_EXECUTE) f |= X86_EXECUTE; 41 | if (flags & PAGE_COW) f |= X86_COW; 42 | return f; 43 | } 44 | 45 | address_space_t *get_current_address_space() 46 | { 47 | return current; 48 | } 49 | 50 | int switch_address_space(address_space_t *dest) 51 | { 52 | write_cr3((uintptr_t)dest->directory | X86_PRESENT | X86_WRITE); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/core/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # Core Code Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | obj_y = hal.c main.c kmain.c 8 | obj_y += locking.c 9 | obj_y += early_pmm.c resource.c devices.c 10 | -------------------------------------------------------------------------------- /src/core/devices.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * Device bootstrap and initialization 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | extern device_driver_t __drivers_begin, __drivers_end; 12 | 13 | static device_t root_device = { 14 | .name = "sys", 15 | .parent = NULL 16 | }; 17 | 18 | static device_driver_t *find_driver(const char *name) 19 | { 20 | for(device_driver_t *i = &__drivers_begin, *e = &__drivers_end; 21 | i < e; i++) { 22 | if (!strcmp(name, i->compat)) { 23 | return i; 24 | } 25 | } 26 | return NULL; 27 | } 28 | 29 | static void device_register_child(device_t *p, device_t *c) 30 | { 31 | if(p == NULL) { 32 | return; 33 | } 34 | c->parent = p; 35 | 36 | if(p->child == NULL) { 37 | p->child = c; 38 | return; 39 | } 40 | 41 | p = p->child; 42 | while(p->sibling != NULL) { 43 | p = p->sibling; 44 | } 45 | p->sibling = c; 46 | } 47 | 48 | static void device_unregister_child(device_t *p, device_t *c) 49 | { 50 | if(p == NULL) { 51 | return; 52 | } 53 | 54 | if(p->child == c) { 55 | p->child = NULL; 56 | return; 57 | } 58 | 59 | p = p->child; 60 | while (p->sibling != c) { 61 | if(p->sibling == NULL) { 62 | return; 63 | } 64 | p = p->sibling; 65 | } 66 | 67 | p->sibling = c->sibling; 68 | } 69 | 70 | device_t *base_device() 71 | { 72 | return &root_device; 73 | } 74 | 75 | int device_register(device_t *device, device_t *parent, const char *compat) 76 | { 77 | if(device == NULL) { 78 | return -EINVAL; 79 | } 80 | device->driver = find_driver(compat); 81 | 82 | device_register_child(parent, device); 83 | 84 | return 0; 85 | } 86 | 87 | int device_init(device_t *device, void *config) 88 | { 89 | if(device == NULL) { 90 | return -EINVAL; 91 | } 92 | 93 | if(device->driver == NULL) { 94 | return -ENODEV; 95 | } 96 | 97 | if(device->driver->init == NULL) { 98 | return -EOPNOTSUPP; 99 | } 100 | 101 | return device->driver->init(device, config); 102 | } 103 | 104 | int device_unregister(device_t *device) 105 | { 106 | if(device == NULL) { 107 | return -ENODEV; 108 | } 109 | 110 | while(device->child != NULL) { 111 | device_unregister(device->child); 112 | device->child = device->child->sibling; 113 | } 114 | 115 | device_unregister_child(device->parent, device); 116 | 117 | if(device->driver != NULL) { 118 | if(device->driver->fini != NULL) { 119 | return device->driver->fini(device); 120 | } 121 | } 122 | return 0; 123 | } 124 | 125 | int device_api_call(device_t *device, void *data) 126 | { 127 | if(device == NULL) { 128 | return -EINVAL; 129 | } 130 | if(device->driver == NULL) { 131 | return -ENODEV; 132 | } 133 | if(device->driver->api == NULL) { 134 | return -ENOSYS; 135 | } 136 | return device->driver->api(device, data); 137 | } 138 | 139 | /* Driver for the root device, this is here so the linker doesn't yell at us */ 140 | DRIVER = { 141 | .compat = "root", 142 | .init = NULL, 143 | .fini = NULL, 144 | .api = NULL 145 | }; 146 | -------------------------------------------------------------------------------- /src/core/early_pmm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2019 Apollo Developers 3 | * For terms, see LICENSE 4 | * early_pmm.c - trivial physical memory manager for pre-virtual memory manager 5 | * enviorment 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Debugging needs printf. defined somewhere else, probably 13 | #ifdef DEBUG_early_pmm 14 | # include 15 | # define dbg(args...) printf("early_pmm: " args) 16 | #else 17 | # define dbg(args...) 18 | #endif 19 | 20 | // The system (another module) gives us ranges of free memory, 21 | // We're gonna modify them in place 22 | 23 | range_t early_ranges[128]; 24 | unsigned early_nranges; 25 | // Largest valid memory address 26 | uint64_t early_max_extent; 27 | 28 | // Copy the ranges. Be simple with it, if something complex happens? Let's panic 29 | int init_physical_memory_early(range_t *ranges, unsigned nranges, uint64_t max) 30 | { 31 | assert(pmm_init_stage == PMM_INIT_START && "Early mem init called twice!"); 32 | assert(nranges < 128 && "Too many ranges!"); 33 | // You ever read a word too many times and it stops being a word? 34 | // Well, "ranges" 35 | // BTW, we're just gonna copy everything here 36 | memcpy(early_ranges, ranges, nranges * sizeof(range_t)); 37 | early_nranges = nranges; 38 | early_max_extent = max; 39 | 40 | pmm_init_stage = PMM_INIT_EARLY; 41 | return 0; 42 | } 43 | 44 | uint64_t early_alloc_page() 45 | { 46 | // This should only be called if the function above was run, but not after 47 | // the virtual memory is online either 48 | unsigned i; 49 | assert(pmm_init_stage == PMM_INIT_EARLY); 50 | for(i = 0; i < early_nranges; i++) { 51 | if(early_ranges[i].extent <= 0x1000 || 52 | early_ranges[i].start >= 0x100000000ULL) { 53 | // Throw away pages that exist over 4GB for now, or tinier than 4k. 54 | continue; 55 | } 56 | // Under 1MB? Ignore it! 57 | if(early_ranges[i].start < 0x100000) { 58 | continue; 59 | } 60 | uint32_t ret = (uint32_t)early_ranges[i].start; 61 | early_ranges[i].start += 0x1000; 62 | early_ranges[i].extent -= 0x1000; 63 | 64 | dbg("early_allog_page() -> %x\n", ret); 65 | return ret; 66 | } 67 | panic("Early_alloc_page couldn't find any pages to use!"); 68 | } 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/core/kmain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef GITREV 7 | #define GITREV 1 8 | #endif 9 | 10 | extern uint32_t free_memory_get_megs(); 11 | 12 | char* spinny[] = {"|","/","-","\\"}; 13 | 14 | void kmain(int argc, char **argv) 15 | { 16 | int i; 17 | int proc_count = get_num_processors(); 18 | int major = hal_version_major(); 19 | int minor = hal_version_minor(); 20 | printf("Apollo Kernel Version %d.%d (Build %s).\n", major, minor, GITREV); 21 | printf("%d System Processor", proc_count); 22 | 23 | if(proc_count > 1) 24 | { 25 | printf("s"); 26 | } 27 | 28 | printf(" [%d MB Memory]\n", free_memory_get_megs()); 29 | 30 | printf("\nKernel Arguments:\n"); 31 | 32 | for(i = 0; i < argc; i++) 33 | { 34 | printf(" [%d] = %s\n", i, argv[i]); 35 | } 36 | uint64_t t0 = get_timestamp(); 37 | uint64_t t1 = 500000; 38 | i = 0; 39 | printf(" "); 40 | while(1) 41 | { 42 | if(get_timestamp() > (t0 + t1)) 43 | { 44 | i++; 45 | t0 += t1; 46 | if(i > 3) 47 | { 48 | i = 0; 49 | } 50 | printf("\b%s", spinny[i]); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/core/locking.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void spinlock_init(spinlock_t *lock) 4 | { 5 | lock->val = 0; 6 | lock->interrupts = 0; 7 | } 8 | 9 | void spinlock_acquire(spinlock_t *lock) 10 | { 11 | int interrupts = get_interrupt_state(); 12 | 13 | disable_interrupts(); 14 | while (__sync_bool_compare_and_swap(&lock->val, 0, 1) == 0) 15 | { 16 | ; // Wait for sync 17 | } 18 | lock->interrupts = interrupts; 19 | } 20 | 21 | void spinlock_release(spinlock_t *lock) 22 | { 23 | while (__sync_bool_compare_and_swap(&lock->val, 1, 0) == 0) 24 | { 25 | ; // Wait for sync 26 | } 27 | set_interrupt_state(lock->interrupts); 28 | } 29 | -------------------------------------------------------------------------------- /src/core/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * Main.c - Main function of kernel activity 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // These are defined by the linker from the "modules" section 12 | extern module_t __modules_begin, __modules_end; 13 | 14 | // Function definitions that are only used inside main. (these will be moved) 15 | static void earlypanic(const char *msg, const char *msg2); 16 | static module_t *find_module(const char *name); 17 | static void fini_module(module_t *m); 18 | static void log_status(int status, const char *name, const char *text); 19 | 20 | // TODO: put these in a header 21 | void set_log_level(int); 22 | void resolve_module(module_t *m); 23 | void init_module(module_t *m); 24 | 25 | // This variable will be overridden if we are in a test harness. 26 | module_t *test_module __attribute__((weak)) = (module_t*)NULL; 27 | 28 | static int logLevel; 29 | 30 | static int search_argv(const char* arg, int argc, char **argv) 31 | { 32 | int i; 33 | for(i = 0; i < argc; i++) 34 | { 35 | if(strcmp(argv[i], arg) == 0) { 36 | return 1; 37 | } 38 | } 39 | return 0; 40 | } 41 | 42 | int main(int argc, char* argv[]) 43 | { 44 | int log_level_setting = search_argv("debug=y", argc, argv); 45 | 46 | set_log_level(log_level_setting); // Turn on logging 47 | // Set all module states to not initialised so the dependency tree works 48 | for(module_t *m = &__modules_begin, *e = &__modules_end; m < e; m++) { 49 | m->state = MODULE_NOT_INITIALISED; 50 | } 51 | // Resolve prereqs of the module. 52 | 53 | for(module_t *m = &__modules_begin, *e = &__modules_end; m < e; m++) { 54 | resolve_module(m); 55 | } 56 | 57 | // Init the console first, that way we have output. 58 | 59 | module_t *console = find_module("console"); 60 | if(console) { 61 | init_module(console); 62 | } 63 | 64 | for(module_t *m = &__modules_begin, *e = &__modules_end; m < e; m++) { 65 | if((m != test_module) && (m != console)) { // this should be done last! 66 | init_module(m); 67 | } 68 | } 69 | if(test_module && TEST_HARNESS == 1) { 70 | set_log_level(0); 71 | init_module(test_module); 72 | } else { 73 | enable_interrupts(); 74 | kmain(argc, argv); 75 | } 76 | set_log_level(log_level_setting); // This could have been changed elsewhere. 77 | 78 | // We've returned from kernel, that means we're shutting down. 79 | // Run the finishing modules. 80 | for(module_t *m = &__modules_begin, *e = &__modules_end; m < e; m++) { 81 | fini_module(m); 82 | } 83 | #ifndef HOSTED 84 | for(;;); // Spin loop 85 | #endif 86 | return 0; 87 | } 88 | 89 | void set_log_level(int l) 90 | { 91 | logLevel = l; 92 | } 93 | 94 | void resolve_module(module_t *m) 95 | { 96 | // Did we already resolve the pre-requisites? 97 | if (m->state >= MODULE_PREREQS_RESOLVED) { 98 | return; 99 | } 100 | // Find the required modules first 101 | for (prereq_t *p = m->required; p != NULL && p->name != NULL; p++) { 102 | p->module = find_module(p->name); 103 | } 104 | // Find the "soft" requirements next. 105 | for (prereq_t *p = m->load_after; p != NULL && p->name != NULL; p++) { 106 | p->module = find_module(p->name); 107 | } 108 | // Finally change state to show prereqs resolved. 109 | m->state = MODULE_PREREQS_RESOLVED; 110 | } 111 | 112 | // Initialize the module! 113 | void init_module(module_t *m) 114 | { 115 | if (m->state >= MODULE_INIT_RUN) { 116 | return; 117 | } 118 | m->state = MODULE_INIT_RUN; 119 | 120 | if (m->required) { 121 | for (prereq_t *p = m->required; p != NULL && p->name != NULL; p++) { 122 | if (!p->module) { 123 | earlypanic("Module not found: ", p->name); 124 | } else { 125 | init_module(p->module); 126 | } 127 | } 128 | } 129 | if (m->load_after) { 130 | for (prereq_t *p = m->load_after; p != NULL && p->name != NULL; p++) { 131 | if (p->module) { 132 | init_module(p->module); 133 | } 134 | } 135 | } 136 | if (m->init) { 137 | int ok = m->init(); 138 | log_status(ok, m->name, "Started"); 139 | } else { 140 | log_status(-1, m->name, "No init() found!"); 141 | } 142 | } 143 | 144 | static void fini_module(module_t *m) 145 | { 146 | if (m->state != MODULE_INIT_RUN) { 147 | return; 148 | } 149 | m->state = MODULE_FINI_RUN; 150 | 151 | if (m->required) { 152 | for (prereq_t *p = m->required; p != NULL && p->name != NULL; p++) { 153 | if(!p->module) { 154 | earlypanic("Module not found: ", p->name); 155 | } else { 156 | fini_module(p->module); 157 | } 158 | } 159 | } 160 | 161 | if (m->load_after) { 162 | for (prereq_t *p = m->load_after; p != NULL && p->name != NULL; p++) { 163 | if(p->module) { 164 | fini_module(p->module); 165 | } 166 | } 167 | } 168 | 169 | if (m->fini) { 170 | int ok = m->fini(); 171 | log_status(ok, m->name, "Stopped"); 172 | } 173 | } 174 | 175 | static module_t *find_module(const char *name) 176 | { 177 | for(module_t *i = &__modules_begin, *e = &__modules_end; i < e; i++) { 178 | if (!strcmp(name, i->name)) { 179 | return i; 180 | } 181 | } 182 | return NULL; 183 | } 184 | 185 | static void log_status(int status, const char *name, const char *text) { 186 | if (logLevel == 0) { 187 | return; // No logging enabled 188 | } 189 | if (status == 0) { 190 | printf("[\033[32m OK \033[0m] "); 191 | } else { 192 | printf("[\033[31mFAILED\033[0m] "); 193 | } 194 | printf("%s %s\n", text, name); 195 | #ifdef HOSTED 196 | printf("main: %s %s with status %d\n", text, name, status); 197 | #endif 198 | } 199 | 200 | static void earlypanic(const char *msg, const char *msg2) { 201 | write_console("PANIC! ", 7); 202 | write_console(msg, strlen(msg)); 203 | if(msg2) { 204 | write_console(msg2, strlen(msg2)); 205 | } 206 | write_console("\n", 1); 207 | 208 | #ifdef HOSTED 209 | printf("main: PANIC! %s %s\n", msg, msg2); 210 | #endif 211 | for (;;); 212 | } 213 | -------------------------------------------------------------------------------- /src/core/testing/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # Core Testing Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | testing_y += interrupt_test.c 8 | -------------------------------------------------------------------------------- /src/core/testing/interrupt_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST_GROUP(interrupt_test); 5 | 6 | static volatile uint32_t testVar; 7 | 8 | static int callback(struct regs *r, void *p) 9 | { 10 | testVar = (uint32_t)p; 11 | return 0; 12 | } 13 | 14 | TEST_SETUP(interrupt_test) 15 | { 16 | testVar = 0; 17 | register_interrupt_handler(3, &callback, (void*)0xDEADBEEF); 18 | } 19 | TEST_TEAR_DOWN(interrupt_test) 20 | { 21 | unregister_interrupt_handler(3, &callback, (void*)0xDEADBEEF); 22 | } 23 | 24 | 25 | TEST(interrupt_test, pointerDataTest) 26 | { 27 | trap(); 28 | TEST_ASSERT_EQUAL(0xDEADBEEF, testVar); 29 | } 30 | 31 | TEST(interrupt_test, actuallyUnregisters) 32 | { 33 | unregister_interrupt_handler(3, &callback, (void*)0xDEADBEEF); 34 | trap(); 35 | TEST_ASSERT_EQUAL(0, testVar); 36 | } 37 | 38 | TEST(interrupt_test, TooManyHandlers) 39 | { 40 | // This should fail after 4 registered 41 | // We already have 1 from the setup. 42 | int i = 1; 43 | while(register_interrupt_handler(3, &callback, (void*)i) == 0) { 44 | i++; 45 | if(i > 300) { // arbitrarily large number 46 | break; 47 | } 48 | } 49 | TEST_ASSERT_EQUAL(4, i); 50 | // unregister all the interrupts we assigned. 51 | while(unregister_interrupt_handler(3, &callback, (void*)i--) == 0); 52 | } 53 | -------------------------------------------------------------------------------- /src/drivers/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Drivers" 2 | source "src/drivers/clock/Kconfig" 3 | 4 | source "src/drivers/base/Kconfig" 5 | 6 | source "src/drivers/console/Kconfig" 7 | 8 | source "src/drivers/irqchip/Kconfig" 9 | 10 | source "src/drivers/framebuffer/Kconfig" 11 | 12 | endmenu 13 | -------------------------------------------------------------------------------- /src/drivers/base/Kconfig: -------------------------------------------------------------------------------- 1 | if BASE_SYSTEM 2 | 3 | menu "Base System Drivers" 4 | 5 | config QEMU_SHUTDOWN 6 | bool "QEMU Shutdown Hack" 7 | depends on X86_BASE 8 | help 9 | Allow QEMU to be shut down and exit without using ACPI Calls. 10 | 11 | config BCM2711_GPIO 12 | bool "BCM2711 GPIO Driver" 13 | depends on RPI4_BASE 14 | help 15 | Allow configuration of the BCM2711's GPIO pins. 16 | endmenu 17 | 18 | endif 19 | -------------------------------------------------------------------------------- /src/drivers/base/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # Base Drivers Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | # qemu shutdown hack for the qemu emulator 8 | obj_$(CONFIG_QEMU_SHUTDOWN) += qemu_shutdown.c 9 | obj_$(CONFIG_BCM2711_GPIO) += bcm2711_gpio.c 10 | -------------------------------------------------------------------------------- /src/drivers/base/bcm2711_gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * bcm2711_gpio.c - Driver to control the GPIO pins of the BCM2711 SoC 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "include/bcm2711_gpio.h" 12 | 13 | static int gpio_call(device_t *dev, uint32_t pin, uint32_t val, int reg, 14 | int field_sz, int read) 15 | { 16 | uint32_t current_value; 17 | int num_fields = 32 / field_sz; 18 | int bitshift = (pin % num_fields) * field_sz; 19 | resource_type_t off = (pin / num_fields) + reg; 20 | unsigned int field_mask = (1 << field_sz) - 1; 21 | 22 | if (pin > GPIO_MAX_PIN) { 23 | return -EINVAL; 24 | } 25 | if (val > field_mask) { 26 | return -EINVAL; 27 | } 28 | 29 | if(resource_read(¤t_value, dev->access, off, 1)) { 30 | return -EIO; 31 | } 32 | 33 | if(read) 34 | { 35 | return (current_value >> bitshift) & field_mask; 36 | } 37 | 38 | // Clear out bits related to what we're changing 39 | current_value &= ~(field_mask << bitshift); 40 | // Inject value into correct position 41 | current_value |= val << bitshift; 42 | return resource_write(¤t_value, dev->access, off, 1); 43 | } 44 | 45 | static int gpio_function(device_t *dev, int pin_number, int value) 46 | { 47 | return gpio_call(dev, pin_number, value, GPFSEL_REG, GPFSEL_FIELD_SIZE, 0); 48 | } 49 | 50 | static int gpio_pull(device_t *dev, int pin_number, int value) 51 | { 52 | return gpio_call(dev, pin_number, value, GPPULL_REG, GPPULL_FIELD_SIZE, 0); 53 | } 54 | 55 | static int api_call(device_t *dev, void *api_data) 56 | { 57 | int32_t *data = (int32_t *)api_data; 58 | switch(data[0]) 59 | { 60 | case 0: // Set GPIO to Input (data[1] = pin) 61 | return gpio_function(dev, data[1], GPIO_FUNCTION_INPUT); 62 | case 1: // Set GPIO to Output (data[1] = pin) 63 | return gpio_function(dev, data[1], GPIO_FUNCTION_OUTPUT); 64 | case 2: // Set GPIO to ALT0 (data[1] = pin) 65 | return gpio_function(dev, data[1], GPIO_FUNCTION_ALT0); 66 | case 3: // Set GPIO to ALT1 (data[1] = pin) 67 | return gpio_function(dev, data[1], GPIO_FUNCTION_ALT1); 68 | case 4: // Set GPIO to ALT2 (data[1] = pin) 69 | return gpio_function(dev, data[1], GPIO_FUNCTION_ALT2); 70 | case 5: // Set GPIO to ALT3 (data[1] = pin) 71 | return gpio_function(dev, data[1], GPIO_FUNCTION_ALT3); 72 | case 6: // Set GPIO to ALT4 (data[1] = pin) 73 | return gpio_function(dev, data[1], GPIO_FUNCTION_ALT4); 74 | case 7: // Set GPIO to ALT5 (data[1] = pin) 75 | return gpio_function(dev, data[1], GPIO_FUNCTION_ALT5); 76 | case 8: // Set GPIO Pin Pull (None) 77 | return gpio_pull(dev, data[1], GPIO_PULL_NONE); 78 | case 9: // Set GPIO Pin Pull (None) 79 | return gpio_pull(dev, data[1], GPIO_PULL_UP); 80 | case 10: // Set GPIO Pin Pull (None) 81 | return gpio_pull(dev, data[1], GPIO_PULL_DOWN); 82 | default: 83 | return -EOPNOTSUPP; 84 | } 85 | return 0; 86 | } 87 | 88 | static int init(device_t *dev, void *p) 89 | { 90 | return 0; // No actual initialization needed here! 91 | } 92 | 93 | DRIVER = { 94 | .compat = "gpio/bcm2711", 95 | .api = &api_call, 96 | .init = &init 97 | }; 98 | -------------------------------------------------------------------------------- /src/drivers/base/include/bcm2711_gpio.h: -------------------------------------------------------------------------------- 1 | #define GPIO_MAX_PIN 53 2 | 3 | // Register Offsets 4 | #define GPFSEL_REG 0x00 // Pin Function Select 5 | #define GPFSET_REG 0x07 // Pin Output Set 6 | #define GPCLR_REG 0x0A // Pin Output Clear 7 | #define GPLEV_REG 0x0D // Pin Level 8 | #define GPED_REG 0x10 // Pin Event Detcet Status 9 | #define GPREN_REG 0x13 // Pin Rising Edge Dectect Enable 10 | #define GPFEN_REG 0x16 // Pin Falling Edge Detect Enable 11 | #define GPHEN_REG 0x19 // Pin High Detect Enable 12 | #define GPLEN_REG 0x1C // Pin Low Detect Enable 13 | #define GPAREN_REG 0x1F // Pin Async. Rising Edge Detect 14 | #define GPAFEN_REG 0x22 // Pin Async. Falling Edge Detect 15 | #define GPPULL_REG 0x39 // Pin Pull-up/Pull-down 16 | 17 | // Register Field Size (Number of Bits per GPIO line) 18 | #define GPFSEL_FIELD_SIZE 3 19 | #define GPFSET_FIELD_SIZE 1 20 | #define GPCLR_FIELD_SIZE 1 21 | #define GPLEV_FIELD_SIZE 1 22 | #define GPED_FIELD_SIZE 1 23 | #define GPREN_FIELD_SIZE 1 24 | #define GPFEN_FIELD_SIZE 1 25 | #define GPHEN_FIELD_SIZE 1 26 | #define GPLEN_FIELD_SIZE 1 27 | #define GPAREN_FIELD_SIZE 1 28 | #define GPAFEN_FIELD_SIZE 1 29 | #define GPPULL_FIELD_SIZE 2 30 | 31 | // GPIO Function Selections 32 | 33 | #define GPIO_FUNCTION_INPUT 0x00 34 | #define GPIO_FUNCTION_OUTPUT 0x01 35 | #define GPIO_FUNCTION_ALT0 0x04 36 | #define GPIO_FUNCTION_ALT1 0x05 37 | #define GPIO_FUNCTION_ALT2 0x06 38 | #define GPIO_FUNCTION_ALT3 0x07 39 | #define GPIO_FUNCTION_ALT4 0x03 40 | #define GPIO_FUNCTION_ALT5 0x02 41 | 42 | // GPIO Pull-up/Pull-down Selection 43 | #define GPIO_PULL_NONE 0x00 44 | #define GPIO_PULL_UP 0x01 45 | #define GPIO_PULL_DOWN 0x02 46 | -------------------------------------------------------------------------------- /src/drivers/base/qemu_shutdown.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * qemu_shutdown.c - Driver for the x86 emulator qemu to allow quick shutdown 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | static resource_t old_qemu = { 11 | .start = 0xB004, 12 | .end = 0xB004, 13 | .flags = RESOURCE_IO 14 | }; 15 | 16 | static resource_t new_qemu = { 17 | .start = 0x604, 18 | .end = 0x604, 19 | .flags = RESOURCE_IO 20 | }; 21 | 22 | void system_shutdown() 23 | { 24 | uint16_t cmd = 0x2000; 25 | 26 | // First try older version (Qemu version older than 2.0) 27 | resource_write(&cmd, &old_qemu, 0, 1); 28 | // Next try newer versions 29 | resource_write(&cmd, &new_qemu, 0, 1); 30 | } 31 | -------------------------------------------------------------------------------- /src/drivers/clock/Kconfig: -------------------------------------------------------------------------------- 1 | if TIMEKEEPING 2 | menu "Timekeeping" 3 | 4 | config CLOCK_RTC_CMOS 5 | bool "RTC Driver" 6 | depends on X86_BASE 7 | help 8 | The Real Time Clock driver pulls the system time from the CMOS 9 | chip built into many systems. This enables wall time be read by 10 | the kernel. 11 | 12 | config CLOCK_8254 13 | bool "Intel 8254" 14 | depends on X86_BASE 15 | help 16 | The Intel 8254 also known as the Programmable Interval Timer 17 | is standard in all IBM-PC systems. It should be enabled to allow 18 | Timekeeping functionality unless another method is being used. 19 | 20 | endmenu 21 | endif 22 | -------------------------------------------------------------------------------- /src/drivers/clock/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # Clock Driver Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | obj_$(CONFIG_CLOCK_RTC_CMOS) += rtc-cmos.c 8 | obj_$(CONFIG_CLOCK_8254) += i8254.c 9 | 10 | test_$(CONFIG_CLOCK_8254) += i8254_test.c 11 | -------------------------------------------------------------------------------- /src/drivers/clock/i8254.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * i8254.c - Driver for the 8253/8254 Programmable Interrupt Timer 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "include/i8254.h" 12 | 13 | int i8254_configure(timekeeping_state_t *chip, int channel, int mode) 14 | { 15 | uint32_t divisor; 16 | uint8_t low, high, init_byte; 17 | uint8_t channel_select = 0; 18 | int ret; 19 | 20 | switch(channel) 21 | { 22 | case 0: 23 | channel_select = i8254_DATA_0; 24 | init_byte = i8254_CHANNEL_0; 25 | break; 26 | case 1: 27 | channel_select = i8254_DATA_1; 28 | init_byte = i8254_CHANNEL_1; 29 | break; 30 | case 2: 31 | channel_select = i8254_DATA_2; 32 | init_byte = i8254_CHANNEL_2; 33 | break; 34 | default: 35 | return -1; 36 | } 37 | 38 | switch(mode) 39 | { 40 | case 0: 41 | init_byte |= i8254_MODE_0; 42 | break; 43 | case 1: 44 | init_byte |= i8254_MODE_1; 45 | break; 46 | case 2: 47 | init_byte |= i8254_MODE_2; 48 | break; 49 | case 3: 50 | init_byte |= i8254_MODE_3; 51 | break; 52 | case 4: 53 | init_byte |= i8254_MODE_4; 54 | break; 55 | case 5: 56 | init_byte |= i8254_MODE_5; 57 | break; 58 | default: 59 | return -1; 60 | } 61 | 62 | init_byte |= i8254_LHBYTE | i8254_BIN_MODE; 63 | divisor = chip->base_frequency / chip->frequency; 64 | low = (uint8_t)(divisor & 0xFF); 65 | high = (uint8_t)((divisor >> 8) & 0xFF); 66 | 67 | ret = resource_write(&init_byte, chip->data, i8254_CMD, 1); 68 | ret |= resource_write(&low, chip->data, channel_select, 1); 69 | ret |= resource_write(&high, chip->data, channel_select, 1); 70 | 71 | return ret; 72 | } 73 | 74 | static int configure(device_t *device, void *p) 75 | { 76 | int *config = (int *)p; 77 | timekeeping_state_t *chip = (timekeeping_state_t *)device->data; 78 | return i8254_configure(chip, config[0], config[1]); 79 | } 80 | 81 | DRIVER = { 82 | .compat = "clock/i8254", 83 | .init = &configure 84 | }; 85 | -------------------------------------------------------------------------------- /src/drivers/clock/i8254_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST_GROUP(i8254_test); 5 | 6 | static volatile uint32_t testVar; 7 | 8 | static int callback(struct regs *r, void *p) 9 | { 10 | testVar++; 11 | return 0; 12 | } 13 | 14 | TEST_SETUP(i8254_test) 15 | { 16 | testVar = 0; 17 | register_interrupt_handler(32, &callback, (void*)0xDEADBEEF); 18 | } 19 | TEST_TEAR_DOWN(i8254_test) 20 | { 21 | unregister_interrupt_handler(32, &callback, (void*)0xDEADBEEF); 22 | } 23 | 24 | 25 | TEST(i8254_test, didTimePass) 26 | { 27 | while(testVar < 200); 28 | TEST_ASSERT(testVar != 0); // Make sure time has passed 29 | } 30 | 31 | TEST(i8254_test, updatedTimestamp) 32 | { 33 | uint64_t ts = get_timestamp(); 34 | while(testVar < 200); 35 | TEST_ASSERT(get_timestamp() > ts); 36 | } 37 | -------------------------------------------------------------------------------- /src/drivers/clock/include/i8254.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2022 Apollo Project Developers 3 | * i8254.h - Definitions for controlling the intel 8253/8254 4 | */ 5 | 6 | #ifndef __DRIVER_I8254_H 7 | #define __DRIVER_I8254_H 8 | #include 9 | 10 | #define i8254_DATA_0 0 11 | #define i8254_DATA_1 1 12 | #define i8254_DATA_2 2 13 | #define i8254_CMD 3 14 | 15 | #define i8254_BIN_MODE 0x00 /* 16 Bit Binary Counting Mode */ 16 | #define i8254_BCD_MODE 0x01 /* Four Digit Binary Coded Decimal Counting */ 17 | 18 | #define i8254_MODE_0 0x00 /* Interrupt on Terminal Count */ 19 | #define i8254_MODE_1 0x02 /* Hardware re-triggerable One-Shot */ 20 | #define i8254_MODE_2 0x04 /* Rate Generator */ 21 | #define i8254_MODE_3 0x06 /* Square Wave Generator */ 22 | #define i8254_MODE_4 0x08 /* Software Triggered Strobe */ 23 | #define i8254_MODE_5 0x0A /* Hardware Triggered Strobe */ 24 | 25 | #define i8254_LATCH 0x00 /* Latch Count Value Command */ 26 | #define i8254_LOBYTE 0x10 /* Access Low Byte Only */ 27 | #define i8254_HIBYTE 0x20 /* Access High Byte Only */ 28 | #define i8254_LHBYTE 0x30 /* Access Both Bytes */ 29 | 30 | #define i8254_CHANNEL_0 0x00 /* Select Channel 0 */ 31 | #define i8254_CHANNEL_1 0x40 /* Select Channel 1 */ 32 | #define i8254_CHANNEL_2 0x80 /* Select Channel 2 */ 33 | #define i8254_READBACK 0xC0 /* 8254 Readback Command */ 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /src/drivers/clock/include/rtc_cmos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtc-cmos.h - RTC and CMOS definitions 3 | */ 4 | 5 | #ifndef __RTC_CMOS_H 6 | #define __RTC_CMOS_H 7 | 8 | #include 9 | 10 | typedef struct cmos_register { 11 | uint8_t second; 12 | uint8_t minute; 13 | uint8_t hour; 14 | uint8_t day; 15 | uint8_t month; 16 | uint8_t year; 17 | uint8_t century; 18 | 19 | uint8_t registera; 20 | uint8_t registerb; 21 | uint8_t registerc; 22 | uint8_t registerd; 23 | } cmos_register_t; 24 | 25 | #define CMOS_INDEX_PORT 0x70 // TODO: Move these to a config 26 | #define CMOS_DATA_PORT 0x71 27 | 28 | #define CMOS_REGISTER_SECOND 0x00 29 | #define CMOS_REGISTER_MINUTE 0x02 30 | #define CMOS_REGISTER_HOUR 0x04 31 | #define CMOS_REGISTER_DAY 0x07 32 | #define CMOS_REGISTER_MONTH 0x08 33 | #define CMOS_REGISTER_YEAR 0x09 34 | #define CMOS_REGISTER_STATUSA 0x0A 35 | #define CMOS_REGISTER_STATUSB 0x0B 36 | #define CMOS_REGISTER_STATUSC 0x0C 37 | #define CMOS_REGISTER_STATUSD 0x0D 38 | 39 | #define CMOS_BASE_FREQUENCY 32768 40 | 41 | // Register A flags 42 | #define CMOS_UPDATE_IN_PROGRESS 0x80 43 | // Bits 4-6 are frequency divider for base clock, you shouldn't touch that 44 | // Bits 0-3 are the interrupt frequency divider 45 | 46 | // Register B flags 47 | #define CMOS_UPDATE_CLOCK 0x80 48 | #define CMOS_PERIODIC_INTERRUPT 0x40 49 | #define CMOS_ALARM_INTERRUPT 0x20 50 | #define CMOS_UPDATE_ENDED_INT 0x10 51 | #define CMOS_SQUARE_WAVE 0x08 52 | #define CMOS_BINARY_DATE_MODE 0x04 53 | #define CMOS_24_HOUR_MODE 0x02 54 | #define CMOS_DAYLIGHT_SAVINGS 0x01 55 | 56 | // Register C flag 57 | #define CMOS_INTERRUPT_REQUEST 0x80 58 | #define CMOS_INTERRUPT_OCCURED 0x40 59 | #define CMOS_ALARM_OCCURED 0x20 60 | #define CMOS_UPDATE_ENDED_OCCURED 0x10 61 | // Bottom 4 bits are reserved 62 | 63 | 64 | // Register D flags 65 | #define CMOS_VALID_RAM 0x80 66 | // The bottom 7 bits are reserved. 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/drivers/clock/rtc-cmos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Developers 3 | * For terms, see LICENSE 4 | * rtc.c - Real time clock and the CMOS backup battery 5 | */ 6 | 7 | #include 8 | #include 9 | #include "include/rtc_cmos.h" 10 | 11 | // This is cumulative days, not real "days" 12 | static const uint32_t days_from_month[12] = { 13 | // Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec 14 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 15 | }; 16 | static const uint32_t seconds_in_a_day = 86400; 17 | static const uint32_t seconds_in_a_year = 31536000; 18 | 19 | static resource_t rtc = { 20 | .name = "cmos-registers", 21 | .start = 0x70, 22 | .end = 0x71, 23 | .flags = RESOURCE_IO | RESOURCE_IO_INDEXED | RESOURCE_IO_SLOW 24 | }; 25 | 26 | // Returns number of leap days since beginning of epoch (January 1970) 27 | // This doesn't work for divisible by 100 non-leap years (2100, for example) 28 | // TODO: Fix that ^ 29 | static int leap_days(uint8_t year, uint8_t month) 30 | { 31 | int days; 32 | year -= 1972; // 1972 was a leap year (good starting point) 33 | days = (year / 4) + 1; // Add one for 1972 34 | 35 | // If it's not march or later in a leap year, fix the off by one error 36 | if ((year/4 == 0) && (month <= 2)) { 37 | days--; 38 | } 39 | 40 | return days; 41 | } 42 | 43 | static int cmos_update_in_progress() 44 | { 45 | uint8_t ret; 46 | resource_read(&ret, &rtc, CMOS_REGISTER_STATUSA, 1); 47 | return ret & 0x80; 48 | } 49 | 50 | static void read_RTC(cmos_register_t *cmos) 51 | { 52 | int interrupt_state; 53 | 54 | while(cmos_update_in_progress()); // Wait until CMOS finished an update 55 | 56 | // Atomic section 57 | interrupt_state = get_interrupt_state(); 58 | disable_interrupts(); 59 | resource_read(&(cmos->second ), &rtc, CMOS_REGISTER_SECOND, 1); 60 | resource_read(&(cmos->minute ), &rtc, CMOS_REGISTER_MINUTE, 1); 61 | resource_read(&(cmos->hour ), &rtc, CMOS_REGISTER_HOUR, 1); 62 | resource_read(&(cmos->day ), &rtc, CMOS_REGISTER_DAY, 1); 63 | resource_read(&(cmos->month ), &rtc, CMOS_REGISTER_MONTH, 1); 64 | resource_read(&(cmos->year ), &rtc, CMOS_REGISTER_YEAR, 1); 65 | resource_read(&(cmos->registera), &rtc, CMOS_REGISTER_STATUSA,1); 66 | resource_read(&(cmos->registerb), &rtc, CMOS_REGISTER_STATUSB,1); 67 | resource_read(&(cmos->registerc), &rtc, CMOS_REGISTER_STATUSC,1); 68 | resource_read(&(cmos->registerd), &rtc, CMOS_REGISTER_STATUSD,1); 69 | // End of Atomic section 70 | set_interrupt_state(interrupt_state); 71 | 72 | 73 | // Check if the time is in BCD format 74 | if (!(cmos->registerb & CMOS_BINARY_DATE_MODE)) { 75 | // Convert out of BCD, very simple 76 | cmos->second = (cmos->second & 0xF) + ((cmos->second / 16) * 10); 77 | cmos->minute = (cmos->minute & 0xF) + ((cmos->minute / 16) * 10); 78 | cmos->hour = (cmos->hour & 0xF) + ((cmos->hour / 16) * 10); 79 | cmos->day = (cmos->day & 0xF) + ((cmos->day / 16) * 10); 80 | cmos->month = (cmos->month & 0xF) + ((cmos->month / 16) * 10); 81 | cmos->year = (cmos->year & 0xF) + ((cmos->year / 16) * 10); 82 | } 83 | // Assume it's not 21xx year 84 | cmos->year += 2000; 85 | } 86 | 87 | // Returns the number of seconds since January 1st, 1970. 88 | uint32_t get_epoch_time() 89 | { 90 | uint32_t time; 91 | cmos_register_t cmos; 92 | 93 | // Populate cmos 94 | read_RTC(&cmos); 95 | // Start adding seconds 96 | time = cmos.second; 97 | time += cmos.minute * 60; 98 | time += cmos.hour * 3600; 99 | time += cmos.day * seconds_in_a_day; 100 | time += days_from_month[cmos.month] * seconds_in_a_day; 101 | time += (cmos.year - 1970) * seconds_in_a_year; 102 | 103 | // Add in Leap year's extra days 104 | time += (leap_days(cmos.year, cmos.month) * seconds_in_a_day); 105 | 106 | return time; 107 | } 108 | -------------------------------------------------------------------------------- /src/drivers/console/Kconfig: -------------------------------------------------------------------------------- 1 | if CONSOLE 2 | menu "Console Drivers" 3 | 4 | config CONSOLE_HOSTED 5 | bool "Hosted Console Support" 6 | depends on HOSTED_BASE 7 | help 8 | Driver that utilizes stdio when on a hosted system 9 | 10 | config CONSOLE_VGA 11 | bool "VGA Text Console" 12 | select FRAMEBUFFER 13 | select FRAMEBUFFER_VGA 14 | help 15 | Driver that utilizes the VGA Framebuffer for kernel console 16 | 17 | source "src/drivers/console/serial/Kconfig" 18 | 19 | endmenu 20 | 21 | endif # if CONSOLE 22 | -------------------------------------------------------------------------------- /src/drivers/console/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # Console Driver Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | # Hosted local console 8 | obj_$(CONFIG_CONSOLE_HOSTED) += hosted_console.c 9 | 10 | # Basic VGA Console 11 | obj_$(CONFIG_CONSOLE_VGA) += vga_console.c 12 | -------------------------------------------------------------------------------- /src/drivers/console/hosted_console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Developers 3 | * For terms, see LICENSE 4 | * hosted_console.c - console that interacts with a host operating system's TTY 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static struct termios orig; 14 | 15 | 16 | int c_read(console_t *obj, char *buf, int len) { 17 | fd_set set; 18 | FD_ZERO(&set); 19 | FD_SET(0, &set); 20 | struct timeval tv; 21 | memset(&tv, 0, sizeof(struct timeval)); 22 | 23 | if (select(1, &set, NULL, NULL, &tv) > 0) { 24 | return (int)read(0, buf, len); 25 | } 26 | return 0; 27 | } 28 | 29 | int c_write(console_t *obj, const char *buf, int len) { 30 | return (int)write(1, buf, len); 31 | } 32 | 33 | console_t c = { 34 | .open = NULL, 35 | .close = NULL, 36 | .read = &c_read, 37 | .write = &c_write, 38 | .flush = NULL, 39 | .data = NULL 40 | }; 41 | 42 | int init_console() { 43 | struct termios t; 44 | tcgetattr(1, &t); 45 | tcgetattr(1, &orig); 46 | 47 | t.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON); 48 | tcsetattr(1, TCSANOW, &t); 49 | 50 | register_console(&c); 51 | return 0; 52 | } 53 | 54 | // Console cleanup. 55 | int fini_console() { 56 | tcsetattr(1, TCSANOW, &orig); 57 | return 0; 58 | } 59 | 60 | static prereq_t prereqs[] = { {"console",NULL}, {NULL,NULL} }; 61 | MODULE = { 62 | .name = "hosted/console", 63 | .required = prereqs, 64 | .load_after = NULL, 65 | .init = &init_console, 66 | .fini = NULL 67 | }; 68 | -------------------------------------------------------------------------------- /src/drivers/console/include/vga.h: -------------------------------------------------------------------------------- 1 | #ifndef __VGA_TEXT_H 2 | #define __VGA_TEXT_H 3 | 4 | // VGA Colors 5 | #define VGA_C_BLACK 0 6 | #define VGA_C_BLUE 1 7 | #define VGA_C_GREEN 2 8 | #define VGA_C_CYAN 3 9 | #define VGA_C_RED 4 10 | #define VGA_C_MAGENTA 5 11 | #define VGA_C_BROWN 6 12 | #define VGA_C_LIGHTGRAY 7 13 | #define VGA_C_DARKGRAY 8 14 | #define VGA_C_LIGHTBLUE 9 15 | #define VGA_C_LIGHTGREEN 10 16 | #define VGA_C_LIGHTCYAN 11 17 | #define VGA_C_LIGHTRED 12 18 | #define VGA_C_LIGHTMAGENTA 13 19 | #define VGA_C_LIGHTBROWN 14 20 | #define VGA_C_WHITE 15 21 | 22 | #define DEFAULT_BG_COLOR VGA_C_BLUE 23 | #define DEFAULT_FG_COLOR VGA_C_LIGHTGRAY 24 | 25 | typedef struct { 26 | char escape_buf[4]; 27 | int escape_buf_idx; 28 | int escape_nums[4]; 29 | int escape_num_idx; 30 | uint8_t cursor_y; 31 | uint8_t cursor_x; 32 | 33 | device_t *dev; 34 | resource_t *framebuffer; 35 | uint16_t max_rows; 36 | uint16_t max_cols; 37 | int bg_color; 38 | int fg_color; 39 | int bold; 40 | int in_escape; 41 | } vga_console_state_t; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/drivers/console/serial/16550_uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Developers 3 | * For terms, see LICENSE 4 | * 16550_uart.c - Standard UART Driver 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "include/16550_uart.h" 12 | 13 | static int is_transmit_empty(device_t *d) { 14 | uint32_t data; 15 | resource_read(&data, d->access, UART_LSR, 1); 16 | if(data & UART_EMPTY_TRANS) { 17 | return 1; 18 | } 19 | return 0; 20 | } 21 | 22 | static void write_char(device_t *d, char c) 23 | { 24 | while(!is_transmit_empty(d)); 25 | uint32_t actual = c; 26 | resource_write(&actual, d->access, UART_RXTX, 1); 27 | } 28 | 29 | static int write(console_t *obj, const char *buffer, int len) 30 | { 31 | int i; 32 | device_t *dev = (device_t *)obj->data; 33 | for (i=0; idata; 46 | uint32_t data = 0; 47 | while((data & UART_EMPTY_DATA) == 0) { 48 | resource_read(&data, dev->access, UART_LSR, 1); 49 | } 50 | } 51 | 52 | static int open(console_t *obj) 53 | { 54 | device_t *dev = (device_t *)obj->data; 55 | // Enable Data Terminal Ready, and Request to Send 56 | uint32_t data = UART_DATA_TERM_READY | UART_REQ_TO_SEND | 57 | UART_AUX_OUTPUT_2; // Aux Output 2 enables the IRQ on PC compatibles 58 | resource_write(&data, dev->access, UART_MCR, 1); // Modem Control Register 59 | 60 | data = UART_ENABLE_FIFO | UART_FIFO_INT_8 | UART_CLEAR_RECV_FIFO | 61 | UART_CLEAR_TRANS_FIFO; // Clear out the FIFO's, reset their state. 62 | resource_write(&data, dev->access, UART_IIFIFO, 1); // FIFO Control Register 63 | 64 | data = UART_RECV_DATA_INT | UART_TRANS_EMPTY_INT | 65 | UART_RECV_STATUS_INT | UART_MODEM_STATUS_INT; // Interrupt types 66 | resource_write(&data, dev->access, UART_INTEN, 1); // Enable Interrupts 67 | 68 | return 0; 69 | } 70 | 71 | static int close(console_t *obj) 72 | { 73 | device_t *dev = (device_t *)obj->data; 74 | 75 | uint32_t data = 0; 76 | resource_write(&data, dev->access, UART_MCR, 1); // Disable Modem Controls 77 | resource_write(&data, dev->access, UART_INTEN, 1); // Disable Interrupts 78 | 79 | return 0; 80 | } 81 | 82 | static console_t dev_serial = { 83 | .open = open, 84 | .close = close, 85 | .write = write, 86 | .flush = flush, 87 | }; 88 | 89 | // We always want 8N1, baudrate is defined by p (as a uint16_t) 90 | static int init(device_t *d, void *p) 91 | { 92 | // UART Clock is in reference to 115200 baud 93 | uint16_t baud_div = (*(uint32_t *)p / 115200); 94 | uint32_t data; 95 | 96 | data = 0; 97 | resource_write(&data, d->access, UART_INTEN, 1); // Mask All Interrupts 98 | 99 | data = UART_DLAB; 100 | resource_write(&data, d->access, UART_LCR, 1); // Enable DLAB 101 | 102 | data = (baud_div & 0xFF); 103 | resource_write(&data, d->access, UART_RXTX, 1); // Divisor Low Byte 104 | data = (baud_div >> 8) & 0xFF; 105 | resource_write(&data, d->access, UART_INTEN, 1); // Divisor High Byte 106 | 107 | data = UART_DATA_BIT_8 | UART_NO_PARITY | UART_ONE_STOP_BIT; // 8N1 108 | resource_write(&data, d->access, UART_LCR, 1); // Line Protocol 109 | dev_serial.data = d; 110 | return register_console(&dev_serial); 111 | } 112 | 113 | DRIVER = { 114 | .compat = "console/serial/16550", 115 | .init = &init 116 | }; 117 | -------------------------------------------------------------------------------- /src/drivers/console/serial/Kconfig: -------------------------------------------------------------------------------- 1 | config CONSOLE_SERIAL_16550_UART 2 | bool "16550 UART Console" 3 | help 4 | Enables the 16550 driver, and enables kernel console output 5 | on the primary 16550 port. 6 | -------------------------------------------------------------------------------- /src/drivers/console/serial/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # Serial TTY Driver Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | obj_$(CONFIG_CONSOLE_SERIAL_16550_UART) += 16550_uart.c 8 | #obj_$(CONFIG_CONSOLE_SERIAL_RPI4_UART) += rpi4_uart.c 9 | -------------------------------------------------------------------------------- /src/drivers/console/serial/include/16550_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef __1655_UART_H 2 | #define __1655_UART_H 3 | 4 | // UART REGISTERS 5 | 6 | #define UART_RXTX 0x0 // THR/RBR when DLAB = 0, DLL when DLAB = 1 7 | #define UART_INTEN 0x1 // IER when DLAB = 0, DLH when DLAB = 1 8 | #define UART_IIFIFO 0x2 // IIR as Read, FCR for Write 9 | #define UART_LCR 0x3 // Line Control Register 10 | #define UART_MCR 0x4 // Modem Control Register 11 | #define UART_LSR 0x5 // Line Status Register 12 | #define UART_MSR 0x6 // Modem Status Register 13 | #define UART_SCRATCH 0x7 // Scratch Register 14 | 15 | // Interrupt Enable Register (IER) 16 | 17 | #define UART_RECV_DATA_INT 0x01 // Enable Recieved Data Available Int 18 | #define UART_TRANS_EMPTY_INT 0x02 // Enable Transmit Register Empty Int 19 | #define UART_RECV_STATUS_INT 0x04 // Enable Receiver Line Status Int 20 | #define UART_MODEM_STATUS_INT 0x08 // Enable Modem Status Int 21 | #define UART_SLEEP_MODE 0x10 // Enable Sleep Mode (16750) 22 | #define UART_LO_POWER_MODE 0x20 // Enable Low Power Mode (16750) 23 | // Bit 7 & 8 are reserved, and are not defined 24 | 25 | // Interrupt Identification Register (IIR) 26 | #define UART_INT_PENDING 0x01 27 | #define UART_MODEM_STATUS 0x00 28 | #define UART_TRANSMIT_EMPTY 0x02 29 | #define UART_RECV_DATA_AVAIL 0x04 30 | #define UART_RECVR_LINE_STAT 0x06 31 | #define UART_TIME_OUT_INT 0x0C 32 | #define UART_FIFO_64 0x20 33 | #define UART_NO_FIFO 0x00 34 | #define UART_FIFO_ENABLED_ERR 0x80 35 | #define UART_FIFO_ENABLED 0xC0 36 | 37 | // FIFO Control Register (FCR) 38 | 39 | #define UART_ENABLE_FIFO 0x01 40 | #define UART_CLEAR_RECV_FIFO 0x02 41 | #define UART_CLEAR_TRANS_FIFO 0x04 42 | #define UART_DMA_MODE_SELECT 0x08 43 | #define UART_ENABLE_FIFO_64 0x20 44 | // FIFO Interrupt Trigger levels for 16 byte FIFO 45 | #define UART_FIFO_INT_1 0x00 // Trigger interrupts every byte 46 | #define UART_FIFO_INT_4 0x40 // Trigger interrupts every 4 bytes 47 | #define UART_FIFO_INT_8 0x80 // Trigger interrupts every 8 bytes 48 | #define UART_FIFO_INT_14 0xC0 // Trigger interrupts every 14 bytes 49 | // FIFO Interrupt Trigger levels for 64 byte FIFO 50 | // Yes, these are the same values as above 51 | #define UART_FIFO_INT_16 0x40 52 | #define UART_FIFO_INT_32 0x80 53 | #define UART_FIFO_INT_56 0xC0 54 | 55 | // Line Control Register (LCR) 56 | 57 | #define UART_DATA_BIT_5 0x0 58 | #define UART_DATA_BIT_6 0x1 59 | #define UART_DATA_BIT_7 0x2 60 | #define UART_DATA_BIT_8 0x3 61 | #define UART_ONE_STOP_BIT 0x0 62 | #define UART_TWO_STOP_BIT 0x4 // Bit 3 63 | // Bit 3-5 64 | #define UART_NO_PARITY 0x00 // 000 65 | #define UART_ODD_PARITY 0x08 // 001 66 | #define UART_EVEN_PARITY 0x18 // 011 67 | #define UART_MARK_PARITY 0x28 // 101 68 | #define UART_SPACE_PARITY 0x38 // 111 69 | #define UART_BREAK_ENABLE 0x40 // Bit 6 70 | #define UART_DLAB 0x80 // Bit 7 71 | 72 | // Modem Control Register (MCR) 73 | 74 | #define UART_DATA_TERM_READY 0x01 // Data Terminal Ready 75 | #define UART_REQ_TO_SEND 0x02 // Request to Send 76 | #define UART_AUX_OUTPUT_1 0x04 // Auxiliary Out 1 77 | #define UART_AUX_OUTPUT_2 0x08 // Auxiliary Out 2 78 | #define UART_LOOPBACK_MODE 0x10 // Loopback Mode 79 | #define UART_AUTOFLOW 0x20 // Autoflow Control (16750) 80 | 81 | // Line Status Register (LSR) 82 | 83 | #define UART_DATA_READY 0x01 // Data Reay 84 | #define UART_OVERRUN_ERR 0x02 // Overrun Error 85 | #define UART_PARITY_ERR 0x04 // Parity Error 86 | #define UART_FRAMING_ERR 0x08 // Framing Error 87 | #define UART_BREAK_INT 0x10 // Break Interrupt 88 | #define UART_EMPTY_TRANS 0x20 // Empty Transmitter Holding Register 89 | #define UART_EMPTY_DATA 0x40 // Empty Data Holding Register 90 | #define UART_FIFO_ERR 0x80 // Error in Recieved FIFO 91 | 92 | // Modem Status Register (MSR) 93 | 94 | #define UART_DEL_CLR_TO_SEND 0x01 // Delta Clear to Send 95 | #define UART_DEL_DATA_SET_RDY 0x02 // Delta Data Set Ready 96 | #define UART_TRAIL_RING_IND 0x04 // Trailing Ring Indicator 97 | #define UART_DEL_DATA_CARRIER 0x08 // Delta Data Carrier Detect 98 | #define UART_CLEAR_TO_SEND 0x10 // Clear to Send 99 | #define UART_DATA_SET_READY 0x20 // Data Set Ready 100 | #define UART_RING_IND 0x40 // Ring Indicator 101 | #define UART_CARRIER_DETECT 0x80 // Carrier Detect 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/drivers/framebuffer/Kconfig: -------------------------------------------------------------------------------- 1 | if FRAMEBUFFER 2 | menu "Framebuffer Drivers" 3 | 4 | config FRAMEBUFFER_VGA 5 | bool "VGA Framebuffer" 6 | depends on X86_BASE 7 | help 8 | Driver that utilize the VGA Framebuffer. 9 | 10 | endmenu 11 | 12 | endif # if Framebuffer 13 | -------------------------------------------------------------------------------- /src/drivers/framebuffer/Makefile: -------------------------------------------------------------------------------- 1 | ############################### 2 | # Apollo Project # 3 | # Framebuffer Driver Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################### 6 | 7 | # VGA Display Driver 8 | obj_$(CONFIG_FRAMEBUFFER_VGA) += vga.c vga_fonts.c 9 | -------------------------------------------------------------------------------- /src/drivers/framebuffer/include/vga.h: -------------------------------------------------------------------------------- 1 | #ifndef __VGA_H 2 | #define __VGA_H 3 | 4 | #include 5 | 6 | #define VGA_BASE_POINTER_1 0xA0000 7 | #define VGA_BASE_POINTER_2 0xB0000 8 | #define VGA_BASE_POINTER_3 0xB8000 9 | 10 | // Sequencer Registers 11 | #define VGA_RESET_REG 0x00 12 | #define VGA_CLOCKING_MODE 0x01 13 | #define VGA_MAP_MASK 0x02 14 | #define VGA_CHAR_MASK 0x03 15 | #define VGA_SEQ_MEM_MODE 0x04 16 | 17 | // Graphics Registers 18 | #define VGA_SET_RESET 0x00 19 | #define VGA_ENABLE_SET_RESET 0x01 20 | #define VGA_COLOR_COMPARE 0x02 21 | #define VGA_DATA_ROTATE 0x03 22 | #define VGA_READ_MAP_SELECT 0x04 23 | #define VGA_GRAPHICS_MODE 0x05 24 | #define VGA_MISC_GRAPHICS 0x06 25 | #define VGA_COLOR_DONT_CARE 0x07 26 | #define VGA_BIT_MASK_REG 0x08 27 | 28 | // CRTC Registers 29 | #define VGA_MAX_SCAN_LINE 0x09 30 | #define VGA_CURSOR_START 0x0A 31 | #define VGA_CURSOR_END 0x0B 32 | #define VGA_CURSOR_HIGH_BYTE 0x0E 33 | #define VGA_CURSOR_LOW_BYTE 0x0F 34 | 35 | // Register Index Offsets 36 | #define VGA_ATTRIBUTE_REG_OFFSET 0x00 37 | #define VGA_SEQUENCER_REG_OFFSET 0x04 38 | #define VGA_GRAPHICS_REG_OFFSET 0x0E 39 | #define VGA_CRTC_REG_OFFSET 0x14 40 | 41 | typedef struct { 42 | uint16_t h_res, v_res; 43 | 44 | resource_t *vga_base, *vga_control_base, *framebuffer; 45 | resource_t attribute_control, sequencer, graphics, crtc; 46 | } vga_state_t; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/drivers/irqchip/8259_pic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * 8259_pic.c - Intel Programmable Interrupt Controller driver 5 | * 6 | * Datasheet available here: 7 | * https://pdos.csail.mit.edu/6.828/2018/readings/hardware/8259A.pdf 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "include/8259_pic.h" 15 | 16 | /** 17 | ** Generic PIC driver code 18 | **/ 19 | 20 | static int i8259_ack(irqchip_t *chip, uint32_t n) 21 | { 22 | resource_t *base; 23 | uint8_t cmd; 24 | 25 | if(chip == NULL) 26 | { 27 | return -1; 28 | } 29 | base = (resource_t *)chip->data; 30 | 31 | cmd = PIC_EOI; 32 | 33 | /* Check to see if we're a cascaded PIC, if so, run an EOI against the 34 | * main PIC too 35 | */ 36 | if(chip->flags & IRQCHIP_CASCADE_SECONDARY) 37 | { 38 | if(resource_write(&cmd, base->parent, 0, 1)) 39 | { 40 | return -1; 41 | } 42 | } 43 | 44 | /* TODO: Spurrious interrupt checks */ 45 | /* Send the EOI to the PIC */ 46 | if(resource_write(&cmd, base, 0, 1)) 47 | { 48 | return -1; 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | static int i8259_mask(irqchip_t *chip, uint32_t n) 55 | { 56 | 57 | uint8_t mask; 58 | resource_t *base; 59 | 60 | if(chip == NULL) 61 | { 62 | return -1; 63 | } 64 | base = (resource_t *)chip->data; 65 | 66 | /* Retrieve existing mask from the Interrupt Mask Register. 67 | * The IMR, set via OCW1, is described in Fig. 8 of the data sheet. 68 | */ 69 | if(resource_read(&mask, base, 1, 1)) 70 | { 71 | return -1; 72 | } 73 | 74 | /* Mask the desired IRQ line by setting that bit into the mask. 75 | */ 76 | mask |= (1 << n); 77 | 78 | /* 79 | * Push the mask out back to the IMR (OCW1). 80 | */ 81 | if(resource_write(&mask, base, 1, 1)) 82 | { 83 | return -1; 84 | } 85 | return 0; 86 | } 87 | 88 | static int i8259_unmask(irqchip_t *chip, uint32_t n) 89 | { 90 | uint8_t mask; 91 | resource_t *base; 92 | 93 | if(chip == NULL) 94 | { 95 | return -1; 96 | } 97 | base = (resource_t *)chip->data; 98 | 99 | /* Retrieve existing mask from the Interrupt Mask Register. 100 | * The IMR, set via OCW1, is described in Fig. 8 of the data sheet. 101 | */ 102 | if(resource_read(&mask, base, 1, 1)) 103 | { 104 | return -1; 105 | } 106 | 107 | /* Mask the desired IRQ line by clearing that bit in the mask. 108 | */ 109 | mask &= ~(1 << n); 110 | 111 | /* 112 | * Push the mask out back to the IMR (OCW1). 113 | */ 114 | if(resource_write(&mask, base, 1, 1)) 115 | { 116 | return -1; 117 | } 118 | return 0; 119 | } 120 | 121 | int i8259_init(irqchip_t *chip, uint8_t icw3) 122 | { 123 | uint8_t mask; 124 | uint8_t cmd; 125 | resource_t *base; 126 | int cascade_mode = 0; 127 | 128 | /* Quick null pointer check */ 129 | if(chip == NULL) 130 | { 131 | return -1; 132 | } 133 | 134 | base = (resource_t *)chip->data; 135 | if(base == NULL) 136 | { 137 | return -1; 138 | } 139 | 140 | /* Make sure that the interrupt range requested is within the 8 bit limit */ 141 | if(chip->isr_start + 8 > 255) 142 | { 143 | return -1; 144 | } 145 | 146 | /* Check to see if we need ICW3 or not */ 147 | if((chip->flags & IRQCHIP_CASCADE_PRIMARY) || 148 | (chip->flags & IRQCHIP_CASCADE_SECONDARY)) 149 | { 150 | cascade_mode = 1; 151 | } 152 | 153 | if(resource_read(&mask, base, 1, 1)) 154 | { 155 | return -1; 156 | } 157 | 158 | /* ICW1 is described in Fig. 7 of the datasheet. 159 | * We want: 160 | * - Begin initialization 161 | * - ICW4 needed 162 | * - Cascade mode is optional depending on topology 163 | * - Edge Triggered Interrupts (Default) 164 | * 165 | * Other bits are only useful for MCS-80/85 mode 166 | */ 167 | cmd = PIC_ICW1_INIT | PIC_ICW1_ICW4; 168 | if (cascade_mode == 0) 169 | { 170 | cmd |= PIC_ICW1_SINGLE; /* Disable Cascade mode */ 171 | } 172 | if(resource_write(&cmd, base, 0, 1)) 173 | { 174 | return -1; 175 | } 176 | 177 | /* ICW2 is also described in Fig. 7 of the datasheet. 178 | * This represents the vector address of the PIC chip in 8086 mode. 179 | */ 180 | cmd = chip->isr_start; 181 | if(resource_write(&cmd, base, 1, 1)) 182 | { 183 | return -1; 184 | } 185 | 186 | /* ICW3 is also described in Fig. 7 of the datasheet. 187 | * It isn't written in single PIC mode, so we clause guard for that 188 | * ICW3 is passed from the calling function, as the syntax changes 189 | * depending if the chip is set up as the primary PIC or a cascaded one. 190 | * There is no way to tell programmatically which, as that is set via a 191 | * hardware pin on the PIC itself. 192 | */ 193 | if(cascade_mode == 1) { 194 | if(resource_write(&icw3, base, 1, 1)) 195 | { 196 | return -1; 197 | } 198 | } 199 | 200 | /* ICW4 is also described in Fig. 7 of the datasheet. 201 | * ICW4 determines the operating mode of the PIC. 202 | * We want: 203 | * - 8086/8088 Mode (not MCS-80/85 mode) 204 | * - Normal EOI Mode (default, otherwise auto EOI) 205 | * - Non-Buffered Mode (default) 206 | * - Not Special fully nested mode (default) 207 | */ 208 | cmd = PIC_ICW4_8086; 209 | if(resource_write(&cmd, base, 1, 1)) 210 | { 211 | return -1; 212 | } 213 | 214 | /* Finally, Restore the mask cached earlier */ 215 | if(resource_write(&mask, base, 1, 1)) 216 | { 217 | return -1; 218 | } 219 | 220 | /* The 8259 has 8 IRQ Channels */ 221 | chip->isr_len = 8; 222 | chip->ack = &i8259_ack; 223 | chip->mask = &i8259_mask; 224 | chip->unmask = &i8259_unmask; 225 | 226 | irqchip_register(chip); 227 | 228 | return 0; 229 | } 230 | 231 | static int configure(device_t *device, void *p) 232 | { 233 | uint32_t *config = (uint32_t *)p; 234 | irqchip_t *chip = (irqchip_t *)device->data; 235 | return i8259_init(chip, *config); 236 | } 237 | 238 | DRIVER = { 239 | .compat = "irqchip/8254_pic", 240 | .init = &configure 241 | }; 242 | -------------------------------------------------------------------------------- /src/drivers/irqchip/Kconfig: -------------------------------------------------------------------------------- 1 | if IRQ 2 | menu "IRQ Chips" 3 | config IRQCHIP_8259 4 | bool "Intel 8259" 5 | depends on X86_BASE 6 | help 7 | The standard IRQ Chip found in all IBM-PC compatibles. 8 | 9 | endmenu 10 | endif 11 | -------------------------------------------------------------------------------- /src/drivers/irqchip/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # IRQ Driver Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | obj_$(CONFIG_IRQ) += irqchip.c 8 | obj_$(CONFIG_IRQCHIP_8259) += 8259_pic.c 9 | -------------------------------------------------------------------------------- /src/drivers/irqchip/include/8259_pic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) 2022 Apollo Project Developers 3 | * pic.h - Definitions for controlling the Programmable Interrupt Controller 4 | */ 5 | 6 | #ifndef __8259_PIC_H 7 | #define __8259_PIC_H 8 | #include 9 | 10 | // PIC Commands 11 | 12 | #define PIC_ICW1_ICW4 0x01 // ICW4 not needed (ICW4 Needed if set) 13 | #define PIC_ICW1_SINGLE 0x02 // Single cascade mode 14 | #define PIC_ICW1_INTERVAL4 0x04 // Call address interval 4 (8 if not set) 15 | #define PIC_ICW1_LEVEL 0x08 // Level triggered mode (Edge if not set) 16 | #define PIC_ICW1_INIT 0x10 // Initialize PIC 17 | #define PIC_ICW1_MCS_IVA(ad) (ad << 5) // MCS Interrupt Vector Address 18 | 19 | #define PIC_ICW4_8086 0x01 // 8086/88 Mode (MCS-80/58 if not set) 20 | #define PIC_ICW4_AUTO 0x02 // Auto EOI (Manual EOI if not set) 21 | #define PIC_ICW4_BUFFERED 0x04 // Buffered mode 22 | #define PIC_ICW4_MASTER 0x08 // Master Mode (Slave if not set) 23 | #define PIC_ICW4_NESTED 0x10 // Special Fully Nested Mode 24 | 25 | // OCW 2 & 3 Commands, OCW1 is written/read by the data register 26 | #define PIC_ISR_SELECT 0x01 // Select ISR (or IRR if 0) - OCW3 27 | #define PIC_READ_REGISTER 0x02 // Read Register Command - OCW3 28 | #define PIC_OCW3_SELECT 0x08 // Select the OCW3 register (OCW2 otherwise) 29 | #define PIC_EOI 0x20 // End of interrupt - OCW2 30 | #define PIC_SPECIFIC 0x40 // Specific Modifier - IR in bits 0-2 31 | #define PIC_ROTATE 0x80 // Rotate in auto EOI mode 32 | #define PIC_SET_PRIORITY 0xC0 // Set priority - IR in bits 0-2 33 | 34 | #define PIC_ROTATE_SP PIC_ROTATE | PIC_EOI | PIC_SPECIFIC 35 | #define PIC_ROTATE_NSP PIC_ROTATE | PIC_EOI 36 | #define PIC_EOI_SP PIC_EOI | PIC_SPECIFIC 37 | #define PIC_READ_ISR PIC_READ_REGISTER | PIC_OCW3_SELECT | PIC_ISR_SELECT 38 | #define PIC_READ_IRR PIC_READ_REGISTER | PIC_OCW3_SELECT 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/drivers/irqchip/irqchip.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static irqchip_t *irq_chips = NULL; 5 | 6 | static irqchip_t *find_irq_line(uint32_t n) { 7 | irqchip_t *ret = irq_chips; 8 | 9 | while(ret != NULL) 10 | { 11 | if ((n >= ret->isr_start) && (n < (ret->isr_start + ret->isr_len))) { 12 | return ret; 13 | } 14 | ret = ret->next; 15 | } 16 | return ret; 17 | } 18 | 19 | int irqchip_register(irqchip_t *c) { 20 | if(c == NULL) 21 | { 22 | return -1; // Null pointer!! 23 | } 24 | c->next = irq_chips; 25 | irq_chips = c; 26 | return 0; 27 | } 28 | 29 | int irqchip_unregister(irqchip_t *c) { 30 | irqchip_t *current = irq_chips; 31 | irqchip_t *previous = NULL; 32 | if(current == NULL) 33 | { 34 | return 0; 35 | } 36 | if(c == NULL) 37 | { 38 | return 0; 39 | } 40 | while(current != c) 41 | { 42 | if(current->next == NULL) 43 | { 44 | return -1; // Not found in the list! 45 | } 46 | previous = current; 47 | current = current->next; 48 | } 49 | if(previous == NULL) 50 | { 51 | previous = current->next; 52 | } else { 53 | previous->next = current->next; 54 | } 55 | return 0; 56 | } 57 | 58 | void irqchip_ack(uint32_t n) { 59 | irqchip_t *this = find_irq_line(n); 60 | if(this) { 61 | if(this->ack) { 62 | this->ack(this, n - this->isr_start); 63 | } 64 | } 65 | } 66 | 67 | void irqchip_mask(uint32_t n) { 68 | irqchip_t *this = find_irq_line(n); 69 | if(this) { 70 | if(this->mask) { 71 | this->mask(this, n - this->isr_start); 72 | } 73 | } 74 | } 75 | 76 | void irqchip_unmask(uint32_t n) { 77 | irqchip_t *this = find_irq_line(n); 78 | if(this) { 79 | if(this->unmask) { 80 | this->unmask(this, n - this->isr_start); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/include/adt/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef BITMAP_H 2 | #define BITMAP_H 3 | 4 | #include 5 | 6 | // This ADT exposes a statically sized bitmap. 7 | 8 | typedef struct bitmap { 9 | uint8_t *data; 10 | int64_t max_extent; 11 | } bitmap_t; 12 | 13 | void bitmap_init(bitmap_t *xb, uint8_t *storage, int64_t max_extent); 14 | 15 | // Set a bit at index idx 16 | void bitmap_set(bitmap_t *xb, unsigned idx); 17 | 18 | // Clear a bit at index idx 19 | void bitmap_clear(bitmap_t *xb, unsigned idx); 20 | 21 | // Returns nonzero if bit set at idx 22 | int bitmap_isset(bitmap_t *xb, unsigned idx); 23 | 24 | // Returns nonzero if bit is clear at idx 25 | int bitmap_isclear(bitmap_t *xb, unsigned idx); 26 | 27 | // Return the index of the first bit set, or -1 if no bits are sets 28 | int64_t bitmap_first_set(bitmap_t *xb); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/include/adt/buddy.h: -------------------------------------------------------------------------------- 1 | #ifndef BUDDY_H 2 | #define BUDDY_H 3 | 4 | #include 5 | #include 6 | 7 | #define MAX_BUDDY_SZ_LOG2 28 // 2^28 = 256MB 8 | #define MIN_BUDDY_SZ_LOG2 12 // 2^12 = 4KB 9 | 10 | #define NUM_BUDDY_BUCKETS (MAX_BUDDY_SZ_LOG2 - MIN_BUDDY_SZ_LOG2 + 1) 11 | 12 | typedef struct buddy { 13 | uint64_t start, size; 14 | bitmap_t orders[NUM_BUDDY_BUCKETS]; 15 | } buddy_t; 16 | 17 | size_t buddy_calc_overhead(range_t r); 18 | int buddy_init(buddy_t *bd, uint8_t *overhead_store, range_t r, int start_freed); 19 | uint64_t buddy_alloc(buddy_t *bd, unsigned sz); 20 | void buddy_free_range(buddy_t *bd, range_t range); 21 | void buddy_free(buddy_t *bd, uint64_t addr, unsigned sz); 22 | 23 | extern buddy_t kernel_buddy; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/include/adt/ringbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef RINGBUF_H 2 | #define RINGBUF_H 3 | 4 | /* Ring buffer storing characters 5 | * 6 | * This ADT exposes a circular buffer, each item being of @c char type. It is minimal 7 | * and not in any way threadsafe. It has no dependencies. */ 8 | 9 | /* A ring buffer storing characters. */ 10 | typedef struct char_ringbuf { 11 | char *buffer, *buffer_start, *buffer_end; 12 | int buffer_length; 13 | } char_ringbuf_t; 14 | 15 | 16 | /* Create a new character ring buffer, using 'buffer' as memory, which is 'len' bytes 17 | long. */ 18 | char_ringbuf_t make_char_ringbuf(char *buffer, int len); 19 | 20 | /* Read len characters from a char ring buffer. */ 21 | int char_ringbuf_read(char_ringbuf_t *state, char *buf, int len); 22 | 23 | /* Write len characters to a char ring buffer. This does not guarantee that all 24 | elements were written successfully. */ 25 | void char_ringbuf_write(char_ringbuf_t *state, const char *buf, int len); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/include/arch/hosted/hal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * Hosted Hal.h 4 | * Used to testbed the kernel without baremetal 5 | */ 6 | 7 | #ifndef __ARCH_HOSTED_HAL_H 8 | #define __ARCH_HOSTED_HAL_H 9 | 10 | #include 11 | #include 12 | 13 | #define THREAD_STACK_SZ 0x10000 // 64KB of kernel stack. 14 | 15 | typedef struct address_space { 16 | uint32_t a[1<<20]; 17 | spinlock_t lock; 18 | } address_space_t; 19 | 20 | extern void abort() __attribute__((noreturn)); 21 | 22 | static inline unsigned get_page_size() { 23 | return 4096; 24 | } 25 | 26 | static inline unsigned get_page_shift() { 27 | return 12; 28 | } 29 | 30 | static inline unsigned get_page_mask() { 31 | return 0xFFF; 32 | } 33 | 34 | static inline uintptr_t round_to_page_size(uintptr_t x) { 35 | if ((x & 0xFFF) != 0) 36 | return ((x >> 12) + 1) << 12; 37 | else 38 | return x; 39 | } 40 | 41 | struct regs { 42 | }; 43 | 44 | struct jmp_buf_impl { 45 | uint64_t rsp, rbp, rip, rbx, rsi, rdi, rflags, 46 | r8, r9, r10, r11, r12, r13, r14, r15; 47 | }; 48 | 49 | typedef struct jmp_buf_impl jmp_buf[1]; 50 | 51 | static inline void jmp_buf_set_stack(jmp_buf buf, uintptr_t stack) { 52 | buf[0].rsp = stack; 53 | } 54 | 55 | static inline void jmp_buf_to_regs(struct regs *r, jmp_buf buf) { 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/include/arch/rpi4/hal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * - Hardware abstraction layer 4 | */ 5 | 6 | #ifndef __ARCH_RPI4_HAL_H 7 | #define __ARCH_RPI4_HAL_H 8 | 9 | #include 10 | #include 11 | 12 | #define THREAD_STACK_SZ 0x2000 // Kernel stack 8k 13 | 14 | 15 | typedef struct address_space { 16 | uint32_t *directory; 17 | spinlock_t lock; 18 | } address_space_t; 19 | 20 | static inline unsigned get_page_size() { 21 | return 4096; 22 | } 23 | 24 | static inline unsigned get_page_shift() { 25 | return 12; 26 | } 27 | 28 | static inline unsigned get_page_mask() { 29 | return 0xFFF; 30 | } 31 | 32 | static inline uintptr_t round_to_page_size(uintptr_t x) { 33 | if ((x & 0xFFF) != 0) 34 | return ((x >> 12) + 1) << 12; 35 | else 36 | return x; 37 | } 38 | 39 | static inline void abort() { 40 | for(;;); 41 | } 42 | 43 | #include "arch/rpi4/regs.h" 44 | 45 | struct jmp_buf_impl { 46 | uint64_t si; 47 | }; 48 | 49 | typedef struct jmp_buf_impl jmp_buf[1]; 50 | 51 | static inline void jmp_buf_set_stack(jmp_buf buf, uintptr_t stack) { 52 | buf[0].si = stack; 53 | } 54 | 55 | static inline void jmp_buf_to_regs(struct regs *r, jmp_buf buf) { 56 | // todo 57 | } 58 | 59 | #define abort() (void)0 60 | 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/include/arch/rpi4/regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * - Register definitions 4 | */ 5 | 6 | #ifndef __ARCH_RPI4_REGS_H 7 | #define __ARCH_RPI4_REGS_H 8 | 9 | #include 10 | 11 | typedef struct regs { 12 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7; 13 | uint64_t x8, x9, x10, x11, x12, x13, x14, x15; 14 | uint64_t x16, x17, x18, x19, x20, x21, x22, x23; 15 | uint64_t x24, x25, x26, x27, x28, x29, x30, sp; 16 | } rpi4_regs_t; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/include/arch/x86/hal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2022 Apollo Project Developers 3 | * - Hardware abstraction layer 4 | */ 5 | 6 | #ifndef __ARCH_X86_HAL_H 7 | #define __ARCH_X86_HAL_H 8 | 9 | #include 10 | #include 11 | 12 | #define THREAD_STACK_SZ 0x2000 // Kernel stack 8k 13 | 14 | #define X86_PRESENT 0x1 15 | #define X86_WRITE 0x2 16 | #define X86_USER 0x4 17 | #define X86_EXECUTE 0x200 18 | #define X86_COW 0x400 19 | 20 | typedef struct address_space { 21 | uint32_t *directory; 22 | spinlock_t lock; 23 | } address_space_t; 24 | 25 | static inline unsigned get_page_size() { 26 | return 4096; 27 | } 28 | 29 | static inline unsigned get_page_shift() { 30 | return 12; 31 | } 32 | 33 | static inline unsigned get_page_mask() { 34 | return 0xFFF; 35 | } 36 | 37 | static inline uintptr_t round_to_page_size(uintptr_t x) { 38 | if ((x & 0xFFF) != 0) 39 | return ((x >> 12) + 1) << 12; 40 | else 41 | return x; 42 | } 43 | 44 | static inline void abort() { 45 | for(;;); 46 | } 47 | 48 | #include "arch/x86/regs.h" 49 | 50 | struct jmp_buf_impl { 51 | uint32_t esp, ebp, eip, ebx, esi, edi, eflags; 52 | }; 53 | 54 | typedef struct jmp_buf_impl jmp_buf[1]; 55 | 56 | static inline void jmp_buf_set_stack(jmp_buf buf, uintptr_t stack) { 57 | buf[0].esp = stack; 58 | } 59 | 60 | static inline void jmp_buf_to_regs(struct regs *r, jmp_buf buf) { 61 | r->esp = buf[0].esp; 62 | r->ebp = buf[0].ebp; 63 | r->eip = buf[0].eip; 64 | r->ebx = buf[0].ebx; 65 | r->esi = buf[0].edi; 66 | r->eflags = buf[0].eflags; 67 | } 68 | 69 | #define abort() (void)0 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/include/arch/x86/mmap.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_X86_MMAP_H 2 | #define __ARCH_X86_MMAP_H 3 | 4 | #define MMAP_KERNEL_START 0xC0000000 5 | 6 | // At least 64MB of address space for 36-bit physical Addresses 7 | #define MMAP_COW_REFCNTS 0xCC000000 8 | 9 | #define MMAP_KERNEL_VMSPACE_START 0xD0000000 10 | #define MMAP_KERNEL_VMSPACE_END 0xFE800000 11 | 12 | #define MMAP_PMM_BITMAP 0xFE800000 13 | #define MMAP_PMM_BITMAP_END 0xFF800000 14 | 15 | #define MMAP_KERNEL_END 0xFF800000 16 | 17 | #define IS_KERNEL_ADDR(x) ((void*)(x) >= (void*)MMAP_KERNEL_START) 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/include/arch/x86/regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2024 Apollo Project Developers 3 | * - Register definitions 4 | */ 5 | 6 | #ifndef __ARCH_X86_REGS_H 7 | #define __ARCH_X86_REGS_H 8 | 9 | #include 10 | 11 | typedef struct regs { 12 | uint32_t ds; 13 | uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; 14 | uint32_t interrupt_num, error_code; 15 | uint32_t eip, cs, eflags, useresp, ss; 16 | } x86_regs_t; 17 | 18 | uint32_t read_cr0(); 19 | uint32_t read_cr2(); 20 | uint32_t read_cr3(); 21 | void write_cr0(uint32_t); 22 | void write_cr2(uint32_t); 23 | void write_cr3(uint32_t); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/include/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef ASSERT_H 2 | #define ASSERT_H 3 | 4 | #if defined(HOSTED) 5 | # include_next 6 | #else 7 | 8 | #define _stringify(x) (#x) 9 | #define assert(cond) ( (cond) ? (void)0 : assert_fail(#cond, __FILE__, __LINE__) ) 10 | 11 | #endif 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/include/math.h: -------------------------------------------------------------------------------- 1 | #ifndef MATH_H 2 | #define MATH_H 3 | 4 | unsigned log2_roundup(unsigned n); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDIO_H 2 | #define __STDIO_H 3 | 4 | #if !defined(NULL) /* Define NULL */ 5 | #define NULL ((void*)0) 6 | #endif 7 | 8 | int putchar(int character); 9 | int puts(const char *str); 10 | 11 | /* int vsprintf(char *buf, const char *fmt, va_list args); 12 | int vprintf(const char *fmt, va_list args); */ 13 | int sprintf(char *buf, const char *fmt, ...); 14 | int printf(const char *fmt, ...); 15 | 16 | void debug(unsigned char *str); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/include/stdlib.h: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/include/string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2016 Apollo Project Developers 3 | * C standard library for strings. 4 | */ 5 | 6 | #ifndef _STRING_H 7 | #define _STRING_H 8 | 9 | #include 10 | 11 | #ifndef NULL 12 | #define NULL 0 13 | #endif 14 | 15 | #ifndef _SIZE_T 16 | #define _SIZE_T 17 | typedef unsigned int size_t; 18 | #endif 19 | 20 | void *memcpy(void *, const void *, size_t); 21 | void *memmove(void *, const void *, size_t); 22 | char *strcpy(char *, const char *); 23 | char *strncpy(char *, const char *, size_t); 24 | void *memset(void *, int, size_t); 25 | size_t strlen(const char *); 26 | char *strcat(char *, const char *); 27 | char *strncat(char *, const char *, size_t); 28 | int memcmp(const void *, const void *, size_t); 29 | int strcmp(const char *, const char *); 30 | int strncmp(const char *, const char *, size_t); 31 | const void *memchr(const void *, int, size_t); 32 | char *strchr(const char *, int); 33 | size_t strcspn(const char *, const char *); 34 | char *strpbrk(const char *, const char *); 35 | char *strrchr(const char *, int); 36 | size_t strspn(const char *, const char *); 37 | char *strstr(const char *, const char *); 38 | char *strtok(char *, const char *); 39 | 40 | 41 | #endif /* _STRING_H */ 42 | -------------------------------------------------------------------------------- /src/include/sys/device.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Apollo Project Developers 3 | * For terms, see LICENSE 4 | * - Device abstraction layer 5 | * 6 | */ 7 | 8 | #ifndef __SYS_DEVICE_H 9 | #define __SYS_DEVICE_H 10 | 11 | #include 12 | 13 | typedef struct device_struct device_t; 14 | 15 | typedef struct { 16 | const char *compat; 17 | int (*init)(device_t *device, void *config); 18 | int (*fini)(device_t *device); 19 | int (*api)(device_t *device, void *data); 20 | } device_driver_t; 21 | 22 | /** 23 | * @brief Device instance definition. 24 | * 25 | * @name: Name of this device instance 26 | * @data: Private data 27 | * @access: Resource pointer to access device 28 | * @driver: (semi-opaque) Driver associated with this device. 29 | * @parent: (semi-opaque) Parent device in the device tree 30 | * @sibling: (semi-opaque) Next sibling device in the device tree 31 | * @child: (semi-opaque) Child device in the device tree. 32 | */ 33 | struct device_struct { 34 | char *name; 35 | void *data; 36 | resource_t *access; 37 | device_driver_t *driver; 38 | device_t *parent, *sibling, *child; 39 | }; 40 | 41 | /** 42 | * @brief Retrieve a pointer to the base device 43 | * 44 | * @return device_t* 45 | */ 46 | device_t *base_device(); 47 | 48 | int device_register(device_t *d, device_t *parent, const char *compat); 49 | int device_unregister(device_t *d); 50 | int device_init(device_t *d, void *config); 51 | int device_api_call(device_t *d, void *data); 52 | 53 | #define DRIVER static device_driver_t x \ 54 | __attribute__((__section__(".drivers"),used)) 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/include/sys/interrupts.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS_INTERRUPTS_H 2 | #define __SYS_INTERRUPTS_H 3 | 4 | #include 5 | // Pointers are generally the same size as the CPU registers... 6 | typedef __UINTPTR_TYPE__ reg_t; 7 | 8 | // Dynamic function jumps. Very bad stuff 9 | typedef void (*voidCallback)(int, reg_t*); 10 | 11 | void interruptHandlerRegister(int num, voidCallback handler); 12 | void unhandledInterrupt(int argc, reg_t *argv); 13 | extern voidCallback interruptHandlers[]; 14 | 15 | #endif // __SYS_INTERRUPTS_H 16 | -------------------------------------------------------------------------------- /src/include/sys/irqchip.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS_IRQCHIP_H 2 | #define __SYS_IRQCHIP_H 3 | 4 | #include 5 | 6 | #define IRQCHIP_CASCADE_PRIMARY 0x00000001 7 | #define IRQCHIP_CASCADE_SECONDARY 0x00000002 8 | 9 | /** 10 | * struct irqchip - per irq chip information 11 | * @name: Unique name of the chip (see irqchip_state) 12 | * 13 | * @mask: Enable an interrupt line 14 | * @unmask: Disable an interrupt line 15 | * @ack: Acknowledge an interrupt 16 | * @isr_start: Offset from hardware interrupt numbering 17 | * @isr_len: Number of interrupts serviced by this chip 18 | * @next: Pointer to next irqchip 19 | * @data: Implementation specific data 20 | */ 21 | typedef struct irqchip { 22 | const char *name; 23 | uint32_t flags; 24 | 25 | int (*mask)(struct irqchip *data, uint32_t n); 26 | int (*unmask)(struct irqchip *data, uint32_t n); 27 | int (*ack)(struct irqchip *data, uint32_t n); 28 | 29 | uint32_t isr_start; 30 | uint32_t isr_len; 31 | 32 | struct irqchip *next; 33 | void *data; 34 | } irqchip_t; 35 | 36 | /** 37 | * @brief Register an IRQ Chip 38 | * 39 | * @param c Pointer to the IRQChip instance 40 | * @return int value of the init() function return 41 | */ 42 | int irqchip_register(irqchip_t *c); 43 | 44 | /** 45 | * @brief De-register an IRQ Chip 46 | * 47 | * @param c Pointer to the IRQChip instance 48 | * @return int value of the fini() function return 49 | */ 50 | int irqchip_unregister(irqchip_t *c); 51 | 52 | /** 53 | * @brief Acknowledge an interrupt 54 | * 55 | * @param c Pointer to the IRQChip instance 56 | * @param n The interrupt line to acknowledge 57 | */ 58 | void irqchip_ack(uint32_t n); 59 | 60 | /** 61 | * @brief mask an interrupt 62 | * 63 | * @param n The interrupt line to mask 64 | */ 65 | void irqchip_mask(uint32_t n); 66 | 67 | /** 68 | * @brief Unmask an interrupt 69 | * 70 | * @param n The interrupt line to unmask 71 | */ 72 | void irqchip_unmask(uint32_t n); 73 | 74 | #endif /* __SYS_IRQCHIP_H */ 75 | -------------------------------------------------------------------------------- /src/include/sys/mmap.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS_MMAP_H 2 | #define __SYS_MMAP_H 3 | 4 | // This file steps to includes for arch specific mmap's 5 | 6 | #if defined(X64) 7 | #include 8 | #elif defined(X86) 9 | #include 10 | #elif defined(HOSTED) 11 | #include 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/include/sys/resource.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS_RESOURCE_H 2 | #define __SYS_RESOURCE_H 3 | 4 | #include 5 | 6 | /* Bits 8-11: Resource Type */ 7 | #define RESOURCE_TYPE 0x00000F00 8 | #define RESOURCE_META 0x00000000 /* Meta Resource */ 9 | #define RESOURCE_IO 0x00000100 /* IO Bus */ 10 | #define RESOURCE_MEM 0x00000200 /* Memory Bus */ 11 | 12 | /* Bits 0-7 are Resource type specific */ 13 | #define RESOURCE_SPECIFIC 0x000000FF 14 | 15 | /* Bits 0-7 Resource IO Specific */ 16 | /* Bits 0-3 are IO Resource Types */ 17 | #define RESOURCE_IO_LINEAR 0x00000000 /* Linear Access of resource */ 18 | #define RESOURCE_IO_INDEXED 0x00000001 /* Access is controlled via an index */ 19 | #define RESOURCE_IO_FIFO 0x00000002 /* Resource is a FIFO buffer */ 20 | /* Bits 4-7 are Type Modifiers */ 21 | #define RESOURCE_IO_SLOW 0x00000010 /* Access requires an iowait() */ 22 | 23 | /* Bits 12 & 13: Resource Data Width */ 24 | #define RESOURCE_WIDTH 0x00003000 25 | #define RESOURCE_WIDTH_8 0x00000000 /* (Default) 8 bit data */ 26 | #define RESOURCE_WIDTH_16 0x00001000 /* 16 Bit Data transfer */ 27 | #define RESOURCE_WIDTH_32 0x00002000 /* 32 Bit Data transfer */ 28 | #define RESOURCE_WIDTH_64 0x00003000 /* 64 Bit Data transfer */ 29 | 30 | /* Generic */ 31 | #define RESOURCE_DISABLED 0x10000000 /* Resource unreachable */ 32 | #define RESOURCE_BUSY 0x20000000 /* Resource in use */ 33 | 34 | typedef struct resource { 35 | resource_type_t start; 36 | resource_type_t end; 37 | const char *name; 38 | uint32_t flags; 39 | struct resource *parent, *sibling, *child; 40 | } resource_t; 41 | 42 | void resource_register(resource_t *r, resource_t *parent); 43 | resource_t *resource_find(const char *name, resource_t *parent); 44 | 45 | int resource_write(void *src, resource_t *r, resource_type_t off, size_t n); 46 | int resource_read(void *dest, resource_t *r, resource_type_t off, size_t n); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/include/sys/testing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2018 Apollo Developers 3 | * testing.h - integrate tests tighter into kernel. 4 | */ 5 | 6 | #ifndef __SYS_TESTING_H 7 | #define __SYS_TESTING_H 8 | 9 | #include 10 | 11 | typedef struct test_mod { 12 | void (*runner)(void); 13 | } test_mod_t; 14 | 15 | #undef TEST 16 | 17 | #define TEST(group, name) \ 18 | void TEST_##group##_##name##_(void); \ 19 | void TEST_##group##_##name##_run(void); \ 20 | static test_mod_t run_##group##_##name##_test \ 21 | __attribute__((__section__("testing"),used)) = { \ 22 | .runner = &TEST_##group##_##name##_run }; \ 23 | void TEST_##group##_##name##_run(void) \ 24 | {\ 25 | UnityTestRunner(TEST_##group##_SETUP,\ 26 | TEST_##group##_##name##_,\ 27 | TEST_##group##_TEAR_DOWN,\ 28 | "TEST(" #group ", " #name ")",\ 29 | TEST_GROUP_##group, #name,\ 30 | __FILE__, __LINE__);\ 31 | }\ 32 | void TEST_##group##_##name##_(void) 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/include/sys/timekeeping.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2019 Apollo Developers 3 | * timekeeping.h - Functionality for time 4 | */ 5 | 6 | #ifndef __SYS_TIMEKEEPING_H 7 | #define __SYS_TIMEKEEPING_H 8 | 9 | #include 10 | #include 11 | 12 | typedef struct callback_state 13 | { 14 | // Data given by register_callback() 15 | uint64_t miliseconds; 16 | int periodic; 17 | void (*cb)(void *); 18 | void *data; 19 | 20 | // Internal bookkeeping 21 | uint64_t time_elapsed; 22 | int active; 23 | } callback_state_t; 24 | 25 | // Struct for a timekeeping device 26 | typedef struct timekeeping_state 27 | { 28 | const char *name; // Name of this timekeeping device 29 | uint32_t frequency; // Frequency of clock 30 | uint64_t ticks; // Simple number of ticks 31 | 32 | uint32_t priority; // Priority to set system clock (highest wins) 33 | 34 | uint32_t us_per_tick; // Microseconds per tick (rounded) 35 | uint32_t ns_per_tick; // Remainder from microsecond round (3 places) 36 | uint32_t ns_count; // Count of ns, so we can add it to timestamp 37 | 38 | uint32_t base_frequency;// Frequency of base clock 39 | resource_t *data; // Pointer to resource struct to access the device 40 | } timekeeping_state_t; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/include/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2018 Apollo Project Developers 3 | * - Hardware Abstraction Layer 4 | * 5 | * Includes all of the builtin types 6 | * Also defines null 7 | */ 8 | 9 | #ifndef __TYPES_H 10 | #define __TYPES_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #undef NULL 17 | #define NULL 0 18 | 19 | typedef size_t phys_addr_t; 20 | 21 | typedef phys_addr_t resource_type_t; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/libc/Kconfig: -------------------------------------------------------------------------------- 1 | menuconfig LIBC 2 | bool "Standard Library Functions" 3 | select LIBC_MATH 4 | select LIBC_STDIO 5 | select LIBC_STRING 6 | help 7 | Standard library functionality is used throughout the kernel. Do not 8 | disable this functionality unless you know what you are doing. 9 | if LIBC 10 | 11 | config LIBC_MATH 12 | bool " Compatiblity" 13 | help 14 | Enables functions found in math.h 15 | 16 | config LIBC_STDIO 17 | bool " Compatibility" 18 | help 19 | Enables functions found in stdio.h 20 | 21 | config LIBC_STRING 22 | bool " Compatibility" 23 | default y 24 | help 25 | Enables functions found in string.h 26 | 27 | endif 28 | -------------------------------------------------------------------------------- /src/libc/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # libc Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | obj_$(CONFIG_LIBC_MATH) += math.c 7 | obj_$(CONFIG_LIBC_STDIO) += stdio.c 8 | obj_$(CONFIG_LIBC_STRING) += string.c 9 | -------------------------------------------------------------------------------- /src/libc/math.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2019 Apollo Developers 3 | * For terms, see LICENSE 4 | * math.c - math helper functions 5 | */ 6 | 7 | #include 8 | 9 | unsigned log2_roundup(unsigned n) 10 | { 11 | // Calculate the floor of log2(n) 12 | unsigned l2; 13 | 14 | l2 = 31 - __builtin_clz(n); // gcc builtin, returns number of leading 0's 15 | // in n, if x is 0, result undefined. 16 | // TODO: I hate using builtins 17 | if (n == 1U << l2) { // n == 2^log2(n), floor(n) = n 18 | return l2; // no need to round up 19 | } 20 | // floor(n) != n, return round up 21 | return l2 + 1; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/libc/string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2016 Apollo Project Developers 3 | * libc/string.c - functions for 4 | */ 5 | 6 | #include 7 | #include 8 | #if !defined(HOSTED) // check for hosted system 9 | 10 | void *memcpy(void *destination, const void *source, size_t num) 11 | { 12 | uint8_t *dp = destination; 13 | const uint8_t *sp = source; 14 | 15 | for(; num != 0; num--) { 16 | *dp++ = *sp++; 17 | } 18 | return destination; 19 | } 20 | 21 | void *memmove(void *destination, const void *source, size_t num) 22 | { 23 | char *sp = (char*) source; 24 | char *dp = (char*) destination; 25 | 26 | // Source -> Destination is not really a move at all 27 | if(sp==dp) { 28 | return destination; 29 | } 30 | 31 | // Backwards copy if source could overrun destination 32 | if(sp 10 | #include 11 | #include 12 | #include 13 | 14 | #define CONSOLE_BUF_SZ (80*50) 15 | 16 | static console_t *consoles = NULL; 17 | 18 | // A lock for all console operations. 19 | static spinlock_t lock = SPINLOCK_RELEASED; 20 | 21 | char_ringbuf_t console_buf; // Console buffer, used for pre-screen. 22 | char console_char_buf[CONSOLE_BUF_SZ]; // 80*50 23 | 24 | int register_console(console_t *c) 25 | { 26 | // spinlock_acquire(&lock); 27 | if (consoles) { 28 | consoles->prev = c; 29 | } 30 | 31 | c->next = consoles; 32 | c->prev = NULL; 33 | 34 | consoles = c; 35 | 36 | // If an open() was provided, call it. 37 | if (c->open) { 38 | c->open(c); 39 | } 40 | 41 | // Spit current contents of the ringbuffer to the console 42 | if (c->write) { 43 | char buf[CONSOLE_BUF_SZ]; // Magic number = 80*50 44 | char_ringbuf_read(&console_buf, buf, console_buf.buffer_length); 45 | c->write(c, buf, strlen(buf)); 46 | } 47 | 48 | //spinlock_release(&lock); 49 | return 0; 50 | } 51 | 52 | void unregister_console(console_t *c) 53 | { 54 | // spinlock_acquire(&lock); 55 | console_t *prev = NULL; 56 | console_t *this = consoles; 57 | 58 | while(this) { 59 | if(this == c) { 60 | if(this->next) { 61 | this->next->prev = prev; 62 | } 63 | if(this->prev) { 64 | this->prev->next = this->next; 65 | } 66 | if(!prev) { 67 | consoles = c; 68 | } 69 | 70 | if(this->flush) { 71 | this->flush(this); 72 | } 73 | if(this->close) { 74 | this->close(this); 75 | } 76 | break; 77 | } 78 | prev = this; 79 | this = this->next; 80 | } 81 | //spinlock_release(&lock); 82 | } 83 | 84 | // write to all consoles 85 | void write_console(const char *buf, int len) 86 | { 87 | // spinlock_acquire(&lock); 88 | console_t *this = consoles; 89 | if(consoles == NULL) { 90 | char_ringbuf_write(&console_buf, buf, len); 91 | } 92 | while (this) { 93 | if(this->write) { 94 | this->write(this, buf, len); 95 | } 96 | this = this->next; 97 | } 98 | //spinlock_release(&lock); 99 | } 100 | 101 | int read_console(char *buf, int len) 102 | { 103 | if (len == 0) { 104 | return 0; 105 | } 106 | // spinlock_acquire(&lock); 107 | console_t *this = consoles; 108 | while (this) { 109 | if (this->read) { 110 | int n = this->read(this, buf, len); 111 | if (n > 0) { 112 | spinlock_release(&lock); 113 | return n; 114 | } 115 | } 116 | this = this->next; 117 | if (!this) { 118 | this = consoles; 119 | } 120 | } 121 | //spinlock_release(&lock); 122 | return -1; 123 | } 124 | 125 | static int shutdown_console() 126 | { 127 | console_t *this = consoles; 128 | while (this) { 129 | if (this->flush) { 130 | this->flush(this); 131 | } 132 | if (this->close) { 133 | this->close(this); 134 | } 135 | this = this->next; 136 | } 137 | return 0; 138 | } 139 | 140 | static int console_init() 141 | { 142 | memset(console_char_buf, 0, CONSOLE_BUF_SZ); // Zero out the buffer. 143 | console_buf = make_char_ringbuf(console_char_buf, CONSOLE_BUF_SZ); 144 | return 0; 145 | } 146 | 147 | MODULE = { 148 | .name = "console", 149 | .required = NULL, 150 | .load_after = NULL, 151 | .init = &console_init, 152 | .fini = &shutdown_console, 153 | }; 154 | -------------------------------------------------------------------------------- /src/test/Kconfig: -------------------------------------------------------------------------------- 1 | config TESTING 2 | bool "Enable Kernel Unit Tests" 3 | help 4 | This option enables the unit testing of the base kernel. 5 | When this is active, testing support will be compiled in. 6 | Please note that the kernel will not function normally if 7 | this is selected. 8 | -------------------------------------------------------------------------------- /src/test/Makefile: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Apollo Project # 3 | # Test Harness Makefile # 4 | # (c) 2022 Apollo Developers # 5 | ############################## 6 | 7 | obj_$(CONFIG_TESTING) := ../third_party/unity/unity_fixture.c ../third_party/unity/unity.c 8 | obj_$(CONFIG_TESTING) += testing.c 9 | -------------------------------------------------------------------------------- /src/test/testing.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) 2018 Apollo Developers 3 | * testing.c - Testing harness interface 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | // Symbols defined by the linker. Essentially an array of test functions! 10 | extern test_mod_t __start_testing, __stop_testing; 11 | 12 | static void run_all_tests() 13 | { 14 | test_mod_t *m, *e = &__stop_testing; 15 | for (m = &__start_testing; m < e; m++) { 16 | m->runner(); // Run the test 17 | } 18 | } 19 | 20 | 21 | static int testing() 22 | { 23 | int retVal; 24 | // Making a fake argc. 25 | const char *argv[] = {"test", "-v"}; 26 | 27 | retVal = UnityMain(2, argv, run_all_tests); 28 | // TODO: Add like a 30 second busy wait here so you can actually see the result. 29 | system_shutdown(); 30 | return retVal; 31 | } 32 | 33 | MODULE = { 34 | .name = "testing", 35 | .required = NULL, 36 | .load_after = NULL, 37 | .init = &testing, 38 | .fini = NULL 39 | }; 40 | 41 | 42 | // The MODULE macro creates a module_t type named x. here we assign it to the 43 | // test_module pointer to fill the weakly assigned variable created in main.c 44 | module_t *test_module = &x; 45 | -------------------------------------------------------------------------------- /src/third_party/unity/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/third_party/unity/include/unity_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * unity_config.h 3 | * File for configging unity - Written by Apollo Developers 4 | */ 5 | 6 | #ifndef __UNITY_INCLUDE_CONFIG_H 7 | #define __UNITY_INCLUDE_CONFIG_H 8 | 9 | // We like macros 10 | 11 | // TODO: implement these headers 12 | #define UNITY_EXCLUDE_SETJMP_H 13 | #define UNITY_EXCLUDE_MATH_H 14 | #define UNITY_EXCLUDE_TIME_H 15 | #define UNITY_EXCLUDE_STDLIB_MALLOC 16 | 17 | 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/third_party/unity/include/unity_fixture.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010 James Grenning and Contributed to Unity Project 2 | * ========================================== 3 | * Unity Project - A Test Framework for C 4 | * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 5 | * [Released under MIT License. Please refer to license.txt for details] 6 | * ========================================== */ 7 | 8 | #ifndef UNITY_FIXTURE_H_ 9 | #define UNITY_FIXTURE_H_ 10 | 11 | #include "unity.h" 12 | #include "unity_internals.h" 13 | #include "unity_fixture_malloc_overrides.h" 14 | #include "unity_fixture_internals.h" 15 | 16 | int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)); 17 | 18 | 19 | #define TEST_GROUP(group)\ 20 | static const char* TEST_GROUP_##group = #group 21 | 22 | #define TEST_SETUP(group) void TEST_##group##_SETUP(void);\ 23 | void TEST_##group##_SETUP(void) 24 | 25 | #define TEST_TEAR_DOWN(group) void TEST_##group##_TEAR_DOWN(void);\ 26 | void TEST_##group##_TEAR_DOWN(void) 27 | 28 | 29 | #define TEST(group, name) \ 30 | void TEST_##group##_##name##_(void);\ 31 | void TEST_##group##_##name##_run(void);\ 32 | void TEST_##group##_##name##_run(void)\ 33 | {\ 34 | UnityTestRunner(TEST_##group##_SETUP,\ 35 | TEST_##group##_##name##_,\ 36 | TEST_##group##_TEAR_DOWN,\ 37 | "TEST(" #group ", " #name ")",\ 38 | TEST_GROUP_##group, #name,\ 39 | __FILE__, __LINE__);\ 40 | }\ 41 | void TEST_##group##_##name##_(void) 42 | 43 | #define IGNORE_TEST(group, name) \ 44 | void TEST_##group##_##name##_(void);\ 45 | void TEST_##group##_##name##_run(void);\ 46 | void TEST_##group##_##name##_run(void)\ 47 | {\ 48 | UnityIgnoreTest("IGNORE_TEST(" #group ", " #name ")", TEST_GROUP_##group, #name);\ 49 | }\ 50 | void TEST_##group##_##name##_(void) 51 | 52 | /* Call this for each test, insider the group runner */ 53 | #define RUN_TEST_CASE(group, name) \ 54 | { void TEST_##group##_##name##_run(void);\ 55 | TEST_##group##_##name##_run(); } 56 | 57 | /* This goes at the bottom of each test file or in a separate c file */ 58 | #define TEST_GROUP_RUNNER(group)\ 59 | void TEST_##group##_GROUP_RUNNER(void);\ 60 | void TEST_##group##_GROUP_RUNNER(void) 61 | 62 | /* Call this from main */ 63 | #define RUN_TEST_GROUP(group)\ 64 | { void TEST_##group##_GROUP_RUNNER(void);\ 65 | TEST_##group##_GROUP_RUNNER(); } 66 | 67 | /* CppUTest Compatibility Macros */ 68 | #ifndef UNITY_EXCLUDE_CPPUTEST_ASSERTS 69 | /* Sets a pointer and automatically restores it to its old value after teardown */ 70 | #define UT_PTR_SET(ptr, newPointerValue) UnityPointer_Set((void**)&(ptr), (void*)(newPointerValue), __LINE__) 71 | #define TEST_ASSERT_POINTERS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_PTR((expected), (actual)) 72 | #define TEST_ASSERT_BYTES_EQUAL(expected, actual) TEST_ASSERT_EQUAL_HEX8(0xff & (expected), 0xff & (actual)) 73 | #define FAIL(message) TEST_FAIL_MESSAGE((message)) 74 | #define CHECK(condition) TEST_ASSERT_TRUE((condition)) 75 | #define LONGS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_INT((expected), (actual)) 76 | #define STRCMP_EQUAL(expected, actual) TEST_ASSERT_EQUAL_STRING((expected), (actual)) 77 | #define DOUBLES_EQUAL(expected, actual, delta) TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual)) 78 | #endif 79 | 80 | /* You must compile with malloc replacement, as defined in unity_fixture_malloc_overrides.h */ 81 | void UnityMalloc_MakeMallocFailAfterCount(int countdown); 82 | 83 | #endif /* UNITY_FIXTURE_H_ */ 84 | -------------------------------------------------------------------------------- /src/third_party/unity/include/unity_fixture_internals.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010 James Grenning and Contributed to Unity Project 2 | * ========================================== 3 | * Unity Project - A Test Framework for C 4 | * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 5 | * [Released under MIT License. Please refer to license.txt for details] 6 | * ========================================== */ 7 | 8 | #ifndef UNITY_FIXTURE_INTERNALS_H_ 9 | #define UNITY_FIXTURE_INTERNALS_H_ 10 | 11 | #ifdef __cplusplus 12 | extern "C" 13 | { 14 | #endif 15 | 16 | struct UNITY_FIXTURE_T 17 | { 18 | int Verbose; 19 | unsigned int RepeatCount; 20 | const char* NameFilter; 21 | const char* GroupFilter; 22 | }; 23 | extern struct UNITY_FIXTURE_T UnityFixture; 24 | 25 | typedef void unityfunction(void); 26 | void UnityTestRunner(unityfunction* setup, 27 | unityfunction* testBody, 28 | unityfunction* teardown, 29 | const char* printableName, 30 | const char* group, 31 | const char* name, 32 | const char* file, unsigned int line); 33 | 34 | void UnityIgnoreTest(const char* printableName, const char* group, const char* name); 35 | void UnityMalloc_StartTest(void); 36 | void UnityMalloc_EndTest(void); 37 | int UnityGetCommandLineOptions(int argc, const char* argv[]); 38 | void UnityConcludeFixtureTest(void); 39 | 40 | void UnityPointer_Set(void** pointer, void* newValue, UNITY_LINE_TYPE line); 41 | void UnityPointer_UndoAllSets(void); 42 | void UnityPointer_Init(void); 43 | #ifndef UNITY_MAX_POINTERS 44 | #define UNITY_MAX_POINTERS 5 45 | #endif 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif /* UNITY_FIXTURE_INTERNALS_H_ */ 52 | -------------------------------------------------------------------------------- /src/third_party/unity/include/unity_fixture_malloc_overrides.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010 James Grenning and Contributed to Unity Project 2 | * ========================================== 3 | * Unity Project - A Test Framework for C 4 | * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 5 | * [Released under MIT License. Please refer to license.txt for details] 6 | * ========================================== */ 7 | 8 | #ifndef UNITY_FIXTURE_MALLOC_OVERRIDES_H_ 9 | #define UNITY_FIXTURE_MALLOC_OVERRIDES_H_ 10 | 11 | #include 12 | 13 | #ifdef UNITY_EXCLUDE_STDLIB_MALLOC 14 | /* Define this macro to remove the use of stdlib.h, malloc, and free. 15 | * Many embedded systems do not have a heap or malloc/free by default. 16 | * This internal unity_malloc() provides allocated memory deterministically from 17 | * the end of an array only, unity_free() only releases from end-of-array, 18 | * blocks are not coalesced, and memory not freed in LIFO order is stranded. */ 19 | #ifndef UNITY_INTERNAL_HEAP_SIZE_BYTES 20 | #define UNITY_INTERNAL_HEAP_SIZE_BYTES 256 21 | #endif 22 | #endif 23 | 24 | /* These functions are used by the Unity Fixture to allocate and release memory 25 | * on the heap and can be overridden with platform-specific implementations. 26 | * For example, when using FreeRTOS UNITY_FIXTURE_MALLOC becomes pvPortMalloc() 27 | * and UNITY_FIXTURE_FREE becomes vPortFree(). */ 28 | #if !defined(UNITY_FIXTURE_MALLOC) || !defined(UNITY_FIXTURE_FREE) 29 | #include 30 | #define UNITY_FIXTURE_MALLOC(size) malloc(size) 31 | #define UNITY_FIXTURE_FREE(ptr) free(ptr) 32 | #else 33 | extern void* UNITY_FIXTURE_MALLOC(size_t size); 34 | extern void UNITY_FIXTURE_FREE(void* ptr); 35 | #endif 36 | 37 | #define malloc unity_malloc 38 | #define calloc unity_calloc 39 | #define realloc unity_realloc 40 | #define free unity_free 41 | 42 | void* unity_malloc(size_t size); 43 | void* unity_calloc(size_t num, size_t size); 44 | void* unity_realloc(void * oldMem, size_t size); 45 | void unity_free(void * mem); 46 | 47 | #endif /* UNITY_FIXTURE_MALLOC_OVERRIDES_H_ */ 48 | -------------------------------------------------------------------------------- /x86.config: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Apollo Kernel Configuration 4 | # 5 | 6 | # 7 | # Architecture 8 | # 9 | CONFIG_TARGET="x86" 10 | CONFIG_X86_BASE=y 11 | 12 | # 13 | # Subsystems 14 | # 15 | CONFIG_TIMEKEEPING=y 16 | CONFIG_CONSOLE=y 17 | CONFIG_FRAMEBUFFER=y 18 | CONFIG_IRQ=y 19 | # CONFIG_BASE_SYSTEM is not set 20 | 21 | # 22 | # Drivers 23 | # 24 | 25 | # 26 | # Timekeeping 27 | # 28 | CONFIG_CLOCK_RTC_CMOS=y 29 | CONFIG_CLOCK_8254=y 30 | 31 | # 32 | # Console Drivers 33 | # 34 | CONFIG_CONSOLE_VGA=y 35 | CONFIG_CONSOLE_SERIAL_16550_UART=y 36 | 37 | # 38 | # IRQ Chips 39 | # 40 | CONFIG_IRQCHIP_8259=y 41 | 42 | # 43 | # Framebuffer Drivers 44 | # 45 | CONFIG_FRAMEBUFFER_VGA=y 46 | CONFIG_LIBC=y 47 | CONFIG_LIBC_MATH=y 48 | CONFIG_LIBC_STDIO=y 49 | CONFIG_LIBC_STRING=y 50 | # CONFIG_TESTING is not set 51 | --------------------------------------------------------------------------------