├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── Makefile_old ├── README.md ├── TODO-LOCALE.md ├── TODO.md ├── Unifont.psf ├── choacuryscreenshot.png ├── compile.bat ├── compile.sh ├── compile_no_audio.sh ├── create-disk.sh ├── create-disk_working.sh ├── how-to-run.txt ├── prereq.sh ├── projectlogo.png ├── src ├── assets │ ├── icns │ │ ├── capyweb_16.png │ │ └── capyweb_32.png │ └── sfx │ │ └── Startup.wav ├── boot │ ├── grub.cfg │ ├── placeholder_grub.txt │ └── splash_image.png ├── drivers │ ├── GPU │ │ ├── ihd │ │ │ └── regs.h │ │ └── vmsvga │ │ │ ├── vmsvga.c │ │ │ └── vmsvga.h │ ├── critical.h │ ├── debug.c │ ├── debug.h │ ├── egs.c │ ├── files │ │ └── sfx │ │ │ └── Startup.wav │ ├── filesystem │ │ ├── fat.c │ │ ├── fat.h │ │ ├── filesystem.c │ │ ├── virtualfs.c │ │ └── virtualfs.h │ ├── gdt.c │ ├── gdt.h │ ├── idt.c │ ├── idt.h │ ├── interrupt.asm │ ├── key.c │ ├── key.h │ ├── keymaps │ │ ├── ps2_keymap_fi.c │ │ ├── ps2_keymap_fi.h │ │ ├── ps2_keymap_gb.c │ │ ├── ps2_keymap_gb.h │ │ ├── ps2_keymap_us.c │ │ └── ps2_keymap_us.h │ ├── mouse.h │ ├── pci.c │ ├── pci.h │ ├── pic.c │ ├── pic.h │ ├── pit.c │ ├── pit.h │ ├── ports.c │ ├── ports.h │ ├── ps2.c │ ├── ps2.h │ ├── ps2_keyboard.c │ ├── ps2_keyboard.h │ ├── ps2_mouse.c │ ├── ps2_mouse.h │ ├── sound.c │ ├── sound.h │ ├── ssp.c │ ├── storage │ │ ├── ata.c │ │ ├── ata.h │ │ ├── device.c │ │ ├── device.h │ │ ├── fat.c │ │ ├── fat.h │ │ ├── gpt.c │ │ ├── gpt.h │ │ ├── partition.c │ │ └── partition.h │ ├── types.h │ ├── utils.c │ ├── utils.h │ ├── vbe.c │ ├── vbe.h │ ├── vga.c │ └── vga.h ├── gui │ ├── Point.h │ ├── bindraw.h │ ├── bitmap │ │ ├── bitmap.c │ │ └── bitmap.h │ ├── desktop.c │ ├── desktop.cpp │ ├── desktop.h │ ├── pfont.h │ └── window │ │ ├── gui.cpp │ │ ├── gui.hpp │ │ ├── headers │ │ ├── bitmap.hpp │ │ └── rim.hpp │ │ ├── icons.hpp │ │ ├── manager │ │ ├── manager.c.old │ │ ├── manager.cpp │ │ └── manager.hpp │ │ ├── window.c.old │ │ ├── window.cpp │ │ ├── window.h.old │ │ └── window.hpp ├── kernel │ ├── gdt.asm │ ├── kernel special stuff.txt │ ├── kernel.asm │ ├── kernel.c │ ├── krnentry.asm │ ├── multiboot.h │ ├── panic.c │ ├── panic.h │ ├── process.c │ └── process.h ├── linker.ld ├── memory │ ├── kmalloc.c │ ├── kmalloc.h │ ├── pmm.c │ └── pmm.h ├── recovery │ ├── pong.cpp │ ├── pong.hpp │ ├── recovery.cpp │ └── recovery.h └── shell │ ├── commands │ ├── beep │ │ ├── beep.c │ │ └── beep.h │ ├── calc │ │ ├── calc.c │ │ └── calc.h │ ├── cat │ │ ├── cat.c │ │ └── cat.h │ ├── cd │ │ ├── cd.c │ │ └── cd.h │ ├── chstat │ │ ├── chstat.c │ │ └── chstat.h │ ├── clear │ │ ├── clear.c │ │ └── clear.h │ ├── command.c │ ├── command.h │ ├── compdate │ │ ├── compdate.c │ │ └── compdate.h │ ├── echo │ │ ├── echo.c │ │ └── echo.h │ ├── guiload │ │ ├── guiload.c │ │ └── guiload.h │ ├── help │ │ ├── help.c │ │ └── help.h │ ├── ls │ │ ├── ls.c │ │ └── ls.h │ ├── mkdir │ │ ├── mkdir.c │ │ └── mkdir.h │ ├── pause │ │ ├── pause.c │ │ └── pause.h │ ├── pl │ │ ├── pl.c │ │ └── pl.h │ ├── recovery │ │ ├── recovery.c │ │ └── recovery.h │ ├── structure.md │ ├── vbetest │ │ ├── vbetest.c │ │ └── vbetest.h │ └── whereami │ │ ├── whereami.c │ │ └── whereami.h │ ├── shell.c │ ├── shell.h │ ├── string_mang.h │ ├── terminal.c │ ├── terminal.h │ └── user_input.h └── test.bmp /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve ChoacuryOS 4 | title: "[BUG]" 5 | labels: bug, needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Steps to Reproduce** 14 | Steps to reproduce the behaviour: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behaviour** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | - Version [e.g. 22] 27 | - Specific feature? 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 ChoacuryOS 4 | title: "[FEATURE]" 5 | labels: enhancement, needs-triage 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ./build 2 | build -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.ejs": "html", 4 | "fat.h": "c", 5 | "kmalloc.h": "c", 6 | "bitmap.h": "c", 7 | "window.h": "c", 8 | "stdint.h": "c", 9 | "sstream": "cpp", 10 | "pmm.h": "c", 11 | "vbe.h": "c", 12 | "terminal.h": "c", 13 | "utils.h": "c", 14 | "pit.h": "c", 15 | "device.h": "c", 16 | "debug.h": "c", 17 | "ps2_keyboard.h": "c", 18 | "sound.h": "c", 19 | "desktop.h": "c", 20 | "panic.h": "c", 21 | "vga.h": "c", 22 | "command.h": "c" 23 | } 24 | } -------------------------------------------------------------------------------- /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 on 63 | the Discord server. 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 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ChoacuryOS 2 | 3 | First off, thank you for taking the time to contribute to the project! ❤️ 4 | 5 | All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. 6 | Please make sure to read the relevant section before making your contribution. 7 | 8 | > And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about: 9 | > - Star the project 10 | > - Tweet about it 11 | > - Refer this project in your project's readme 12 | > - Mention the project at local meetups and tell your friends/colleagues 13 | 14 | 15 | ## Table of Contents 16 | 17 | - [Code of Conduct](#code-of-conduct) 18 | - [I Have a Question](#i-have-a-question) 19 | - [I Want To Contribute](#i-want-to-contribute) 20 | - [Reporting Bugs](#reporting-bugs) 21 | - [Suggesting Enhancements](#suggesting-enhancements) 22 | - [Your First Code Contribution](#your-first-code-contribution) 23 | - [Improving The Documentation](#improving-the-documentation) 24 | - [Styleguides](#styleguides) 25 | - [Commit Messages](#commit-messages) 26 | - [Join The Project Team](#join-the-project-team) 27 | 28 | 29 | ## Code of Conduct 30 | 31 | This project and everyone participating in it is governed by the 32 | [CONTRIBUTING.md Code of Conduct](blob/master/CODE_OF_CONDUCT.md). 33 | By participating, you are expected to uphold this code. Please report unacceptable behavior 34 | to <>. 35 | 36 | 37 | ## I Have a Question 38 | 39 | > If you want to ask a question, we assume that you have read the available [Documentation](https://teamchoacury.github.io/docs). 40 | 41 | Before you ask a question, it is best to search for existing [Issues](/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. 42 | It is also advisable to search the internet for answers first. 43 | 44 | If you then still feel the need to ask a question and need clarification, we recommend the following: 45 | 46 | - Open an [Issue](/issues/new). 47 | - Provide as many details as you can about the issue you are facing. 48 | - Add steps to reproduce if you can. 49 | 50 | We will look at the issue. 51 | 52 | If it is not an issue, we suggest opening a discussion on the [discussions tab](/discussions) 53 | 54 | ## I Want To Contribute 55 | 56 | > ### Legal Notice 57 | > When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license. 58 | 59 | ### Reporting Bugs 60 | 61 | #### Before Submitting a Bug Report 62 | 63 | A good bug report shouldn't leave others needing to chase you up for more information. 64 | Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. 65 | Please complete the following steps in advance to help us fix any potential bug as fast as possible. 66 | 67 | - Make sure that you are using the latest version. 68 | - Determine if your bug is really a bug and not an error on your side (e.g. using incompatible environment components/versions - make sure that you have read the [documentation](https://teamchoacury.github.io/docs/)). 69 | If you are looking for support, you might want to check [this section](#i-have-a-question)). 70 | - To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](issues?q=label%3Abug). 71 | - Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue. 72 | - Collect information about the bug: 73 | - Stack trace (Traceback) 74 | - Steps to reproduce 75 | - Screenshots/Screen recordings 76 | 77 | #### How Do I Submit a Good Bug Report? 78 | 79 | We use GitHub issues to track bugs and errors. If you run into an issue with the project: 80 | 81 | - Open an [Issue](/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) 82 | - Explain the behavior you would expect and the actual behavior. 83 | - Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. 84 | This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. 85 | - Provide the information you collected in the previous section. 86 | 87 | ### Suggesting Enhancements 88 | 89 | This section guides you through submitting an enhancement suggestion for CONTRIBUTING.md, 90 | **including completely new features and minor improvements to existing functionality**. 91 | Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions. 92 | 93 | #### Before Submitting an Enhancement 94 | 95 | - Make sure that you are using the latest version. 96 | - Read the [documentation](https://teamchoacury.github.io/docs/) carefully and find out if the functionality is already covered, maybe by an individual configuration. 97 | - Perform a [search](/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one. 98 | - Find out whether your idea fits with the scope and aims of the project. 99 | It's up to you to make a strong case to convince the project's developers of the merits of this feature. 100 | Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. 101 | If you're just targeting a minority of users, consider writing a package that they can install. 102 | 103 | 104 | #### How Do I Submit a Good Enhancement Suggestion? 105 | 106 | Enhancement suggestions are tracked as [GitHub issues](/issues). 107 | 108 | - Use a **clear and descriptive title** for the issue to identify the suggestion. 109 | - Provide a **step-by-step description of the suggested enhancement** in as many details as possible. 110 | - **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you. 111 | - You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. 112 | You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. 113 | - **Explain why this enhancement would be useful** to most CONTRIBUTING.md users. You may also want to point out the other projects that solved it better and which could serve as inspiration. 114 | 115 | ### Your First Code Contribution 116 | 117 | If this is your first time contributing to the project, make sure that you read through the various documentation, and other contributions, to familiarise yourself with the projects and our style. 118 | 119 | ### Improving The Documentation 120 | 121 | When improving the documentation, please ensure that you follow the style of the documentation. Make sure you look at other pages, similar to what you are making. If you are unsure, or cannot find an example, 122 | please ask someone in the Discord server. 123 | 124 | 138 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR := build 2 | SRC_DIR := src 3 | 4 | CC := gcc 5 | CXX := g++ # C++ 6 | LD := ld 7 | ASM := nasm 8 | 9 | CFLAGS := -m32 -O2 -lto -static -fPIC -fstack-protector -ffreestanding -Wall -Wextra -I$(SRC_DIR) 10 | CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti 11 | ASMFLAGS := -f elf32 12 | LDFLAGS := -m elf_i386 -T $(SRC_DIR)/linker.ld -nostdlib -flto 13 | 14 | # we should wildcard this # 15 | SRCS := \ 16 | drivers/debug.c \ 17 | drivers/filesystem/fat.c \ 18 | drivers/gdt.c \ 19 | drivers/idt.c \ 20 | drivers/interrupt.asm \ 21 | drivers/key.c \ 22 | drivers/pci.c \ 23 | drivers/pic.c \ 24 | drivers/pit.c \ 25 | drivers/ports.c \ 26 | drivers/ps2_keyboard.c \ 27 | drivers/ps2_mouse.c \ 28 | drivers/keymaps/ps2_keymap_fi.c \ 29 | drivers/keymaps/ps2_keymap_us.c \ 30 | drivers/ps2.c \ 31 | drivers/sound.c \ 32 | drivers/storage/ata.c \ 33 | drivers/storage/device.c \ 34 | drivers/storage/gpt.c \ 35 | drivers/storage/partition.c \ 36 | drivers/ssp.c \ 37 | drivers/utils.c \ 38 | drivers/vga.c \ 39 | drivers/vbe.c \ 40 | drivers/GPU/vmsvga/vmsvga.c \ 41 | kernel/kernel.c \ 42 | kernel/krnentry.asm \ 43 | kernel/panic.c \ 44 | memory/kmalloc.c \ 45 | memory/pmm.c \ 46 | shell/shell.c \ 47 | shell/terminal.c \ 48 | gui/desktop.cpp \ 49 | shell/commands/command.c \ 50 | shell/commands/guiload/guiload.c \ 51 | shell/commands/clear/clear.c \ 52 | shell/commands/beep/beep.c \ 53 | shell/commands/calc/calc.c \ 54 | shell/commands/compdate/compdate.c \ 55 | shell/commands/echo/echo.c \ 56 | shell/commands/pause/pause.c \ 57 | shell/commands/pl/pl.c \ 58 | shell/commands/chstat/chstat.c \ 59 | shell/commands/cd/cd.c \ 60 | shell/commands/cat/cat.c \ 61 | shell/commands/ls/ls.c \ 62 | shell/commands/whereami/whereami.c \ 63 | shell/commands/vbetest/vbetest.c \ 64 | shell/commands/recovery/recovery.c \ 65 | gui/bitmap/bitmap.c \ 66 | gui/window/window.cpp \ 67 | gui/window/manager/manager.cpp \ 68 | gui/window/gui.cpp \ 69 | recovery/recovery.cpp \ 70 | recovery/pong.cpp \ 71 | #gui/widgets.c \ # remove comment when its implemented. 72 | # gui/desktop.cpp (See line 46) was previously a C file 73 | # gui/window/window.cpp (See line 65) was previously a C file 74 | # gui/window/manager/manager.cpp (See line 66) was previously a C file 75 | 76 | OBJS := $(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(SRCS))) 77 | DEPS := $(addprefix $(BUILD_DIR)/,$(addsuffix .d,$(filter-out %.asm,$(SRCS)))) 78 | 79 | .PHONY: all kernel iso run clean 80 | 81 | all: kernel 82 | 83 | kernel: $(OBJS) 84 | $(LD) $(LDFLAGS) $(OBJS) -o $(BUILD_DIR)/ChoacuryOS.bin 85 | grub-file --is-x86-multiboot $(BUILD_DIR)/ChoacuryOS.bin 86 | 87 | img: kernel 88 | ./create-disk.sh 89 | 90 | run: img 91 | qemu-system-x86_64 -hda $(BUILD_DIR)/ChoacuryOS.img -serial stdio -audiodev pa,id=snd0 -machine pcspk-audiodev=snd0 92 | 93 | clean: 94 | rm -rf $(BUILD_DIR) 95 | 96 | -include $(DEPS) 97 | 98 | $(BUILD_DIR)/%.c.o: $(SRC_DIR)/%.c Makefile 99 | @mkdir -p $(@D) 100 | $(CC) $(CFLAGS) -MMD -MP -c $< -o $@ 101 | 102 | $(BUILD_DIR)/%.cpp.o: $(SRC_DIR)/%.cpp Makefile 103 | @mkdir -p $(@D) 104 | $(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@ 105 | 106 | $(BUILD_DIR)/%.asm.o: $(SRC_DIR)/%.asm 107 | @mkdir -p $(@D) 108 | $(ASM) $(ASMFLAGS) $< -o $@ 109 | -------------------------------------------------------------------------------- /Makefile_old: -------------------------------------------------------------------------------- 1 | BUILD_DIR := build 2 | SRC_DIR := src 3 | 4 | CC := gcc 5 | LD := ld 6 | ASM := nasm 7 | 8 | CFLAGS := -m32 -march=i386 -O2 -lto -mgeneral-regs-only -static -fPIC -fstack-protector -ffreestanding -Wall -Wextra -I$(SRC_DIR) 9 | ASMFLAGS := -f elf32 10 | LDFLAGS := -m elf_i386 -T $(SRC_DIR)/linker.ld -nostdlib -flto 11 | 12 | # we should wildcard this # 13 | SRCS := \ 14 | drivers/debug.c \ 15 | drivers/filesystem/fat.c \ 16 | drivers/gdt.c \ 17 | drivers/idt.c \ 18 | drivers/interrupt.asm \ 19 | drivers/key.c \ 20 | drivers/pci.c \ 21 | drivers/pic.c \ 22 | drivers/pit.c \ 23 | drivers/ports.c \ 24 | drivers/ps2_keyboard.c \ 25 | drivers/ps2_mouse.c \ 26 | drivers/keymaps/ps2_keymap_fi.c \ 27 | drivers/keymaps/ps2_keymap_us.c \ 28 | drivers/ps2.c \ 29 | drivers/sound.c \ 30 | drivers/storage/ata.c \ 31 | drivers/storage/device.c \ 32 | drivers/storage/gpt.c \ 33 | drivers/storage/partition.c \ 34 | drivers/ssp.c \ 35 | drivers/utils.c \ 36 | drivers/vga.c \ 37 | drivers/vbe.c \ 38 | drivers/GPU/vmsvga/vmsvga.c \ 39 | kernel/kernel.c \ 40 | kernel/krnentry.asm \ 41 | kernel/panic.c \ 42 | memory/kmalloc.c \ 43 | memory/pmm.c \ 44 | shell/shell.c \ 45 | shell/terminal.c \ 46 | gui/desktop.c \ 47 | shell/commands/command.c \ 48 | shell/commands/guiload/guiload.c \ 49 | shell/commands/clear/clear.c \ 50 | shell/commands/beep/beep.c \ 51 | shell/commands/calc/calc.c \ 52 | shell/commands/compdate/compdate.c \ 53 | shell/commands/echo/echo.c \ 54 | shell/commands/pause/pause.c \ 55 | shell/commands/pl/pl.c \ 56 | shell/commands/chstat/chstat.c \ 57 | shell/commands/cd/cd.c \ 58 | shell/commands/cat/cat.c \ 59 | shell/commands/ls/ls.c \ 60 | shell/commands/whereami/whereami.c \ 61 | shell/commands/vbetest/vbetest.c \ 62 | gui/window/window.c \ 63 | #gui/widgets.c \ # remove comment when its implemented. 64 | 65 | OBJS := $(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(SRCS))) 66 | DEPS := $(addprefix $(BUILD_DIR)/,$(addsuffix .d,$(filter-out %.asm,$(SRCS)))) 67 | 68 | .PHONY: all kernel iso run clean 69 | 70 | all: kernel 71 | 72 | kernel: $(OBJS) 73 | $(LD) $(LDFLAGS) $(OBJS) -o $(BUILD_DIR)/ChoacuryOS.bin 74 | grub-file --is-x86-multiboot $(BUILD_DIR)/ChoacuryOS.bin 75 | 76 | img: kernel 77 | ./create-disk.sh 78 | 79 | run: img 80 | qemu-system-x86_64 -hda $(BUILD_DIR)/ChoacuryOS.img -serial stdio -audiodev pa,id=snd0 -machine pcspk-audiodev=snd0 81 | 82 | clean: 83 | rm -rf $(BUILD_DIR) 84 | 85 | -include $(DEPS) 86 | 87 | $(BUILD_DIR)/%.c.o: $(SRC_DIR)/%.c Makefile 88 | @mkdir -p $(@D) 89 | $(CC) $(CFLAGS) -MMD -MP -c $< -o $@ 90 | 91 | $(BUILD_DIR)/%.asm.o: $(SRC_DIR)/%.asm 92 | @mkdir -p $(@D) 93 | $(ASM) $(ASMFLAGS) $< -o $@ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | [![GitHub release](https://img.shields.io/github/release/Pineconium/ChoacuryOS?include_prereleases=&sort=semver&color=blue)](https://github.com/Pineconium/ChoacuryOS/releases/) 6 | [![License](https://img.shields.io/badge/License-GPL--3.0-blue)](#license) 7 | [![issues - ChoacuryOS](https://img.shields.io/github/issues/Pineconium/ChoacuryOS)](https://github.com/Pineconium/ChoacuryOS/issues) 8 | 9 | [View documentation](https://teamchoacury.github.io/docs/) 10 | 11 | Choacury, (pronounced as coch-curry or /kʰɔx-ˈkʌr.i/), is a custom-built OS written in C, C++ and Assembly. Choacury is currently in a very **Pre-Alpha** stage, meaning some stuff isn't complete yet... 12 | 13 | ![ChoacuryScreenshot](https://raw.githubusercontent.com/Pineconium/ChoacuryOS/main/choacuryscreenshot.png) 14 | 15 | If you want to help out on the project, feel free to contribute to the project! (see TODO.MD for what is needed doing). You can also modify Choacury to your liking if you want to make your own OS! You can also join the [development server](https://discord.gg/qhgDWrzCvg) if you want. 16 | 17 | # System Requirements 18 | Currently, Choacury only works best with virtual machines. However, you *can* use real hardware if you want, just there might be some issues that will be fixed down the line. 19 | 20 | For VirtualBox Users, here are the recommended VM requirements: 21 | - Operating System: Other/Unknown 22 | - Base Memory: 64 MB. 23 | - Video Memory: 9 MB. 24 | - Hard Disk: 2.00 GB. 25 | 26 | # Compile Choacury. 27 | If you want to compile Choacury from the source code, here's what you'll need. 28 | 1. NASM, GCC, GRUB Multiboot, Makefile, and QEMU installed. (the compiler uses the `x86_64` version of QEMU. If you don't use that version of QEMU, replace `qemu-system-x86_64` in the compiler shell script with your version of QEMU) 29 | 2. A computer running any Linux distro (recommended, but there is a batch script for Windows devices as long as you have WSL installed). 30 | 31 | # Contributing 32 | Please read the [contribution guidelines](/CONTRIBUTING.md), and [code of conduct](/CODE_OF_CONDUCT.md) before you contribute. 33 | **All contributions are welcomed! ❤️** 34 | -------------------------------------------------------------------------------- /TODO-LOCALE.md: -------------------------------------------------------------------------------- 1 | # Choacury Localizition To-Do List 2 | 3 | Needs to be expanded, planned to be used when we get the installer and the GUI working. 4 | 5 | ## Keyboard Input 6 | - [x] English (US) 7 | - [ ] English (UK/International) 8 | - [ ] French 9 | - [ ] Spanish (Mexican/Latin American) 10 | - [ ] Spanish (Europe) 11 | - [ ] Portuguese (European) 12 | - [ ] Portuguese (Brazillian) 13 | - [x] Finnish 14 | - [ ] Danish 15 | - [ ] Norwegian 16 | - [ ] Swedish 17 | - [ ] Japanese 18 | - [ ] Chinese 19 | - [ ] Korean 20 | - [ ] Arabic 21 | 22 | ## Translations 23 | - [ ] English (US) 24 | - [x] English (UK/International) 25 | - [ ] French 26 | - [ ] Spanish (Mexican/Latin American) 27 | - [ ] Spanish (Europe) 28 | - [ ] Portuguese (European) 29 | - [ ] Portuguese (Brazillian) 30 | - [ ] Finnish 31 | - [ ] Danish 32 | - [ ] Norwegian 33 | - [ ] Swedish 34 | - [ ] Japanese 35 | - [ ] Chinese 36 | - [ ] Korean 37 | - [ ] Arabic 38 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Todo for Choacury 2 | 3 | ### Barebones 4 | 5 | - [x] Compiler (Linux). 6 | - [x] Compiler (Windows). 7 | - [x] Makefile. 8 | - [x] Cursor Control. 9 | 10 | ### Kernel 11 | - [x] String Message. 12 | - [x] Keyboard Input (PS/2 Only) 13 | - [ ] Multi-Tasking. 14 | - [ ] Multi Core. 15 | - [ ] Multi Threading. 16 | - [ ] ML Paging 17 | - [ ] More CPU features supported (e.g. AVX10, AVX512, SSE5...) 18 | 19 | ### Extra Drivers 20 | - [ ] USB Keyboard Support. 21 | - [ ] Network Card support. 22 | - [ ] USB Mouse Support. 23 | 24 | ### Misc. 25 | - [ ] Ctrl+Alt+Del support 26 | 27 | ### Command Line Interface (CLI) 28 | - [x] Scrolling. 29 | - [x] Barebones CLI. 30 | - [x] Terminal Commands. 31 | - [x] Command Input Detection. 32 | - [x] Standard "echo" command. 33 | 34 | ### Filesystem 35 | - [x] Barebones. 36 | - [x] GPT Partitioning Support. 37 | - [x] Detection from CLI. 38 | - [x] Let Users View files/dirs 39 | - [x] Let Users Read files/dirs 40 | - [ ] Let Users Modify files/dirs 41 | - [ ] Let Users Create files/dirs 42 | - [ ] Built in CLI Text Editor 43 | - [x] FAT Support. 44 | - [ ] RAM Disk 45 | - [ ] Custom Filesystem (CHFM). 46 | - [ ] ext4 (Linux) Support. 47 | - [ ] NTFS (Windows) Support. 48 | 49 | ### Graphics 50 | - [x] 4-bit colour support (16/Standard DOS colours). 51 | - [x] 8-bit colour support (256 colours/ANSI Support). 52 | - [x] High-colour/True colour support (beyond 8-bit/>=256 colours). 53 | - [x] Graphical Shell (GUI). 54 | - [ ] Window Management System 55 | - [x] Mouse Drivers 56 | - [ ] Virtual Terminal/Command Prompt 57 | - [ ] Basic GUI Apps. (e.g. File Manager, Program Launcher) 58 | - [x] VMWare SVGA II drivers 59 | - [x] Bochs Graphics Adaptor 60 | - [ ] Intel HD drivers 61 | - [ ] NVIDIA drivers 62 | - [ ] AMD drivers 63 | - [ ] 3D acceleration 64 | - [x] Possible switch to GPU framebuffer 65 | 66 | ### Audio 67 | - [x] PC Speaker/DOS Beeps. 68 | - [ ] Sound Blaster 16. 69 | - [ ] Audio Codec '97. 70 | - [ ] Intel High Definition Audio. 71 | 72 | ### Networking/Internet 73 | - [ ] Standard networking support. 74 | - [ ] Ability to ping networks/servers. 75 | - [ ] Ability to host a server 76 | - [ ] Working Graphical Web Browser 77 | 78 | ### CPU Architectures 79 | - [x] x86 (Common Intel/AMD) 80 | - [ ] ARM and ARM-based (e.g. Apple Silicon) 81 | - [ ] PowerPC 82 | - [ ] MIPS 83 | 84 | ### Shell 85 | - [ ] Arrow keys support in shell 86 | - [ ] Tab key implementation 87 | - [ ] Options for commands like ls -a -l -R.... and support for more cd commands like cd -, cd ~ 88 | - [ ] Stop using VGA text mode 89 | 90 | -------------------------------------------------------------------------------- /Unifont.psf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/Unifont.psf -------------------------------------------------------------------------------- /choacuryscreenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/choacuryscreenshot.png -------------------------------------------------------------------------------- /compile.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | title Choacury Compiler 3 | wsl ./compile.sh 4 | pause 5 | qemu -hda build/ChoacuryOS.img -display sdl 6 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Just the Makefile run target 3 | make run 4 | -------------------------------------------------------------------------------- /compile_no_audio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make && ./create-disk.sh && qemu-system-x86_64 -hda build/ChoacuryOS.img -serial stdio -------------------------------------------------------------------------------- /create-disk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MOUNT_DIR=build/mount 4 | DISK_PATH=build/ChoacuryOS.img 5 | DISK_SIZE=$((50 * 1024 * 1024)) 6 | 7 | test -f $DISK_PATH 8 | SHOULD_BUILD=$? 9 | 10 | if (($SHOULD_BUILD)); then 11 | # create empty disk image 12 | truncate -s 0 $DISK_PATH 13 | dd if=/dev/zero of=$DISK_PATH bs=512 count=$(($DISK_SIZE / 512)) 14 | 15 | # create partition table 16 | parted --script $DISK_PATH \ 17 | mklabel gpt \ 18 | mkpart boot 1M 2M \ 19 | set 1 bios_grub on \ 20 | mkpart root ext2 2M 100% 21 | fi 22 | 23 | # create loop device 24 | LOOP_DEV=$(sudo losetup --show -fP $DISK_PATH || exit 1) 25 | PARTITION1=${LOOP_DEV}p1 26 | PARTITION2=${LOOP_DEV}p2 27 | if [ ! -b $PARTITION1 ] || [ ! -b $PARTITION2 ]; then 28 | echo "Failed to probe partitions for disk image." >&2 29 | sudo losetup -d $LOOP_DEV 30 | exit 1 31 | fi 32 | 33 | if (($SHOULD_BUILD)); then 34 | # create root filesystem 35 | sudo mkfs.fat $PARTITION2 36 | fi 37 | 38 | # mount root filesystem 39 | mkdir -p $MOUNT_DIR 40 | sudo mount $PARTITION2 "$MOUNT_DIR" 41 | 42 | if (($SHOULD_BUILD)); then 43 | # install grub 44 | sudo grub-install \ 45 | --no-floppy \ 46 | --target=i386-pc \ 47 | --modules="normal ext2 multiboot" \ 48 | --boot-directory="$MOUNT_DIR/boot" \ 49 | $LOOP_DEV 50 | 51 | sudo mkdir -p "$MOUNT_DIR/boot/grub" 52 | sudo cp src/boot/grub.cfg $MOUNT_DIR/boot/grub/ 53 | fi 54 | 55 | # copy kernel to boot 56 | sudo cp build/ChoacuryOS.bin $MOUNT_DIR/boot/ 57 | # copy fonts to / 58 | sudo cp Unifont.psf $MOUNT_DIR/ 59 | 60 | # cleanup 61 | sudo umount "$MOUNT_DIR" 62 | sudo losetup -d $LOOP_DEV 63 | -------------------------------------------------------------------------------- /create-disk_working.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MOUNT_DIR=build/mount 4 | DISK_PATH=build/ChoacuryOS.img 5 | DISK_SIZE=$((50 * 1024 * 1024)) 6 | 7 | test -f $DISK_PATH 8 | SHOULD_BUILD=$? 9 | 10 | if (($SHOULD_BUILD)); then 11 | # create empty disk image 12 | truncate -s 0 $DISK_PATH 13 | dd if=/dev/zero of=$DISK_PATH bs=512 count=$(($DISK_SIZE / 512)) 14 | 15 | # create partition table 16 | parted --script $DISK_PATH \ 17 | mklabel gpt \ 18 | mkpart boot 1M 2M \ 19 | set 1 bios_grub on \ 20 | mkpart root ext2 2M 100% 21 | fi 22 | 23 | # create loop device 24 | LOOP_DEV=$(sudo losetup --show -fP $DISK_PATH || exit 1) 25 | PARTITION1=${LOOP_DEV}p1 26 | PARTITION2=${LOOP_DEV}p2 27 | if [ ! -b $PARTITION1 ] || [ ! -b $PARTITION2 ]; then 28 | echo "Failed to probe partitions for disk image." >&2 29 | sudo losetup -d $LOOP_DEV 30 | exit 1 31 | fi 32 | 33 | if (($SHOULD_BUILD)); then 34 | # create root filesystem 35 | sudo mkfs.fat $PARTITION2 36 | fi 37 | 38 | # mount root filesystem 39 | mkdir -p $MOUNT_DIR 40 | sudo mount $PARTITION2 "$MOUNT_DIR" 41 | 42 | if (($SHOULD_BUILD)); then 43 | # install grub 44 | sudo grub-install \ 45 | --no-floppy \ 46 | --target=i386-pc \ 47 | --modules="normal ext2 multiboot" \ 48 | --boot-directory="$MOUNT_DIR/boot" \ 49 | $LOOP_DEV 50 | 51 | sudo mkdir -p "$MOUNT_DIR/boot/grub" 52 | sudo cp src/boot/grub.cfg $MOUNT_DIR/boot/grub/ 53 | fi 54 | 55 | # copy kernel to boot 56 | sudo cp build/ChoacuryOS.bin $MOUNT_DIR/boot/ 57 | # copy fonts to / 58 | sudo cp Unifont.psf $MOUNT_DIR/ 59 | sudo cp test.bmp $MOUNT_DIR/ 60 | 61 | # cleanup 62 | sudo umount "$MOUNT_DIR" 63 | sudo losetup -d $LOOP_DEV 64 | -------------------------------------------------------------------------------- /how-to-run.txt: -------------------------------------------------------------------------------- 1 | sudo sh ./compile_no_audio.sh 2 | sudo sh ./create-disk_working.sh 3 | qemu-system-x86_64 -hda build/ChoacuryOS.img -serial stdio 4 | 5 | And just ignore the errors -------------------------------------------------------------------------------- /prereq.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # NOTICE: Only for Debian/Ubuntu-based distros. Arch, Gentoo, and Fedora will come soon! 4 | echo "Installing needed software, prepare for a root password prompt" 5 | sudo apt install gcc build-essential grub-common 6 | echo "Done. Check for any errors and warnings that may come up." 7 | -------------------------------------------------------------------------------- /projectlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/projectlogo.png -------------------------------------------------------------------------------- /src/assets/icns/capyweb_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/src/assets/icns/capyweb_16.png -------------------------------------------------------------------------------- /src/assets/icns/capyweb_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/src/assets/icns/capyweb_32.png -------------------------------------------------------------------------------- /src/assets/sfx/Startup.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/src/assets/sfx/Startup.wav -------------------------------------------------------------------------------- /src/boot/grub.cfg: -------------------------------------------------------------------------------- 1 | insmod all_video 2 | 3 | menuentry "Start Choacury" { 4 | multiboot /boot/ChoacuryOS.bin 5 | } 6 | menuentry "Reboot System" { 7 | reboot 8 | } -------------------------------------------------------------------------------- /src/boot/placeholder_grub.txt: -------------------------------------------------------------------------------- 1 | ######################################################################## 2 | REPLACE GRUB.CFG CONTENTS WITH THIS WHEN SPLASH IMAGE SUPPORT IS READY! 3 | ######################################################################## 4 | 5 | menuentry "Start Choacury" { 6 | background_image /boot/splash_image.png 7 | multiboot /boot/ChoacuryOS.bin 8 | } 9 | menuentry "Reboot System" { 10 | reboot 11 | } 12 | -------------------------------------------------------------------------------- /src/boot/splash_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/src/boot/splash_image.png -------------------------------------------------------------------------------- /src/drivers/GPU/ihd/regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | Intel HD Ironlake registers 3 | */ 4 | 5 | #pragma once 6 | #define PP_STAT 0xC7200 7 | #define PP_CTRL 0xC7204 8 | #define PP_ON_DELAYS 0xC7208 9 | #define PP_OFF_DELAYS 0xC720C 10 | 11 | typedef enum { 12 | PP_CTRL_BACKLIGHT_PWR = 2 13 | } PP_CTRL_BITS; 14 | 15 | //Backlight control registers 16 | #define PWM_PCH_CTRL 0xC8250 17 | #define PWM_MOD_FREQ 0xC8254 18 | 19 | typedef enum { 20 | PWM_PCH_CTRL_ENABLE = 31, 21 | PWM_PCH_CTRL_POLARITY = 29, 22 | } PWM_PCH_CTRL_BITS; 23 | 24 | #define BLC_PWM_CTL2 0x48250 25 | #define BLC_PWM_CTL1 0x48254 26 | 27 | typedef enum { 28 | BLC_PWM_CTL2_ENABLE = 31, 29 | BLC_PWM_CTL2_PIPE_ASSIGNMENT = 29, 30 | } BLC_PWM_CTL2_BITS; 31 | 32 | #define DISP_HOTPLUG_DETECT 0xC4030 33 | 34 | #define SOUTH_DISP_INTMSK 0xC4004 35 | #define SOUTH_DISP_INTSTS 0xC4008 36 | #define SOUTH_DISP_INT_ENABLE 0xC400C 37 | 38 | typedef enum { 39 | SOUTH_DISP_INT_DPD_HOTPLUG = 10, 40 | SOUTH_DISP_INT_DPC_HOTPLUG = 9, 41 | SOUTH_DISP_INT_DPB_HOTPLUG = 8, 42 | } SOUTH_DISP_INT_BITS; 43 | 44 | typedef enum { 45 | DISP_HOTPLUG_DETECT_DPD_DETECT_ENABLE = 20, 46 | DISP_HOTPLUG_DETECT_DPC_DETECT_ENABLE = 12, 47 | DISP_HOTPLUG_DETECT_DPB_DETECT_ENABLE = 4, 48 | } DISP_HOTPLUG_DETECT_BITS; 49 | 50 | //GMBUS registers - read EDID 51 | #define GMBUS_0 0xC5100 52 | #define GMBUS_1 0xC5104 53 | #define GMBUS_2 0xC5108 54 | #define GMBUS_3 0xC510C 55 | #define GMBUS_4 0xC5110 56 | #define GMBUS_5 0xC5120 57 | 58 | typedef enum { 59 | GMBUS_RATE_100KHZ = 0, 60 | GMBUS_RATE_50KHZ = 1, 61 | GMBUS_RATE_400KHZ = 2, 62 | } GMBUS_RATE; 63 | 64 | typedef enum { 65 | GMBUS_DEVICE_ANALOG = 2, 66 | GMBUS_DEVICE_LVDS = 3, 67 | GMBUS_DEVICE_PORTC = 4, 68 | GMBUS_DEVICE_PORTB = 5, 69 | GMBUS_DEVICE_PORTD = 6 70 | } GMBUS_DEVICE; 71 | 72 | //Port control registers 73 | #define CRT_PORT_CTRL 0xE1100 74 | #define HDMIC_PORT_CTRL 0xE1150 75 | #define HDMID_PORT_CTRL 0xE1160 76 | #define LVDS_PORT_CTRL 0xE1180 77 | 78 | #define PORT_CTRL_PORT_IS_PRESENT(val) (val & (1 << 2)) 79 | 80 | //Panel fitter registers 81 | #define PF_CTRL_1(i) (0x68080 + (0x800 * i)) 82 | #define PF_WIN_SZ(i) (0x68074 + (0x800 * i)) 83 | #define PF_WIN_POS(i) (0x68070 + (0x800 * i)) 84 | 85 | typedef enum { 86 | PF_CTRL_ENABLE_SCALER = 31, 87 | } PF_CTRL_BITS; 88 | 89 | typedef enum { 90 | PF_WIN_WIDTH_OFF = 16, 91 | PF_WIN_HEIGHT_OFF = 0, 92 | } PF_WIN_SZ_OFFSETS; 93 | 94 | typedef enum { 95 | PF_WIN_X_OFF = 16, 96 | PF_WIN_Y_OFF = 0, 97 | } PF_WIN_POS_OFFSETS; 98 | 99 | #define PF_WIN_SZ_MASK 0xFFF 100 | #define PF_WIN_POS_MASK 0xFFF 101 | 102 | //Pipe registers 103 | #define HTOTAL(x) (0x60000) 104 | #define HBLANK(x) (0x60004) 105 | #define HSYNC(x) (0x60008) 106 | 107 | #define VTOTAL(x) (0x6000C) 108 | #define VBLANK(x) (0x60010) 109 | #define VSYNC(x) (0x60014) 110 | 111 | #define PIPE_SZ(x) (0x6001C) 112 | #define VSYNCSHIFT(x) (0x60028) 113 | 114 | typedef enum { 115 | PIPE_TOTAL_ACTIVE_OFF = 0, 116 | PIPE_TOTAL_TOTAL_OFF = 16, 117 | } PIPE_TOTAL_BITS; 118 | 119 | typedef enum { 120 | PIPE_BLANK_START_OFF = 0, 121 | PIPE_BLANK_END_OFF = 16 122 | } PIPE_BLANK_BITS; 123 | 124 | typedef enum { 125 | PIPE_SYNC_START_OFF = 0, 126 | PIPE_SYNC_END_OFF = 16 127 | } PIPE_SYNC_BITS; 128 | 129 | typedef enum { 130 | PIPE_SZ_WIDTH_OFF = 16, 131 | PIPE_SZ_HEIGHT_OFF = 0, 132 | } PIPE_SZ_BITS; 133 | 134 | #define PIPE_TOTAL_TOTAL_MASK 0x1FFF 135 | #define PIPE_TOTAL_ACTIVE_MASK 0xFFF 136 | 137 | #define PIPE_BLANK_START_MASK 0x1FFF 138 | #define PIPE_BLANK_END_MASK 0x1FFF 139 | 140 | #define PIPE_SYNC_START_MASK 0x1FFF 141 | #define PIPE_SYNC_END_MASK 0x1FFF 142 | 143 | #define PIPE_SZ_WIDTH_MASK 0xFFF 144 | #define PIPE_SZ_HEIGHT_MASK 0xFFF 145 | 146 | 147 | #define PIPE_DATA_M1(x) (0x60030) 148 | 149 | #define PIPE_CONF(x) (0x70008 + (x * 0x1000)) 150 | 151 | typedef enum { 152 | PIPE_CONF_ENABLE = 31, 153 | PIPE_CONF_STATE = 30, 154 | } PIPE_CONF_BITS; 155 | 156 | //Plane Control registers 157 | //VGA Plane Control 158 | #define VGA_PLANE_CTRL 0x41000 159 | 160 | typedef enum { 161 | VGA_PLANE_CTRL_DISABLE_BIT = 31, 162 | VGA_PLANE_PIPE_SELECT_BIT = 29, 163 | } VGA_PLANE_CTRL_BITS; 164 | 165 | //VGA registers 166 | #define VGA_CLOCKING_MODE_CTRL 0x3C5 167 | 168 | #define VGA_CLOCKING_MODE_SCREEN_OFF (1 << 5) 169 | 170 | 171 | //Cursor plane registers 172 | #define CURSOR_PLANE_CTRL(x) (0x70080 + (x * 0x40)) 173 | #define CURSOR_PLANE_BASE(x) (0x70084 + (x * 0x40)) 174 | #define CURSOR_PLANE_POS(x) (0x70088 + (x * 0x40)) 175 | 176 | typedef enum { 177 | CURSOR_PLANE_CTRL_ENABLE_BIT = 27, 178 | CURSOR_PLANE_CTRL_GAMME_ENABLE_BIT = 26, 179 | CURSOR_PLANE_CTRL_MODE_SELECT_UPPER_BIT = 5, 180 | CURSOR_PLANE_CTRL_MODE_SELECT_LOWER_BITS = 0, 181 | } CURSOR_PLANE_CTRL_BITS; 182 | 183 | #define CURSOR_PLANE_CTRL_MODE_SELECT_LOWER_MASK 0x7 184 | #define CURSOR_PLANE_CTRL_MODE_SELECT_CLEAR_MASK ~((1 << CURSOR_PLANE_CTRL_MODE_SELECT_UPPER_BIT) | CURSOR_PLANE_CTRL_MODE_SELECT_LOWER_MASK) 185 | #define CURSOR_PLANE_CTRL_MODE_SELECT_CONV(x) (((x >> 3) << CURSOR_PLANE_CTRL_MODE_SELECT_UPPER_BIT) | ((x & CURSOR_PLANE_CTRL_MODE_SELECT_LOWER_MASK) >> CURSOR_PLANE_CTRL_MODE_SELECT_LOWER_BITS)) 186 | 187 | //NOTE: There are more modes, but these are the only ones we care about. Check the PRM for more info. 188 | typedef enum { 189 | CURSOR_PLANE_DISABLED = 0, 190 | CURSOR_PLANE_128_128_32_RGB_888_ANDINV = 0x2, 191 | CURSOR_PLANE_256_256_32_RGB_888_ANDINV = 0x3, 192 | CURSOR_PLANE_64_64_32_RGB_888_ANDINV = 0x7, 193 | CURSOR_PLANE_128_128_32_ARGB_8888 = 0xA, 194 | CURSOR_PLANE_256_256_32_ARGB_8888 = 0xB, 195 | CURSOR_PLANE_64_64_32_ARGB_8888 = 0xF, 196 | } CURSOR_PLANE_MODES; 197 | 198 | typedef enum { 199 | CURSOR_PLANE_POS_Y_SIGN_BIT = 31, 200 | CURSOR_PLANE_POS_Y_MAGN_OFF = 16, 201 | CURSOR_PLANE_POS_X_SIGN_BIT = 15, 202 | CURSOR_PLANE_POS_X_MAGN_OFF = 0, 203 | } CURSOR_PLANE_POS_BITS; 204 | 205 | #define CURSOR_PLANE_POS_X_MAGN_MASK 0xFFF 206 | #define CURSOR_PLANE_POS_Y_MAGN_MASK 0xFFF 207 | 208 | 209 | //Display plane registers 210 | #define DISPLAY_PLANE_CTRL(x) (0x70180 + (x * 0x1000)) 211 | #define DISPLAY_PLANE_LINOFF(x) (0x70184 + (x * 0x1000)) 212 | #define DISPLAY_PLANE_STRIDE(x) (0x70188 + (x * 0x1000)) 213 | #define DISPLAY_PLANE_SURFACE_ADDR(x) (0x7019C + (x * 0x1000)) 214 | 215 | typedef enum { 216 | DISPLAY_PLANE_CTRL_ENABLE_BIT = 31, 217 | DISPLAY_PLANE_CTRL_GAMMA_ENABLE_BIT = 30, 218 | DISPLAY_PLANE_CTRL_PIXEL_MODE_OFF = 26, 219 | DISPLAY_PLANE_CTRL_ASYNC_SURFACE_ADDR_UPDATE_ENABLE_BIT = 9, 220 | } DISPLAY_PLANE_CTRL_BITS; 221 | 222 | typedef enum { 223 | DISPLAY_PLANE_PIXEL_MODE_XRGB_8_8_8_8 = 0x6, 224 | DISPLAY_PLANE_PIXEL_MODE_XBGR_2_10_10_10 = 0x8, 225 | DISPLAY_PLANE_PIXEL_MODE_XRGB_2_10_10_10 = 0xA, 226 | DISPLAY_PLANE_PIXEL_MODE_XBGR_8_8_8_8 = 0xE, 227 | } DISPLAY_PLANE_PIXEL_MODES; 228 | 229 | #define DISPLAY_PLANE_CTRL_PIXEL_MODE_MASK 0xF 230 | 231 | //Video plane registers 232 | #define VIDEO_PLANE_CTRL(x) (0x72180 + (x * 0x1000)) 233 | #define VIDEO_PLANE_LINOFF(x) (0x72184 + (x * 0x1000)) 234 | #define VIDEO_PLANE_STRIDE(x) (0x72188 + (x * 0x1000)) 235 | #define VIDEO_PLANE_POS(x) (0x7218C + (x * 0x1000)) 236 | #define VIDEO_PLANE_LOC(x) (0x72190 + (x * 0x1000)) 237 | #define VIDEO_PLANE_SURFACE_ADDR(x) (0x7219C + (x * 0x1000)) 238 | 239 | typedef enum { 240 | VIDEO_PLANE_CTRL_ENABLE_BIT = 31, 241 | } VIDEO_PLANE_CTRL_BITS; 242 | -------------------------------------------------------------------------------- /src/drivers/GPU/vmsvga/vmsvga.c: -------------------------------------------------------------------------------- 1 | #include "vmsvga.h" 2 | #include "../../pci.h" 3 | #include "../../types.h" 4 | #include "../../debug.h" 5 | 6 | static inline void outportl(unsigned short port, unsigned int data) { 7 | __asm__ volatile ("outl %0, %1" : : "a"(data), "Nd"(port)); 8 | } 9 | 10 | static inline unsigned int inportl(unsigned short port) { 11 | unsigned int result; 12 | __asm__ volatile ("inl %1, %0" : "=a"(result) : "Nd"(port)); 13 | return result; 14 | } 15 | 16 | 17 | /* Vmware svga II utility functions*/ 18 | void write_register(u32 base_port, u32 reg, u32 value) { 19 | outportl(base_port + SVGA_INDEX_PORT_OFFSET, reg); 20 | outportl(base_port + SVGA_VALUE_PORT_OFFSET, value); 21 | } 22 | 23 | u32 read_register(u32 base_port, u32 reg) { 24 | outportl(base_port + SVGA_INDEX_PORT_OFFSET, reg); 25 | return inportl(base_port + SVGA_VALUE_PORT_OFFSET); 26 | } 27 | 28 | void write_fifo(u32 base_port, u32 value) { 29 | u32 fifo_offset = read_register(base_port, SVGA_FIFO_NEXT_CMD); 30 | outportl(base_port + fifo_offset, value); 31 | write_register(base_port, SVGA_FIFO_NEXT_CMD, fifo_offset + 4); 32 | } 33 | 34 | 35 | int detect_vmware_svga() { 36 | for (int bus = 0; bus < 8; ++bus) { 37 | for (int device = 0; device < 32; ++device) { 38 | for (int function = 0; function < 8; ++function) { 39 | u32 vendor_device_id = read_pci(bus, device, function, 0x00); 40 | if ((vendor_device_id & 0xFFFF) == VMWARE_VENDOR_ID && 41 | (vendor_device_id >> 16) == VMWARE_DEVICE_ID) { 42 | dprintln("VMWARE SVGA FOUND"); 43 | return 1; // Device found 44 | } 45 | } 46 | } 47 | } 48 | dprintln("VMWARE SVGA NOT FOUND"); 49 | return 0; // Device not found 50 | 51 | } 52 | 53 | u32 get_svga_base_port(uint16_t bus, uint16_t device, uint16_t function) { 54 | u32 bar0 = read_pci(bus, device, function, 0x10); // BAR0 55 | return (bar0 & ~0x3) - 1; 56 | } 57 | 58 | void fifo_write_cmd(u32 base_port, u32 cmd, u32* operands, u32 num_operands) { 59 | write_fifo(base_port, cmd); 60 | for (u32 i = 0; i < num_operands; ++i) { 61 | write_fifo(base_port, operands[i]); 62 | } 63 | } 64 | 65 | void init_fifo(u32 base_port, u32 fifo_start, u32 fifo_size) { 66 | // Set FIFO minimum command offset (start of the command queue) 67 | write_register(base_port, SVGA_FIFO_MIN, 293 * 4); // 293 32-bit registers 68 | 69 | // Set FIFO maximum command offset (end of the queue) 70 | write_register(base_port, SVGA_FIFO_MAX, fifo_size); 71 | 72 | // Set the next command offset (initially the start of the command queue) 73 | write_register(base_port, SVGA_FIFO_NEXT_CMD, 293 * 4); 74 | 75 | // Set the stop command offset to the end of the FIFO size 76 | write_register(base_port, SVGA_FIFO_STOP, fifo_size); 77 | 78 | // Mark the FIFO as fully configured by writing 1 to SVGA_REG_CONFIG_DONE 79 | write_register(base_port, SVGA_REG_CONFIG_DONE, 1); 80 | } 81 | 82 | void set_display_mode(u32 base_port, u32 width, u32 height, u32 bpp) { 83 | // Set the desired screen width, height, and bits per pixel 84 | write_register(base_port, SVGA_REG_WIDTH, width); 85 | write_register(base_port, SVGA_REG_HEIGHT, height); 86 | write_register(base_port, SVGA_REG_BPP, bpp); 87 | 88 | // Enable SVGA mode to apply changes 89 | write_register(base_port, SVGA_REG_ENABLE, 1); 90 | } 91 | 92 | void fifo_cmd_update(u32 base_port, u32 fifo_start, u32 start_x, u32 start_y, u32 width, u32 height) { 93 | // Write the update command ID to FIFO 94 | *((volatile u32 *)(fifo_start + read_register(base_port, SVGA_FIFO_NEXT_CMD))) = SVGA_CMD_UPDATE; 95 | increment_fifo_next_cmd(base_port); 96 | 97 | // Write the parameters for the update 98 | *((volatile u32 *)(fifo_start + read_register(base_port, SVGA_FIFO_NEXT_CMD))) = start_x; 99 | increment_fifo_next_cmd(base_port); 100 | *((volatile u32 *)(fifo_start + read_register(base_port, SVGA_FIFO_NEXT_CMD))) = start_y; 101 | increment_fifo_next_cmd(base_port); 102 | *((volatile u32 *)(fifo_start + read_register(base_port, SVGA_FIFO_NEXT_CMD))) = width; 103 | increment_fifo_next_cmd(base_port); 104 | *((volatile u32 *)(fifo_start + read_register(base_port, SVGA_FIFO_NEXT_CMD))) = height; 105 | increment_fifo_next_cmd(base_port); 106 | 107 | // Trigger the FIFO to process the commands by setting the SYNC register 108 | write_register(base_port, SVGA_REG_SYNC, 1); 109 | 110 | // Wait until the SVGA device completes processing the commands 111 | while (read_register(base_port, SVGA_REG_BUSY)) { 112 | // Poll until not busy 113 | } 114 | } 115 | 116 | void increment_fifo_next_cmd(u32 base_port) { 117 | // Increment the SVGA_FIFO_NEXT_CMD by 4 bytes (size of each entry) 118 | u32 next_cmd = read_register(base_port, SVGA_FIFO_NEXT_CMD); 119 | write_register(base_port, SVGA_FIFO_NEXT_CMD, next_cmd + 4); 120 | } 121 | 122 | 123 | void init_vmware_svga(u32 base_port) { 124 | // Set the specification ID 125 | outportl(base_port + SVGA_INDEX_PORT_OFFSET, 0); 126 | outportl(base_port + SVGA_VALUE_PORT_OFFSET, 0x90000002); 127 | 128 | // Verify if device is compatible 129 | u32 id = inportl(base_port + SVGA_VALUE_PORT_OFFSET); 130 | if (id != 0x90000002) { 131 | dprintln("DEVICE NOT SUPPORTED!!!"); 132 | return; // Device not supported 133 | } 134 | 135 | // Read frame buffer address and FIFO settings 136 | u32 fb_start = read_register(base_port, SVGA_REG_FB_START); 137 | u32 fifo_start = read_register(base_port, SVGA_REG_FIFO_START); 138 | u32 fifo_size = read_register(base_port, SVGA_REG_FIFO_SIZE); 139 | 140 | // Initialize FIFO settings 141 | init_fifo(base_port, fifo_start, fifo_size); 142 | 143 | // Enable the SVGA mode 144 | write_register(base_port, SVGA_REG_ENABLE, 1); 145 | // -- This wont work, it will be "initialized" but it wants the FIFO memory to be identity mapped and we dont have paging -- 146 | } 147 | -------------------------------------------------------------------------------- /src/drivers/GPU/vmsvga/vmsvga.h: -------------------------------------------------------------------------------- 1 | /* 2 | VMWARE SVGA II DRIVER HEADER 3 | (everything is in here btw) 4 | */ 5 | #pragma once 6 | #include "../../types.h" 7 | #define VMWARE_VENDOR_ID 0x15AD 8 | #define VMWARE_DEVICE_ID 0x0405 9 | 10 | 11 | #define SVGA_INDEX_PORT_OFFSET 0 12 | #define SVGA_VALUE_PORT_OFFSET 1 13 | #define SVGA_PORT_BASE (bar0 - 1) 14 | 15 | // Port offsets from the base I/O port 16 | #define SVGA_INDEX_PORT_OFFSET 0 // SVGA_INDEX register offset 17 | #define SVGA_VALUE_PORT_OFFSET 1 // SVGA_VALUE register offset 18 | #define SVGA_BIOS_PORT_OFFSET 2 // SVGA_BIOS register offset 19 | #define SVGA_IRQSTATUS_PORT_OFFSET 8 // SVGA_IRQSTATUS register offset 20 | 21 | // Register indices within the SVGA device 22 | #define SVGA_REG_ID 0 // Negotiation specification ID 23 | #define SVGA_REG_ENABLE 1 // Enable SVGA mode 24 | #define SVGA_REG_WIDTH 2 // Current screen width 25 | #define SVGA_REG_HEIGHT 3 // Current screen height 26 | #define SVGA_REG_MAX_WIDTH 4 // Max supported screen width 27 | #define SVGA_REG_MAX_HEIGHT 5 // Max supported screen height 28 | #define SVGA_REG_BPP 7 // Screen bits per pixel 29 | #define SVGA_REG_FB_START 13 // Frame buffer start address 30 | #define SVGA_REG_FB_OFFSET 14 // Frame buffer offset to visible pixels 31 | #define SVGA_REG_VRAM_SIZE 15 // Video RAM size 32 | #define SVGA_REG_FB_SIZE 16 // Frame buffer size 33 | #define SVGA_REG_CAPABILITIES 17 // Device capabilities 34 | #define SVGA_REG_FIFO_START 18 // FIFO start address 35 | #define SVGA_REG_FIFO_SIZE 19 // FIFO size 36 | #define SVGA_REG_CONFIG_DONE 20 // FIFO operation enable flag 37 | #define SVGA_REG_SYNC 21 // Flush FIFO changes 38 | #define SVGA_REG_BUSY 22 // FIFO processing flag 39 | 40 | // FIFO register indices 41 | #define SVGA_FIFO_MIN 0 // Start of the command queue 42 | #define SVGA_FIFO_MAX 1 // End of the command queue 43 | #define SVGA_FIFO_NEXT_CMD 2 // Next command offset 44 | #define SVGA_FIFO_STOP 3 // Stop command 45 | 46 | // Commands 47 | #define SVGA_CMD_UPDATE 1 // Screen update command 48 | #define SVGA_CMD_RECT_COPY 3 // Rectangle copy command 49 | #define SVGA_CMD_DEFINE_CURSOR 19 // Define cursor command 50 | #define SVGA_CMD_DEFINE_ALPHA_CURSOR 22 // Define alpha cursor 51 | 52 | 53 | void init_vmware_svga(u32 base_port); 54 | void init_fifo(u32 base_port, u32 fifo_start, u32 fifo_size); 55 | u32 get_svga_base_port(u16 bus, u16 device, u16 function); 56 | int detect_vmware_svga(); 57 | u32 read_register(u32 base_port, u32 reg); 58 | void write_register(u32 base_port, u32 reg, u32 value); 59 | void fifo_write_cmd(u32 base_port, u32 cmd, u32* operands, u32 num_operands); 60 | void write_fifo(u32 base_port, u32 value); 61 | void set_display_mode(u32 base_port, u32 width, u32 height, u32 bpp); 62 | void increment_fifo_next_cmd(u32 base_port); 63 | void fifo_cmd_update(u32 base_port, u32 fifo_start, u32 start_x, u32 start_y, u32 width, u32 height); 64 | -------------------------------------------------------------------------------- /src/drivers/critical.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* Enter critical section, disables interrupts */ 4 | #define ENTER_CRITICAL() u32 flags_ ## __func__; asm volatile("pushf; cli; pop %0" : "=r"(flags_ ## __func__) :: "memory", "cc") 5 | 6 | /* Leave critical section, re-enables interrupts if they were on when entering */ 7 | #define LEAVE_CRITICAL() asm volatile("push %0; popf" :: "rm"(flags_ ## __func__) : "memory", "cc") -------------------------------------------------------------------------------- /src/drivers/debug.c: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | #include "ports.h" 3 | 4 | void dprintchar(char c) 5 | { 6 | port_byte_out(0x3F8, c); 7 | } 8 | 9 | void dprint(const char* message) 10 | { 11 | for (int i = 0; message[i]; i++) { 12 | dprintchar(message[i]); 13 | } 14 | } 15 | 16 | void dprintln(const char* message) 17 | { 18 | dprint(message); 19 | dprint("\r\n"); 20 | } 21 | 22 | void dprintbyte(u8 byte) { 23 | dprintchar(((byte >> 4) < 10) ? (byte >> 4) + '0' : (byte >> 4) - 10 + 'a'); 24 | dprintchar(((byte & 0x0F) < 10) ? (byte & 0x0F) + '0' : (byte & 0x0F) - 10 + 'a'); 25 | } 26 | 27 | void dprintint(s64 value) { 28 | if (value < 0) { 29 | dprint("-"); 30 | value = -value; 31 | } 32 | 33 | if (value == 0) { 34 | dprint("0"); 35 | return; 36 | } 37 | 38 | char buffer[21]; 39 | int len = 0; 40 | while (value > 0) { 41 | buffer[len++] = (value % 10) + '0'; 42 | value /= 10; 43 | } 44 | 45 | for (int i = len - 1; i >= 0; i--) { 46 | dprintchar(buffer[i]); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/drivers/debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | void dprintchar(char c); 6 | void dprint(const char* message); 7 | void dprintln(const char* message); 8 | void dprintbyte(u8); 9 | void dprintint(s64); 10 | -------------------------------------------------------------------------------- /src/drivers/egs.c: -------------------------------------------------------------------------------- 1 | /* Choacury Extended Graphics Support (E.G.S) */ 2 | 3 | // TODO: Add code here for better graphical stuff (beyond the 16 DOS colours) 4 | -------------------------------------------------------------------------------- /src/drivers/files/sfx/Startup.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/src/drivers/files/sfx/Startup.wav -------------------------------------------------------------------------------- /src/drivers/filesystem/fat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../storage/device.h" 4 | 5 | typedef enum FAT_type { 6 | FAT12, 7 | FAT16, 8 | FAT32 9 | } FAT_type_t; 10 | 11 | typedef struct FAT_file { 12 | struct FAT_filesystem* filesystem; 13 | uint32_t first_cluster; 14 | uint32_t file_size; 15 | bool is_directory; 16 | } FAT_file_t; 17 | 18 | typedef struct FAT_filesystem { 19 | storage_device_t* storage_device; 20 | 21 | FAT_type_t fat_type; 22 | 23 | // Only used in FAT12 and FAT16 24 | struct { 25 | uint32_t root_sector; 26 | uint32_t root_entry_count; 27 | } fat16; 28 | 29 | uint32_t bytes_per_sector; 30 | uint32_t sectors_per_cluster; 31 | 32 | uint32_t first_fat_sector; 33 | uint32_t first_data_sector; 34 | 35 | uint32_t cluster_count; 36 | 37 | uint8_t* sector_buffer; 38 | uint32_t sector_buffer_sector; 39 | 40 | FAT_file_t root_file; 41 | } FAT_filesystem_t; 42 | 43 | // Try to initialize FAT filesystem from storage device 44 | // on success: 45 | // return pointer to FAT filesystem 46 | // on error: 47 | // return NULL 48 | FAT_filesystem_t* FAT_Init(storage_device_t*); 49 | 50 | // Open file with absolute path from a FAT filesystem 51 | // Path separator '/'s is used while parsing 52 | // on success 53 | // return a pointer to FAT file 54 | // file not found: 55 | // return NULL 56 | // on error: 57 | // return NULL 58 | FAT_file_t* FAT_OpenAbsolute(FAT_filesystem_t*, const char* path); 59 | 60 | // Look for a file with name from parent file 61 | // Open files MUST be closed with FAT_Close 62 | // on success 63 | // return a pointer to FAT file 64 | // file not found: 65 | // return NULL 66 | // on error: 67 | // return NULL 68 | FAT_file_t* FAT_Open(FAT_file_t* parent, const char* name); 69 | 70 | // Close a FAT file 71 | void FAT_Close(FAT_file_t* file); 72 | 73 | // Read bytes from a FAT file from given offset 74 | // on success 75 | // return the number of bytes read 76 | // on end of file 77 | // return 0 78 | // on error: 79 | // return 0 80 | size_t FAT_Read(FAT_file_t* file, size_t offset, void* buffer, size_t buffer_len); 81 | 82 | // List all files from parent into the output names 83 | // Output names is pointer to list of char pointers 84 | // All entries in *names_output and *names_output itself MUST be deleted with kfree 85 | // always returns the number of entries in *names_output 86 | size_t FAT_ListFiles(FAT_file_t* parent, char*** names_output); 87 | 88 | // Check if the file is a directory 89 | bool FAT_IsDirectory(FAT_file_t* file); 90 | 91 | //static uint32_t allocate_new_cluster(FAT_filesystem_t* filesystem, uint32_t previous_cluster); 92 | //static void update_file_size_in_dir_entry(FAT_file_t* file); 93 | size_t FAT_Write(FAT_file_t* file, size_t offset, const void* src_buffer, size_t buffer_len); 94 | 95 | 96 | bool FAT_CreateDirectory(FAT_file_t* parent, const char* name); 97 | 98 | -------------------------------------------------------------------------------- /src/drivers/filesystem/filesystem.c: -------------------------------------------------------------------------------- 1 | /* FILE SYSTEM FOR CHOACURY! */ 2 | /* 3 | * Under construction! 4 | */ -------------------------------------------------------------------------------- /src/drivers/filesystem/virtualfs.c: -------------------------------------------------------------------------------- 1 | /* Virtual File System Driver */ 2 | 3 | #include "virtualfs.h" 4 | 5 | // TODO: Expand this :/ -------------------------------------------------------------------------------- /src/drivers/filesystem/virtualfs.h: -------------------------------------------------------------------------------- 1 | // We need something here... -------------------------------------------------------------------------------- /src/drivers/gdt.c: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include "types.h" 3 | 4 | typedef struct { 5 | u16 size; 6 | void* address; 7 | } __attribute__((packed)) GDTR; 8 | 9 | typedef struct { 10 | u16 limit0; 11 | u16 base0; 12 | u8 base1; 13 | u8 access; 14 | u8 limit1 : 4; 15 | u8 flags : 4; 16 | u8 base2; 17 | } __attribute__((packed)) segment_descriptor_t; 18 | 19 | static GDTR s_gdtr; 20 | static segment_descriptor_t s_gdt[5]; 21 | 22 | static void gdt_write_entry(u8 index, u32 base, u32 limit, u8 access, u8 flags) { 23 | s_gdt[index].base0 = (base >> 0) & 0xFFFF; 24 | s_gdt[index].base1 = (base >> 16) & 0xFF; 25 | s_gdt[index].base2 = (base >> 24) & 0xFF; 26 | 27 | s_gdt[index].limit0 = (limit >> 0) & 0xFFFF; 28 | s_gdt[index].limit1 = (limit >> 16) & 0x0F; 29 | 30 | s_gdt[index].access = access; 31 | 32 | s_gdt[index].flags = flags & 0x0F; 33 | } 34 | 35 | static void gdt_flush() { 36 | asm volatile("lgdt %0" :: "m"(s_gdtr)); 37 | } 38 | 39 | void gdt_init() { 40 | s_gdtr.address = s_gdt; 41 | s_gdtr.size = sizeof(s_gdt) - 1; 42 | 43 | gdt_write_entry(0, 0, 0x00000, 0x00, 0x0); // null descriptor 44 | gdt_write_entry(1, 0, 0xFFFFF, 0x9A, 0xC); // kernel code 45 | gdt_write_entry(2, 0, 0xFFFFF, 0x92, 0xC); // kernel data 46 | gdt_write_entry(3, 0, 0xFFFFF, 0xFA, 0xC); // user code 47 | gdt_write_entry(4, 0, 0xFFFFF, 0xF2, 0xC); // user data 48 | 49 | gdt_flush(); 50 | } 51 | -------------------------------------------------------------------------------- /src/drivers/gdt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define KERNEL_CS 0x08 4 | #define KERNEL_DS 0x10 5 | #define USER_CS 0x18 6 | #define USER_DS 0x20 7 | 8 | void gdt_init(); 9 | -------------------------------------------------------------------------------- /src/drivers/idt.c: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include "idt.h" 3 | #include "pic.h" 4 | #include "utils.h" 5 | #include "vga.h" 6 | #include "../kernel/panic.h" 7 | #include "../shell/terminal.h" 8 | 9 | /* Macros for interrupt code gen */ 10 | #define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) 11 | #define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) 12 | 13 | /* How every interrupt gate (handler) is defined */ 14 | typedef struct { 15 | u16 low_offset; // <-- Lower 16 bits of handler function address 16 | u16 sel; // <-- Kernel segment selector 17 | u8 always0; 18 | /* First byte 19 | * Bit 7: "Interrupt is present" 20 | * Bits 6-5: Privilege level of caller (0=kernel -> 3=user) 21 | * Bit 4: Set to 0 for interrupt gates 22 | * Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */ 23 | u8 flags; 24 | u16 high_offset; // <-- Higher 16 bits of handler function address 25 | } __attribute__((packed)) idt_gate_t ; 26 | 27 | /* A pointer to the array of interrupt handlers. 28 | * Assembly instruction 'lidt' will read it */ 29 | typedef struct { 30 | u16 limit; 31 | void* base; 32 | } __attribute__((packed)) idt_register_t; 33 | 34 | #define IDT_ENTRIES 256 35 | static idt_gate_t idt[IDT_ENTRIES]; 36 | static idt_register_t idt_reg; 37 | 38 | static irq_handler_t irq_handlers[32]; 39 | 40 | static const char* isr_names[] = { 41 | "Division Error", 42 | "Debug", 43 | "Non-maskable Interrupt", 44 | "Breakpoint ", 45 | "Overflow", 46 | "Bound Range Exceeded", 47 | "Invalid Opcode", 48 | "Device Not Available", 49 | "Double Fault", 50 | "Coprocessor Segment Overrun", 51 | "Invalid TSS", 52 | "Segment Not Present", 53 | "Stack-Segment Fault", 54 | "General Protection Fault", 55 | "Page Fault", 56 | "Reserved", 57 | "x87 Floating-Point Exception", 58 | "Alignment Check", 59 | "Machine Check", 60 | "SIMD Floating-Point Exception", 61 | "Virtualization Exception", 62 | "Control Protection Exception", 63 | "Reserved 22", 64 | "Reserved 23", 65 | "Reserved 24", 66 | "Reserved 25", 67 | "Reserved 26", 68 | "Reserved 27", 69 | "Hypervisor Injection Exception", 70 | "VMM Communication Exception", 71 | "Security Exception", 72 | "Reserved 31" 73 | }; 74 | 75 | void c_isr_handler(u8 isr, u32 error) { 76 | (void)error; 77 | 78 | if (isr >= 32) { 79 | // Kernel defined interrupts, should not be called. 80 | panic("isr handler called with isr >= 32"); 81 | } 82 | 83 | panic(isr_names[isr]); 84 | } 85 | 86 | void c_irq_handler(u8 irq) { 87 | /* Spurious interrupt */ 88 | if (!pic_is_in_service(irq)) { 89 | return; 90 | } 91 | 92 | irq_handler_t handler = irq_handlers[irq]; 93 | if (handler == 0) { 94 | term_write("no handler for irq", TC_YELLO); 95 | } else { 96 | handler(); 97 | } 98 | 99 | pic_send_eoi(irq); 100 | } 101 | 102 | static void set_idt_gate(int n, void (*handler)()) { 103 | idt[n].low_offset = ((uptr)handler >> 0) & 0xFFFF; 104 | idt[n].sel = KERNEL_CS; 105 | idt[n].always0 = 0; 106 | idt[n].flags = 0x8E; 107 | idt[n].high_offset = ((uptr)handler >> 16) & 0xFFFF; 108 | } 109 | 110 | void idt_register_irq_handler(int irq, void (*handler)()) { 111 | irq_handlers[irq] = handler; 112 | } 113 | 114 | static void idt_flush() { 115 | asm volatile("lidt %0" :: "m"(idt_reg)); 116 | } 117 | 118 | /* Code gen extern definitions for isr handler (defined in interrupt.asm) */ 119 | #define X(num) extern void isr ## num(); 120 | ISR_LIST_X 121 | #undef X 122 | 123 | /* Code gen extern definitions for irq handler (defined in interrupt.asm) */ 124 | #define X(num) extern void irq ## num(); 125 | IRQ_LIST_X 126 | #undef X 127 | 128 | void idt_init() { 129 | memset(idt, 0, sizeof(idt)); 130 | memset(irq_handlers, 0, sizeof(irq_handlers)); 131 | 132 | idt_reg.base = idt; 133 | idt_reg.limit = sizeof(idt) - 1; 134 | 135 | /* Code gen isr handler registration */ 136 | #define X(num) set_idt_gate(num, isr ## num); 137 | ISR_LIST_X 138 | #undef X 139 | 140 | /* Code gen irq handler registration */ 141 | #define X(num) set_idt_gate(num + IRQ_BASE, irq ## num); 142 | ISR_LIST_X 143 | #undef X 144 | 145 | idt_flush(); 146 | } 147 | -------------------------------------------------------------------------------- /src/drivers/idt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IRQ_BASE 32 4 | 5 | typedef void(*irq_handler_t)(); 6 | 7 | void idt_register_irq_handler(int irq, irq_handler_t handler); 8 | void idt_init(); 9 | -------------------------------------------------------------------------------- /src/drivers/interrupt.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | section .text 3 | 4 | extern c_isr_handler 5 | extern c_irq_handler 6 | 7 | isr_stub: 8 | ; Save all registers 9 | pushad 10 | 11 | ; Push C arguments to stack 12 | mov eax, [esp + 8*4] ; <- ISR number 13 | mov ebx, [esp + 9*4] ; <- Error code 14 | push ebx 15 | push eax 16 | 17 | ; Calls the C ISR Handler, I mean its pretty obvious by that name 18 | call c_isr_handler 19 | 20 | ; skip pushed arguments from stack and restore registers 21 | add esp, 8 22 | popad 23 | add esp, 8 24 | 25 | iret 26 | 27 | irq_stub: 28 | ; Save all registers 29 | pushad 30 | 31 | ; Push IRQ number (a.k.a. A C argument) to stack 32 | mov eax, [esp + 8*4] 33 | push eax 34 | 35 | ; Calls the C IRQ Handler 36 | call c_irq_handler 37 | 38 | ; skip pushed argument from stack and restore registers 39 | add esp, 4 40 | popad 41 | add esp, 8 42 | 43 | iret 44 | 45 | %macro isr_gen 1 46 | global isr %+ %1 47 | isr %+ %1: 48 | push 0x69 49 | push %1 50 | jmp isr_stub 51 | %endmacro 52 | 53 | %macro isr_err_gen 1 54 | global isr %+ %1 55 | isr %+ %1: 56 | push %1 57 | jmp isr_stub 58 | %endmacro 59 | 60 | %macro irq_gen 1 61 | global irq %+ %1 62 | irq %+ %1: 63 | push 0 64 | push %1 65 | jmp irq_stub 66 | %endmacro 67 | 68 | isr_gen 0 69 | isr_gen 1 70 | isr_gen 2 71 | isr_gen 3 72 | isr_gen 4 73 | isr_gen 5 74 | isr_gen 6 75 | isr_gen 7 76 | isr_err_gen 8 77 | isr_gen 9 78 | isr_err_gen 10 79 | isr_err_gen 11 80 | isr_err_gen 12 81 | isr_err_gen 13 82 | isr_err_gen 14 83 | isr_gen 15 84 | isr_gen 16 85 | isr_err_gen 17 86 | isr_gen 18 87 | isr_gen 19 88 | isr_gen 20 89 | isr_err_gen 21 90 | isr_gen 22 91 | isr_gen 23 92 | isr_gen 24 93 | isr_gen 25 94 | isr_gen 26 95 | isr_gen 27 96 | isr_gen 28 97 | isr_err_gen 29 98 | isr_err_gen 30 99 | isr_gen 31 100 | 101 | irq_gen 0 102 | irq_gen 1 103 | irq_gen 2 104 | irq_gen 3 105 | irq_gen 4 106 | irq_gen 5 107 | irq_gen 6 108 | irq_gen 7 109 | irq_gen 8 110 | irq_gen 9 111 | irq_gen 10 112 | irq_gen 11 113 | irq_gen 12 114 | irq_gen 13 115 | irq_gen 14 116 | irq_gen 15 117 | irq_gen 16 118 | irq_gen 17 119 | irq_gen 18 120 | irq_gen 19 121 | irq_gen 20 122 | irq_gen 21 123 | irq_gen 22 124 | irq_gen 23 125 | irq_gen 24 126 | irq_gen 25 127 | irq_gen 26 128 | irq_gen 27 129 | irq_gen 28 130 | irq_gen 29 131 | irq_gen 30 132 | irq_gen 31 133 | -------------------------------------------------------------------------------- /src/drivers/key.c: -------------------------------------------------------------------------------- 1 | #include "key.h" 2 | 3 | #include 4 | 5 | /* This is mapping for key => ascii, key is already parsed at this point. */ 6 | static const char* s_key_to_utf8_lower[] = { 7 | NULL, 8 | "0", 9 | "1", 10 | "2", 11 | "3", 12 | "4", 13 | "5", 14 | "6", 15 | "7", 16 | "8", 17 | "9", 18 | "å", 19 | "ä", 20 | "a", 21 | "´", 22 | NULL, 23 | NULL, 24 | "&", 25 | NULL, 26 | NULL, 27 | NULL, 28 | NULL, 29 | "*", 30 | "@", 31 | "b", 32 | "\\", 33 | NULL, 34 | "`", 35 | "c", 36 | NULL, 37 | NULL, 38 | "^", 39 | "}", 40 | ")", 41 | "]", 42 | ":", 43 | ",", 44 | "¤", 45 | "d", 46 | NULL, 47 | "$", 48 | "\"", 49 | "e", 50 | NULL, 51 | NULL, 52 | "=", 53 | NULL, 54 | "!", 55 | "f", 56 | NULL, 57 | NULL, 58 | NULL, 59 | NULL, 60 | NULL, 61 | NULL, 62 | NULL, 63 | NULL, 64 | NULL, 65 | NULL, 66 | NULL, 67 | "g", 68 | ">", 69 | "h", 70 | "½", 71 | "#", 72 | NULL, 73 | "-", 74 | "i", 75 | NULL, 76 | "j", 77 | "k", 78 | "l", 79 | NULL, 80 | NULL, 81 | "<", 82 | "m", 83 | NULL, 84 | NULL, 85 | NULL, 86 | NULL, 87 | "n", 88 | NULL, 89 | "0", 90 | "1", 91 | "2", 92 | "3", 93 | "4", 94 | "5", 95 | "6", 96 | "7", 97 | "8", 98 | "9", 99 | ",", 100 | "/", 101 | NULL, 102 | "-", 103 | "*", 104 | "+", 105 | "ö", 106 | "o", 107 | "{", 108 | "(", 109 | "[", 110 | "p", 111 | NULL, 112 | NULL, 113 | "%", 114 | ".", 115 | "|", 116 | "+", 117 | "q", 118 | "?", 119 | "r", 120 | NULL, 121 | NULL, 122 | "s", 123 | "§", 124 | ";", 125 | "'", 126 | "/", 127 | " ", 128 | NULL, 129 | "t", 130 | "\t", 131 | "~", 132 | "¨", 133 | "u", 134 | "_", 135 | "v", 136 | NULL, 137 | NULL, 138 | NULL, 139 | "w", 140 | "x", 141 | "y", 142 | "z", 143 | }; 144 | 145 | static const char* s_key_to_utf8_upper[] = { 146 | NULL, 147 | "0", 148 | "1", 149 | "2", 150 | "3", 151 | "4", 152 | "5", 153 | "6", 154 | "7", 155 | "8", 156 | "9", 157 | "Å", 158 | "Ä", 159 | "A", 160 | "´", 161 | NULL, 162 | NULL, 163 | "&", 164 | NULL, 165 | NULL, 166 | NULL, 167 | NULL, 168 | "*", 169 | "@", 170 | "B", 171 | "\\", 172 | NULL, 173 | "`", 174 | "C", 175 | NULL, 176 | NULL, 177 | "^", 178 | "}", 179 | ")", 180 | "]", 181 | ":", 182 | ",", 183 | "¤", 184 | "D", 185 | NULL, 186 | "$", 187 | "\"", 188 | "E", 189 | NULL, 190 | NULL, 191 | "=", 192 | NULL, 193 | "!", 194 | "F", 195 | NULL, 196 | NULL, 197 | NULL, 198 | NULL, 199 | NULL, 200 | NULL, 201 | NULL, 202 | NULL, 203 | NULL, 204 | NULL, 205 | NULL, 206 | "G", 207 | ">", 208 | "H", 209 | "½", 210 | "#", 211 | NULL, 212 | "-", 213 | "I", 214 | NULL, 215 | "J", 216 | "K", 217 | "L", 218 | NULL, 219 | NULL, 220 | "<", 221 | "M", 222 | NULL, 223 | NULL, 224 | NULL, 225 | NULL, 226 | "N", 227 | NULL, 228 | "0", 229 | "1", 230 | "2", 231 | "3", 232 | "4", 233 | "5", 234 | "6", 235 | "7", 236 | "8", 237 | "9", 238 | ",", 239 | "/", 240 | NULL, 241 | "-", 242 | "*", 243 | "+", 244 | "Ö", 245 | "O", 246 | "{", 247 | "(", 248 | "[", 249 | "P", 250 | NULL, 251 | NULL, 252 | "%", 253 | ".", 254 | "|", 255 | "+", 256 | "Q", 257 | "?", 258 | "R", 259 | NULL, 260 | NULL, 261 | "S", 262 | "§", 263 | ";", 264 | "'", 265 | "/", 266 | " ", 267 | NULL, 268 | "T", 269 | "\t", 270 | "~", 271 | "¨", 272 | "U", 273 | "_", 274 | "V", 275 | NULL, 276 | NULL, 277 | NULL, 278 | "W", 279 | "X", 280 | "Y", 281 | "Z", 282 | }; 283 | 284 | const char* key_to_utf8(key_event_t* event) { 285 | int shift = !!(event->modifiers & KEY_EVENT_MODIFIERS_SHIFT); 286 | int caps = !!(event->modifiers & KEY_EVENT_MODIFIERS_CAPS_LOCK); 287 | return (shift ^ caps) ? s_key_to_utf8_upper[event->key] : s_key_to_utf8_lower[event->key]; 288 | } 289 | -------------------------------------------------------------------------------- /src/drivers/key.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | typedef enum { 6 | KEY_NONE = 0, 7 | KEY_0, 8 | KEY_1, 9 | KEY_2, 10 | KEY_3, 11 | KEY_4, 12 | KEY_5, 13 | KEY_6, 14 | KEY_7, 15 | KEY_8, 16 | KEY_9, 17 | KEY_A_Ring, 18 | KEY_A_Umlaut, 19 | KEY_A, 20 | KEY_Acute, 21 | KEY_Alt, 22 | KEY_AltGr, 23 | KEY_Ampersand, 24 | KEY_ArrowDown, 25 | KEY_ArrowLeft, 26 | KEY_ArrowRight, 27 | KEY_ArrowUp, 28 | KEY_Asterix, 29 | KEY_AtSign, 30 | KEY_B, 31 | KEY_Backslash, 32 | KEY_Backspace, 33 | KEY_BackTick, 34 | KEY_C, 35 | KEY_Calculator, 36 | KEY_CapsLock, 37 | KEY_Caret, 38 | KEY_CloseCurlyBracket, 39 | KEY_CloseParenthesis, 40 | KEY_CloseSquareBracket, 41 | KEY_Colon, 42 | KEY_Comma, 43 | KEY_Currency, 44 | KEY_D, 45 | KEY_Delete, 46 | KEY_Dollar, 47 | KEY_DoubleQuote, 48 | KEY_E, 49 | KEY_End, 50 | KEY_Enter, 51 | KEY_Equals, 52 | KEY_Escape, 53 | KEY_ExclamationMark, 54 | KEY_F, 55 | KEY_F1, 56 | KEY_F2, 57 | KEY_F3, 58 | KEY_F4, 59 | KEY_F5, 60 | KEY_F6, 61 | KEY_F7, 62 | KEY_F8, 63 | KEY_F9, 64 | KEY_F10, 65 | KEY_F11, 66 | KEY_G, 67 | KEY_GreaterThan, 68 | KEY_H, 69 | KEY_Half, 70 | KEY_Hashtag, 71 | KEY_Home, 72 | KEY_Hyphen, 73 | KEY_I, 74 | KEY_Insert, 75 | KEY_J, 76 | KEY_K, 77 | KEY_L, 78 | KEY_LeftCtrl, 79 | KEY_LeftShift, 80 | KEY_LessThan, 81 | KEY_M, 82 | KEY_MediaNext, 83 | KEY_MediaPlayPause, 84 | KEY_MediaPrevious, 85 | KEY_MediaStop, 86 | KEY_N, 87 | KEY_NumLock, 88 | KEY_Numpad0, 89 | KEY_Numpad1, 90 | KEY_Numpad2, 91 | KEY_Numpad3, 92 | KEY_Numpad4, 93 | KEY_Numpad5, 94 | KEY_Numpad6, 95 | KEY_Numpad7, 96 | KEY_Numpad8, 97 | KEY_Numpad9, 98 | KEY_NumpadDecimal, 99 | KEY_NumpadDivide, 100 | KEY_NumpadEnter, 101 | KEY_NumpadMinus, 102 | KEY_NumpadMultiply, 103 | KEY_NumpadPlus, 104 | KEY_O_Umlaut, 105 | KEY_O, 106 | KEY_OpenCurlyBracket, 107 | KEY_OpenParenthesis, 108 | KEY_OpenSquareBracket, 109 | KEY_P, 110 | KEY_PageDown, 111 | KEY_PageUp, 112 | KEY_Percent, 113 | KEY_Period, 114 | KEY_Pipe, 115 | KEY_Plus, 116 | KEY_Q, 117 | KEY_QuestionMark, 118 | KEY_R, 119 | KEY_RightCtrl, 120 | KEY_RightShift, 121 | KEY_S, 122 | KEY_Section, 123 | KEY_Semicolon, 124 | KEY_SingleQuote, 125 | KEY_Slash, 126 | KEY_Space, 127 | KEY_Super, 128 | KEY_T, 129 | KEY_Tab, 130 | KEY_Tilde, 131 | KEY_TwoDots, 132 | KEY_U, 133 | KEY_Underscore, 134 | KEY_V, 135 | KEY_VolumeDown, 136 | KEY_VolumeMute, 137 | KEY_VolumeUp, 138 | KEY_W, 139 | KEY_X, 140 | KEY_Y, 141 | KEY_Z, 142 | } key_t; 143 | 144 | #define KEY_EVENT_MODIFIERS_SHIFT (1 << 0) 145 | #define KEY_EVENT_MODIFIERS_CONTROL (1 << 1) 146 | #define KEY_EVENT_MODIFIERS_CAPS_LOCK (1 << 2) 147 | #define KEY_EVENT_MODIFIERS_RELEASED (1 << 3) 148 | 149 | typedef struct { 150 | key_t key; 151 | u8 modifiers; 152 | } key_event_t; 153 | 154 | const char* key_to_utf8(key_event_t*); 155 | -------------------------------------------------------------------------------- /src/drivers/keymaps/ps2_keymap_fi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ps2_init_keymap_fi(); 4 | -------------------------------------------------------------------------------- /src/drivers/keymaps/ps2_keymap_gb.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ps2_init_keymap_gb(); 4 | -------------------------------------------------------------------------------- /src/drivers/keymaps/ps2_keymap_us.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ps2_init_keymap_us(); 4 | -------------------------------------------------------------------------------- /src/drivers/mouse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef enum { 6 | LEFT, 7 | RIGHT, 8 | MIDDLE, 9 | EXTRA1, 10 | EXTRA2, 11 | } mouse_button_t; 12 | 13 | typedef struct { 14 | bool pressed; 15 | mouse_button_t button; 16 | } mouse_button_event_t; 17 | 18 | typedef struct { 19 | int rel_x; 20 | int rel_y; 21 | } mouse_move_event_t; 22 | 23 | typedef struct { 24 | int value; 25 | } mouse_scroll_event_t; 26 | 27 | typedef enum { 28 | MOUSE_EVENT_NONE, 29 | MOUSE_BUTTON_EVENT, 30 | MOUSE_MOVE_EVENT, 31 | MOUSE_SCROLL_EVENT, 32 | } mouse_event_type_t; 33 | 34 | typedef struct { 35 | mouse_event_type_t type; 36 | union { 37 | mouse_button_event_t button_event; 38 | mouse_move_event_t move_event; 39 | mouse_scroll_event_t scroll_event; 40 | }; 41 | } mouse_event_t; 42 | -------------------------------------------------------------------------------- /src/drivers/pci.c: -------------------------------------------------------------------------------- 1 | #include "pci.h" 2 | #include "types.h" 3 | #include "ports.h" 4 | #include "debug.h" 5 | 6 | u32 read_pci(u16 bus, u16 device, u16 function, u32 regoffset) { 7 | //create ID to identify an exact function and register offset we want to start reading from (the PCI has 8 buses, 32 devices each, where each device has up to 8 functions) 8 | //creating it is easy, you pretty much put the plain values there in order, so they're all shifted and ORed with each other 9 | u32 id = 0x1 << 31 | ((bus & 0xFF) << 16) | ((device & 0x1F) << 11) | ((function & 0x07) << 8) | (regoffset & 0xFC); 10 | port_dword_out(0xCF8, id); //give ID to PCI's command port 11 | u32 result = port_dword_in(0xCFC); //read the result from PCI's data port 12 | return result >> ((regoffset % 4) << 3); //the real result beginning from a register offset has to be shifted 13 | } 14 | 15 | void write_pci(u16 bus, u16 device, u16 function, u32 regoffset, u32 data) { 16 | u32 id = 0x1 << 31 | ((bus & 0xFF) << 16) | ((device & 0x1F) << 11) | ((function & 0x07) << 8) | (regoffset & 0xFC); //we construct an ID like in the read function 17 | port_dword_out(0xCF8, id); //we give the ID to PCI's command port 18 | port_dword_out(0xCFC, data); //we give the data we want to send to PCI's data port 19 | } 20 | 21 | device_descriptor get_device_descriptor(u16 bus, u16 device, u16 function) { 22 | device_descriptor result; 23 | 24 | result.bus = bus; 25 | result.device = device; 26 | result.function = function; 27 | 28 | result.vendor_id = read_pci(bus, device, function, 0x00); 29 | result.device_id = read_pci(bus, device, function, 0x02); 30 | 31 | result.class_id = read_pci(bus, device, function, 0x0b); 32 | result.subclass_id = read_pci(bus, device, function, 0x0a); 33 | result.interface_id = read_pci(bus, device, function, 0x09); 34 | 35 | result.revision = read_pci(bus, device, function, 0x08); 36 | result.interrupt = read_pci(bus, device, function, 0x3c); 37 | 38 | return result; 39 | } 40 | 41 | void debug_print_pci() { 42 | for(int bus = 0; bus < 8; bus++) //8 buses 43 | { 44 | for(int device = 0; device < 32; device++) //32 possible devices 45 | { 46 | for(int function = 0; function < 8; function++) //8 possible functionss 47 | { 48 | device_descriptor desc = get_device_descriptor(bus, device, function); 49 | 50 | if(desc.vendor_id == 0x0000 || desc.vendor_id == 0xFFFF) //if the vendor ID is 0 or MAX then the function doesn't exist 51 | continue; 52 | 53 | dprint("PCI bus: "); 54 | dprintbyte((u8)(bus & 0xFF)); 55 | 56 | dprint(", Device: "); 57 | dprintbyte((u8)(device & 0xFF)); 58 | 59 | dprint(", Function: "); 60 | dprintbyte(((u8)((function & 0xFF)))); 61 | 62 | dprint(", Vendor ID: "); 63 | dprintbyte((u8)((desc.vendor_id & 0xFF00) >> 8)); 64 | dprintbyte((u8)(desc.vendor_id & 0xFF)); 65 | 66 | dprint(", Device ID: "); 67 | dprintbyte((u8)((desc.device_id & 0xFF00) >> 8)); 68 | dprintbyte((u8)(desc.device_id & 0xFF)); 69 | 70 | dprint("\r\n"); 71 | 72 | //an example for using the PCI information: detecting USB devices 73 | 74 | if((desc.class_id == 0x0C) && (desc.subclass_id == 0x03)) //standard class and subclass IDs for USB devices 75 | { 76 | dprintln("USB device found ^^"); 77 | } 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/drivers/pci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef PCI_H 4 | #define PCI_H 5 | 6 | #include "types.h" 7 | 8 | u32 read_pci(u16 bus, u16 device, u16 function, u32 regoffset); 9 | void write_pci(u16 bus, u16 device, u16 function, u32 regoffset, u32 data); 10 | void debug_print_pci(); 11 | 12 | typedef struct device_descriptor //to be updated eventually: there are more important values one might weant to read, like the BARs (base addresses of device buffers) 13 | { 14 | u32 portBase; 15 | u32 interrupt; 16 | 17 | u16 bus; 18 | u16 device; 19 | u16 function; 20 | 21 | u16 vendor_id; 22 | u16 device_id; 23 | 24 | u8 class_id; 25 | u8 subclass_id; 26 | u8 interface_id; 27 | 28 | u8 revision; 29 | } device_descriptor; 30 | 31 | device_descriptor get_device_descriptor(u16 bus, u16 device, u16 function); 32 | 33 | #endif -------------------------------------------------------------------------------- /src/drivers/pic.c: -------------------------------------------------------------------------------- 1 | #include "idt.h" 2 | #include "pic.h" 3 | #include "ports.h" 4 | 5 | #define PIC_PORT_CMD_MASTER 0x20 6 | #define PIC_PORT_DATA_MASTER 0x21 7 | #define PIC_PORT_CMD_SLAVE 0xA0 8 | #define PIC_PORT_DATA_SLAVE 0xA1 9 | 10 | #define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */ 11 | #define ICW1_SINGLE 0x02 /* Single (cascade) mode */ 12 | #define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ 13 | #define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ 14 | #define ICW1_INIT 0x10 /* Initialization - required! */ 15 | 16 | #define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ 17 | #define ICW4_AUTO 0x02 /* Auto (normal) EOI */ 18 | #define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ 19 | #define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ 20 | #define ICW4_SFNM 0x10 /* Special fully nested (not) */ 21 | 22 | #define PIC_CMD_ISR 0x0B 23 | #define PIC_CMD_EOI 0x20 24 | 25 | void pic_init() { 26 | /* Start initialization sequence */ 27 | port_byte_out(PIC_PORT_CMD_MASTER, ICW1_INIT | ICW1_ICW4); 28 | port_byte_out(PIC_PORT_CMD_SLAVE, ICW1_INIT | ICW1_ICW4); 29 | 30 | /* Set vector offsets */ 31 | port_byte_out(PIC_PORT_DATA_MASTER, IRQ_BASE); 32 | port_byte_out(PIC_PORT_DATA_SLAVE, IRQ_BASE + 8); 33 | 34 | /* Initalize slave-master relation */ 35 | port_byte_out(PIC_PORT_DATA_MASTER, 4); 36 | port_byte_out(PIC_PORT_DATA_SLAVE, 2); 37 | 38 | /* Use mode 8086 instead of 8080 */ 39 | port_byte_out(PIC_PORT_DATA_MASTER, ICW4_8086); 40 | port_byte_out(PIC_PORT_DATA_SLAVE, ICW4_8086); 41 | 42 | /* Initially mask everything but slave */ 43 | port_byte_out(PIC_PORT_DATA_MASTER, 0xFB); 44 | port_byte_out(PIC_PORT_DATA_SLAVE, 0xFF); 45 | } 46 | 47 | void pic_unmask(u8 irq) { 48 | u16 port; 49 | if (irq >= 8) { 50 | port = PIC_PORT_DATA_SLAVE; 51 | irq -= 8; 52 | } else { 53 | port = PIC_PORT_DATA_MASTER; 54 | } 55 | 56 | u8 original = port_byte_in(port); 57 | port_byte_out(port, original & ~(1u << irq)); 58 | } 59 | 60 | void pic_send_eoi(u8 irq) { 61 | if (irq >= 8) { 62 | port_byte_out(PIC_PORT_CMD_SLAVE, PIC_CMD_EOI); 63 | } 64 | port_byte_out(PIC_PORT_CMD_MASTER, PIC_CMD_EOI); 65 | } 66 | 67 | bool pic_is_in_service(u8 irq) { 68 | u16 port = PIC_PORT_CMD_MASTER; 69 | if (irq >= 8) { 70 | port = PIC_PORT_CMD_SLAVE; 71 | irq -= 8; 72 | } 73 | port_byte_out(port, PIC_CMD_ISR); 74 | return port_byte_in(port) & (1 << irq); 75 | } 76 | -------------------------------------------------------------------------------- /src/drivers/pic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include 5 | 6 | /* Initialize PIC. This has to be called once during kernel initialization */ 7 | void pic_init(); 8 | 9 | /* Unmask interrupt from PIC. Calling this allows hardware to trigger irq specified */ 10 | void pic_unmask(u8 irq); 11 | 12 | /* Used to send end of interrupt to PIC */ 13 | void pic_send_eoi(u8 irq); 14 | 15 | bool pic_is_in_service(u8 irq); 16 | -------------------------------------------------------------------------------- /src/drivers/pit.c: -------------------------------------------------------------------------------- 1 | #include "idt.h" 2 | #include "pic.h" 3 | #include "pit.h" 4 | #include "ports.h" 5 | 6 | #define PIT_IRQ 0 7 | 8 | #define TIMER0_CTL 0x40 9 | #define PIT_CTL 0x43 10 | 11 | #define SELECT_CHANNEL0 0x00 12 | 13 | #define ACCESS_HI 0x10 14 | #define ACCESS_LO 0x20 15 | 16 | #define MODE_SQUARE_WAVE 0x06 17 | 18 | #define BASE_FREQUENCY 1193182 19 | 20 | static volatile u64 s_system_time = 0; 21 | 22 | static void pit_irq_handler() { 23 | s_system_time++; 24 | } 25 | 26 | void pit_init() { 27 | port_byte_out(PIT_CTL, SELECT_CHANNEL0 | ACCESS_LO | ACCESS_HI | MODE_SQUARE_WAVE); 28 | 29 | // tick every ms 30 | const u16 timer_reload = BASE_FREQUENCY / 1000; 31 | port_byte_out(TIMER0_CTL, (timer_reload >> 0) & 0xff); 32 | port_byte_out(TIMER0_CTL, (timer_reload >> 8) & 0xff); 33 | 34 | s_system_time = 0; 35 | 36 | idt_register_irq_handler(PIT_IRQ, pit_irq_handler); 37 | pic_unmask(PIT_IRQ); 38 | } 39 | 40 | void pit_sleep_ms(u64 ms) { 41 | u64 wake_time = s_system_time + ms; 42 | while (s_system_time < wake_time) 43 | continue; 44 | } 45 | 46 | u64 pit_current_time_ms() { 47 | return s_system_time; 48 | } 49 | -------------------------------------------------------------------------------- /src/drivers/pit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | void pit_init(); 6 | void pit_sleep_ms(u64); 7 | u64 pit_current_time_ms(); 8 | -------------------------------------------------------------------------------- /src/drivers/ports.c: -------------------------------------------------------------------------------- 1 | #include "ports.h" 2 | 3 | u8 port_byte_in (u16 port) { 4 | u8 result; 5 | __asm__("in %%dx, %%al" : "=a" (result) : "d" (port)); 6 | return result; 7 | } 8 | 9 | void port_byte_out (u16 port, u8 data) { 10 | __asm__ __volatile__("out %%al, %%dx" : : "a" (data), "d" (port)); 11 | } 12 | 13 | u16 port_word_in (u16 port) { 14 | u16 result; 15 | __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port)); 16 | return result; 17 | } 18 | 19 | void port_word_out (u16 port, u16 data) { 20 | __asm__ __volatile__("out %%ax, %%dx" : : "a" (data), "d" (port)); 21 | } 22 | 23 | u32 port_dword_in (u16 port) { 24 | u32 result; 25 | asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port)); 26 | return result; 27 | } 28 | 29 | void port_dword_out (u16 port, u32 data) { 30 | asm volatile ("outl %0, %1" : : "a"(data), "Nd"(port)); 31 | } -------------------------------------------------------------------------------- /src/drivers/ports.h: -------------------------------------------------------------------------------- 1 | #ifndef PORTS_H 2 | #define PORTS_H 3 | 4 | #include "types.h" 5 | 6 | u8 port_byte_in (u16 port); 7 | void port_byte_out (u16 port, u8 data); 8 | u16 port_word_in (u16 port); 9 | void port_dword_out (u16 port, u32 data); 10 | u32 port_dword_in (u16 port); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/drivers/ps2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ps2_keyboard.h" 4 | #include "ps2_mouse.h" 5 | 6 | #define PS2_DUMP_FULL_EVENT_QUEUE 0 7 | 8 | #define PS2_TYPE_NONE 0 9 | #define PS2_TYPE_KEYBOARD 1 10 | #define PS2_TYPE_MOUSE 2 11 | 12 | #define PS2_COMMAND_QUEUE_SIZE 32 13 | #define PS2_BYTE_BUFFER_SIZE 32 14 | #define PS2_EVENT_QUEUE_SIZE 32 15 | 16 | #define PS2_DEVICE_COMMAND_IDENTIFY 0xF2 17 | #define PS2_DEVICE_COMMAND_ENABLE_SCANNING 0xF4 18 | #define PS2_DEVICE_COMMAND_DISABLE_SCANNING 0xF5 19 | #define PS2_DEVICE_COMMAND_RESET 0xFF 20 | 21 | typedef struct ps2_device { 22 | u8 type; 23 | void (*callback)(struct ps2_device*); 24 | 25 | u8 byte_buffer_len; 26 | u8 byte_buffer[PS2_BYTE_BUFFER_SIZE]; 27 | 28 | u8 event_queue_len; 29 | u8 event_queue_head; 30 | u8 event_queue_tail; 31 | union { 32 | struct { 33 | key_event_t keyboard_event_queue[PS2_EVENT_QUEUE_SIZE]; 34 | ps2_keyboard_info_t keyboard_info; 35 | }; 36 | struct { 37 | mouse_event_t mouse_event_queue[PS2_EVENT_QUEUE_SIZE]; 38 | ps2_mouse_info_t mouse_info; 39 | }; 40 | }; 41 | } ps2_device_t; 42 | 43 | void ps2_init(); 44 | void ps2_device_append_command_queue(ps2_device_t* device, u8 command, u8 response_size); 45 | void ps2_device_append_command_queue_with_data(ps2_device_t* device, u8 command, u8 data, u8 response_size); 46 | ps2_device_t* ps2_get_device(u8 index); 47 | -------------------------------------------------------------------------------- /src/drivers/ps2_keyboard.c: -------------------------------------------------------------------------------- 1 | #include "critical.h" 2 | #include "debug.h" 3 | #include "ps2_keyboard.h" 4 | #include "ps2.h" 5 | #include "utils.h" 6 | 7 | #define PS2_KEYBOARD_COMMAND_SET_LEDS 0xED 8 | #define PS2_KEYBOARD_COMMAND_SET_SCANCODE 0xF0 9 | #define PS2_KEYBOARD_COMMAND_ENABLE_SCANNING 0xF4 10 | #define PS2_KEYBOARD_COMMAND_DISABLE_SCANNING 0xF5 11 | 12 | key_t ps2_keymap_normal[0xFF]; 13 | key_t ps2_keymap_shift[0xFF]; 14 | key_t ps2_keymap_extended[0xFF]; 15 | 16 | static void ps2_keyboard_new_byte(ps2_device_t*); 17 | 18 | void ps2_init_keyboard(ps2_device_t* keyboard) { 19 | keyboard->type = PS2_TYPE_KEYBOARD; 20 | keyboard->callback = ps2_keyboard_new_byte; 21 | keyboard->keyboard_info.modifiers = 0; 22 | 23 | /* Turn off all keyboard leds (caps lock, num lock, ...)*/ 24 | ps2_device_append_command_queue_with_data(keyboard, PS2_KEYBOARD_COMMAND_SET_LEDS, 0x00, 0); 25 | 26 | /* Set keyboard to use scancode set 2 */ 27 | ps2_device_append_command_queue_with_data(keyboard, PS2_KEYBOARD_COMMAND_SET_SCANCODE, 2, 0); 28 | 29 | /* Enable scanning (reading user keypresses) */ 30 | ps2_device_append_command_queue(keyboard, PS2_KEYBOARD_COMMAND_ENABLE_SCANNING, 0); 31 | } 32 | 33 | static void ps2_keyboard_new_byte(ps2_device_t* keyboard) { 34 | /* If last byte is 0xE0 or 0xF0, key event is not yet ready */ 35 | u8 last_byte = keyboard->byte_buffer[keyboard->byte_buffer_len - 1]; 36 | if (last_byte == 0xE0 || last_byte == 0xF0) { 37 | return; 38 | } 39 | 40 | if (last_byte == 0x00 || last_byte == 0xFF) { 41 | dprintln("PS/2 Keyboard: keydetection error or internal buffer overflow"); 42 | keyboard->byte_buffer_len = 0; 43 | return; 44 | } 45 | 46 | if (keyboard->byte_buffer_len > 3) { 47 | dprintln("PS/2 Keyboard: corrupted package"); 48 | keyboard->byte_buffer_len = 0; 49 | return; 50 | } 51 | 52 | u8 index = 0; 53 | 54 | bool extended = false; 55 | if (index < keyboard->byte_buffer_len && keyboard->byte_buffer[index] == 0xE0) { 56 | extended = true; 57 | index++; 58 | } 59 | 60 | bool released = false; 61 | if (index < keyboard->byte_buffer_len && keyboard->byte_buffer[index] == 0xF0) { 62 | released = true; 63 | index++; 64 | } 65 | 66 | bool corrupted = (index + 1 != keyboard->byte_buffer_len); 67 | keyboard->byte_buffer_len = 0; 68 | 69 | if (corrupted) 70 | { 71 | dprintln("PS/2 Keyboard: corrupted packet"); 72 | return; 73 | } 74 | 75 | u8 scancode = keyboard->byte_buffer[index]; 76 | 77 | if (keyboard->event_queue_len >= PS2_EVENT_QUEUE_SIZE) { 78 | #if PS2_DUMP_FULL_EVENT_QUEUE 79 | dprintln("PS/2 Keyboard: event queue full, dropping oldest event"); 80 | #endif 81 | keyboard->event_queue_tail = (keyboard->event_queue_tail + 1) % PS2_EVENT_QUEUE_SIZE; 82 | keyboard->event_queue_len--; 83 | } 84 | 85 | key_event_t* event = &keyboard->keyboard_event_queue[keyboard->event_queue_head]; 86 | 87 | event->modifiers = keyboard->keyboard_info.modifiers; 88 | if (released) { 89 | event->modifiers |= KEY_EVENT_MODIFIERS_RELEASED; 90 | } 91 | 92 | if (extended) { 93 | event->key = ps2_keymap_extended[scancode]; 94 | } else if (event->modifiers & KEY_EVENT_MODIFIERS_SHIFT) { 95 | event->key = ps2_keymap_shift[scancode]; 96 | } else { 97 | event->key = ps2_keymap_normal[scancode]; 98 | } 99 | 100 | switch (event->key) 101 | { 102 | case KEY_LeftShift: 103 | case KEY_RightShift: 104 | if (released) { 105 | keyboard->keyboard_info.modifiers &= ~KEY_EVENT_MODIFIERS_SHIFT; 106 | } else { 107 | keyboard->keyboard_info.modifiers |= KEY_EVENT_MODIFIERS_SHIFT; 108 | } 109 | break; 110 | case KEY_LeftCtrl: 111 | case KEY_RightCtrl: 112 | if (released) { 113 | keyboard->keyboard_info.modifiers &= ~KEY_EVENT_MODIFIERS_CONTROL; 114 | } else { 115 | keyboard->keyboard_info.modifiers |= KEY_EVENT_MODIFIERS_CONTROL; 116 | } 117 | break; 118 | case KEY_CapsLock: 119 | if (!released) { 120 | keyboard->keyboard_info.modifiers ^= KEY_EVENT_MODIFIERS_CAPS_LOCK; 121 | } 122 | break; 123 | default: 124 | break; 125 | } 126 | 127 | keyboard->event_queue_head = (keyboard->event_queue_head + 1) % PS2_EVENT_QUEUE_SIZE; 128 | keyboard->event_queue_len++; 129 | } 130 | 131 | void ps2_get_key_event(key_event_t* out) { 132 | for (u8 i = 0; i < 2; i++) { 133 | ps2_device_t* device = ps2_get_device(i); 134 | if (device->type != PS2_TYPE_KEYBOARD) { 135 | continue; 136 | } 137 | 138 | ENTER_CRITICAL(); 139 | if (device->event_queue_len == 0) { 140 | LEAVE_CRITICAL(); 141 | continue; 142 | } 143 | 144 | memcpy(out, &device->keyboard_event_queue[device->event_queue_tail], sizeof(key_event_t)); 145 | device->event_queue_tail = (device->event_queue_tail + 1) % PS2_EVENT_QUEUE_SIZE; 146 | device->event_queue_len--; 147 | LEAVE_CRITICAL(); 148 | 149 | return; 150 | } 151 | 152 | out->key = KEY_NONE; 153 | } 154 | -------------------------------------------------------------------------------- /src/drivers/ps2_keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "key.h" 4 | 5 | #include 6 | 7 | typedef struct { 8 | u8 modifiers; 9 | } ps2_keyboard_info_t; 10 | 11 | extern key_t ps2_keymap_normal[0xFF]; 12 | extern key_t ps2_keymap_shift[0xFF]; 13 | extern key_t ps2_keymap_extended[0xFF]; 14 | 15 | typedef struct ps2_device ps2_device_t; 16 | 17 | void ps2_init_keyboard(ps2_device_t*); 18 | 19 | /* Write key event to out. If no event has happened, key is KEY_NONE */ 20 | void ps2_get_key_event(key_event_t* out); 21 | -------------------------------------------------------------------------------- /src/drivers/ps2_mouse.c: -------------------------------------------------------------------------------- 1 | #include "critical.h" 2 | #include "debug.h" 3 | #include "ps2_mouse.h" 4 | #include "ps2.h" 5 | #include "utils.h" 6 | 7 | #define PS2_MOUSE_COMMAND_SET_SAMPLE_RATE 0xF3 8 | 9 | static void ps2_mouse_new_byte(ps2_device_t*); 10 | 11 | void ps2_init_mouse(ps2_device_t* mouse) { 12 | mouse->type = PS2_TYPE_MOUSE; 13 | mouse->callback = ps2_mouse_new_byte; 14 | mouse->mouse_info.enabled = false; 15 | mouse->mouse_info.id = 0xFF; 16 | mouse->mouse_info.button_mask = 0; 17 | 18 | /* Send magic sequence to query mouse extensions */ 19 | ps2_device_append_command_queue_with_data(mouse, PS2_MOUSE_COMMAND_SET_SAMPLE_RATE, 200, 0); 20 | ps2_device_append_command_queue_with_data(mouse, PS2_MOUSE_COMMAND_SET_SAMPLE_RATE, 100, 0); 21 | ps2_device_append_command_queue_with_data(mouse, PS2_MOUSE_COMMAND_SET_SAMPLE_RATE, 80, 0); 22 | ps2_device_append_command_queue(mouse, PS2_DEVICE_COMMAND_IDENTIFY, 1); 23 | } 24 | 25 | static void ps2_mouse_initialize_extensions(ps2_device_t* mouse) { 26 | u8 last_byte = mouse->byte_buffer[mouse->byte_buffer_len - 1]; 27 | mouse->byte_buffer_len = 0; 28 | 29 | switch (last_byte) 30 | { 31 | case 0x00: 32 | /* No extensions available */ 33 | mouse->mouse_info.id = 0x00; 34 | mouse->mouse_info.enabled = true; 35 | break; 36 | case 0x03: 37 | if (mouse->mouse_info.id == 0x03) { 38 | /* No 5 button extension available */ 39 | mouse->mouse_info.enabled = true; 40 | } else { 41 | /* Scoll extension available, query for 5 button extension */ 42 | mouse->mouse_info.id = 0x03; 43 | ps2_device_append_command_queue_with_data(mouse, PS2_MOUSE_COMMAND_SET_SAMPLE_RATE, 200, 0); 44 | ps2_device_append_command_queue_with_data(mouse, PS2_MOUSE_COMMAND_SET_SAMPLE_RATE, 200, 0); 45 | ps2_device_append_command_queue_with_data(mouse, PS2_MOUSE_COMMAND_SET_SAMPLE_RATE, 80, 0); 46 | ps2_device_append_command_queue(mouse, PS2_DEVICE_COMMAND_IDENTIFY, 1); 47 | } 48 | break; 49 | case 0x04: 50 | /* Scroll and 5 button extensions available! */ 51 | mouse->mouse_info.id = 0x04; 52 | mouse->mouse_info.enabled = true; 53 | break; 54 | default: 55 | dprint("unknown mouse identification byte "); 56 | dprintbyte(last_byte); 57 | dprintln(", assuming no extensions"); 58 | mouse->mouse_info.id = 0x00; 59 | mouse->mouse_info.enabled = true; 60 | break; 61 | } 62 | 63 | /* Set appropriate sample rate and enable mouse scanning */ 64 | if (mouse->mouse_info.enabled) { 65 | ps2_device_append_command_queue_with_data(mouse, PS2_MOUSE_COMMAND_SET_SAMPLE_RATE, 100, 0); 66 | ps2_device_append_command_queue(mouse, PS2_DEVICE_COMMAND_ENABLE_SCANNING, 0); 67 | } 68 | } 69 | 70 | static void ps2_mouse_new_byte(ps2_device_t* mouse) { 71 | /* If mouse is not yet enabled, it means that we are initializing extensions */ 72 | if (!mouse->mouse_info.enabled) { 73 | ps2_mouse_initialize_extensions(mouse); 74 | return; 75 | } 76 | 77 | if (!(mouse->byte_buffer[0] & 0x08)) { 78 | dprintln("corrupted mouse packet"); 79 | mouse->byte_buffer_len = 0; 80 | return; 81 | } 82 | 83 | /* Mouse extensions send 1 extra byte of data */ 84 | int packet_size = (mouse->mouse_info.id == 0x00) ? 3 : 4; 85 | 86 | /* If event packet is not yet sent fully, wait for rest of it */ 87 | if (mouse->byte_buffer_len != packet_size) { 88 | return; 89 | } 90 | mouse->byte_buffer_len = 0; 91 | 92 | /* Ignore packets with bits 6 or 7 set. Qemu sends weird non-standard packets on touchpad when scrolling horizontally. */ 93 | if (mouse->mouse_info.id == 0x04 && (mouse->byte_buffer[3] & 0xC0)) { 94 | return; 95 | } 96 | 97 | /* Bits 0-2 define pressed standard buttons */ 98 | u8 button_mask = mouse->byte_buffer[0] & 0x07; 99 | 100 | /* Calculate mouse movement with sign extensions */ 101 | s32 rel_x = mouse->byte_buffer[1] - (((u16)mouse->byte_buffer[0] << 4) & 0x100); 102 | s32 rel_y = mouse->byte_buffer[2] - (((u16)mouse->byte_buffer[0] << 3) & 0x100); 103 | 104 | /* Mouse IDs 0x03 and 0x04 have byte scroll events */ 105 | s32 scroll = 0; 106 | if (mouse->mouse_info.id == 0x03 || mouse->mouse_info.id == 0x04) { 107 | scroll = (mouse->byte_buffer[3] & 0x0F) - ((mouse->byte_buffer[3] << 1) & 0x10); 108 | } 109 | 110 | /* Mouse ID 0x04 has 2 extra bits for extra buttons */ 111 | if (mouse->mouse_info.id == 0x04) { 112 | button_mask |= (mouse->byte_buffer[3] >> 1) & 0x18; 113 | } 114 | 115 | /* There can be at most 7 events per interrupt (5 buttons, move, scroll) */ 116 | mouse_event_t new_events[7]; 117 | int new_event_count = 0; 118 | 119 | /* Check if button mask has changed (buttons pressed or released) */ 120 | if (button_mask != mouse->mouse_info.button_mask) { 121 | for (int i = 0; i < 5; i++) { 122 | if ((button_mask & (1 << i)) == (mouse->mouse_info.button_mask & (1 << i))) { 123 | continue; 124 | } 125 | 126 | mouse_event_t* event = &new_events[new_event_count++]; 127 | event->type = MOUSE_BUTTON_EVENT; 128 | event->button_event.pressed = !!(button_mask & (1 << i)); 129 | event->button_event.button = i; 130 | } 131 | 132 | mouse->mouse_info.button_mask = button_mask; 133 | } 134 | 135 | /* Check if mouse has moved */ 136 | if (rel_x != 0 || rel_y != 0) { 137 | mouse_event_t* event = &new_events[new_event_count++]; 138 | event->type = MOUSE_MOVE_EVENT; 139 | event->move_event.rel_x = rel_x; 140 | event->move_event.rel_y = rel_y; 141 | } 142 | 143 | /* Check if mouse has scrolled */ 144 | if (scroll) { 145 | mouse_event_t* event = &new_events[new_event_count++]; 146 | event->type = MOUSE_SCROLL_EVENT; 147 | event->scroll_event.value = scroll; 148 | } 149 | 150 | if (mouse->event_queue_len + new_event_count >= PS2_EVENT_QUEUE_SIZE) { 151 | #if PS2_DUMP_FULL_EVENT_QUEUE 152 | dprintln("PS/2 Mouse: event queue full, dropping oldest event"); 153 | #endif 154 | mouse->event_queue_tail = (mouse->event_queue_tail + new_event_count) % PS2_EVENT_QUEUE_SIZE; 155 | mouse->event_queue_len -= new_event_count; 156 | } 157 | 158 | /* Add events to mouse event queue */ 159 | for (int i = 0; i < new_event_count; i++) { 160 | memcpy(&mouse->mouse_event_queue[mouse->event_queue_head], &new_events[i], sizeof(mouse_event_t)); 161 | mouse->event_queue_head = (mouse->event_queue_head + 1) % PS2_EVENT_QUEUE_SIZE; 162 | mouse->event_queue_len++; 163 | } 164 | } 165 | 166 | void ps2_get_mouse_event(mouse_event_t* out) { 167 | for (u8 i = 0; i < 2; i++) { 168 | ps2_device_t* device = ps2_get_device(i); 169 | if (device->type != PS2_TYPE_MOUSE) { 170 | continue; 171 | } 172 | 173 | ENTER_CRITICAL(); 174 | if (device->event_queue_len == 0) { 175 | LEAVE_CRITICAL(); 176 | continue; 177 | } 178 | 179 | memcpy(out, &device->mouse_event_queue[device->event_queue_tail], sizeof(mouse_event_t)); 180 | device->event_queue_tail = (device->event_queue_tail + 1) % PS2_EVENT_QUEUE_SIZE; 181 | device->event_queue_len--; 182 | LEAVE_CRITICAL(); 183 | 184 | return; 185 | } 186 | 187 | out->type = MOUSE_EVENT_NONE; 188 | } 189 | -------------------------------------------------------------------------------- /src/drivers/ps2_mouse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mouse.h" 4 | #include "types.h" 5 | 6 | typedef struct { 7 | bool enabled; 8 | u8 id; 9 | u8 button_mask; 10 | } ps2_mouse_info_t; 11 | 12 | typedef struct ps2_device ps2_device_t; 13 | 14 | void ps2_init_mouse(ps2_device_t*); 15 | 16 | /* Write mouse event to out. If no event has happened, out->type == MOUSE_EVENT_NONE */ 17 | void ps2_get_mouse_event(mouse_event_t* out); 18 | -------------------------------------------------------------------------------- /src/drivers/sound.c: -------------------------------------------------------------------------------- 1 | #include "ports.h" 2 | #include "sound.h" 3 | 4 | /* PC Speaker Stuff */ 5 | void startbeep(u32 nFrequence) { 6 | /* Sets the PIT to the desired freq */ 7 | u32 div = 1193180 / nFrequence; 8 | port_byte_out(0x43, 0xb6); 9 | port_byte_out(0x42, (u8) (div)); 10 | port_byte_out(0x42, (u8) (div >> 8)); 11 | 12 | /* Now lets actually BEEP */ 13 | u8 tmp = port_byte_in(0x61); 14 | if (tmp != (tmp | 3)) { 15 | port_byte_out(0x61, tmp | 3); 16 | } 17 | } 18 | 19 | /* Make the beeper shut up */ 20 | void mutebeep() { 21 | u8 tmp = port_byte_in(0x61) & 0xFC; 22 | port_byte_out(0x61, tmp); 23 | } 24 | -------------------------------------------------------------------------------- /src/drivers/sound.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | void startbeep(u32 nFrequence); 6 | void mutebeep(); 7 | -------------------------------------------------------------------------------- /src/drivers/ssp.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "../kernel/panic.h" 3 | 4 | #if UINT32_MAX == UINTPTR_MAX 5 | #define STACK_CHK_GUARD 0x7eef2b9e 6 | #else 7 | #define STACK_CHK_GUARD 0x14047e612c70ba90 8 | #endif 9 | 10 | /* FIXME: This should be randomized by the bootloader. 11 | As the the kernel is WIP and there are no attackers 12 | this will find bugs and is much better than nothing. */ 13 | uptr __stack_chk_guard = STACK_CHK_GUARD; 14 | 15 | __attribute__((noreturn)) 16 | void __stack_chk_fail(void) 17 | { 18 | panic("Stack smashing detected"); 19 | } 20 | 21 | __attribute__((noreturn)) 22 | void __stack_chk_fail_local(void) 23 | { 24 | __stack_chk_fail(); 25 | } 26 | -------------------------------------------------------------------------------- /src/drivers/storage/ata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ata_controller_init(); 4 | -------------------------------------------------------------------------------- /src/drivers/storage/device.c: -------------------------------------------------------------------------------- 1 | #include "ata.h" 2 | #include "device.h" 3 | #include "partition.h" 4 | #include 5 | #include 6 | 7 | static int g_storage_device_capacity; 8 | int g_storage_device_count; 9 | storage_device_t** g_storage_devices; 10 | 11 | int storage_device_init() { 12 | g_storage_device_count = 0; 13 | 14 | g_storage_device_capacity = 16; 15 | g_storage_devices = (storage_device_t**)kmalloc(sizeof(storage_device_t*) * g_storage_device_capacity); 16 | if (g_storage_devices == NULL) { 17 | panic("Failed to allocate memory for storage devices"); 18 | } 19 | 20 | ata_controller_init(); 21 | 22 | int device_count = g_storage_device_count; 23 | for (int i = 0; i < device_count; i++) { 24 | partition_probe(g_storage_devices[i]); 25 | } 26 | 27 | return g_storage_device_count; 28 | } 29 | 30 | void storage_device_add(storage_device_t* device) { 31 | // Resize the list if necessary 32 | if (g_storage_device_count == g_storage_device_capacity) { 33 | int new_capacity = g_storage_device_capacity * 2; 34 | storage_device_t** new_devices = (storage_device_t**)kmalloc(sizeof(storage_device_t*) * new_capacity); 35 | if (new_devices == NULL) { 36 | panic("Failed to allocate memory for storage devices"); 37 | } 38 | for (int i = 0; i < g_storage_device_count; i++) { 39 | new_devices[i] = g_storage_devices[i]; 40 | } 41 | kfree(g_storage_devices); 42 | g_storage_devices = new_devices; 43 | g_storage_device_capacity = new_capacity; 44 | } 45 | 46 | // Add the device to the list 47 | g_storage_devices[g_storage_device_count++] = device; 48 | } 49 | -------------------------------------------------------------------------------- /src/drivers/storage/device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../types.h" 4 | #include 5 | 6 | typedef struct storage_device { 7 | bool (*read_sectors)(void* self, void* buffer, u64 sector, u64 count); 8 | bool (*write_sectors)(void* self, const void* buffer, u64 sector, u64 count); 9 | u64 sector_count; 10 | u32 sector_size; 11 | const char* model; 12 | struct storage_device** partitions; 13 | u32 partition_count; 14 | } storage_device_t; 15 | 16 | // Initialize all storage devices 17 | // Returns the number of storage devices found 18 | int storage_device_init(); 19 | 20 | // Add a storage device to the list of storage devices 21 | void storage_device_add(storage_device_t* device); 22 | 23 | extern int g_storage_device_count; 24 | extern storage_device_t** g_storage_devices; 25 | -------------------------------------------------------------------------------- /src/drivers/storage/fat.c: -------------------------------------------------------------------------------- 1 | // FAT support 2 | 3 | #include "fat.h" 4 | 5 | // Open a file 6 | void FAT_Open(file){ 7 | return 0; // <-- THIS IS JUST A PLACEHOLDER! 8 | } 9 | 10 | // Reads a file 11 | void FAT_Read(file){ 12 | return 0; // <-- THIS IS JUST A PLACEHOLDER! 13 | } 14 | 15 | // Writes a file 16 | void FAT_Write(file){ 17 | return 0; // <-- THIS IS JUST A PLACEHOLDER! 18 | } -------------------------------------------------------------------------------- /src/drivers/storage/fat.h: -------------------------------------------------------------------------------- 1 | // TODO: Add proper code and headers -------------------------------------------------------------------------------- /src/drivers/storage/gpt.c: -------------------------------------------------------------------------------- 1 | #include "../debug.h" 2 | #include "../utils.h" 3 | #include "gpt.h" 4 | #include "partition.h" 5 | #include 6 | 7 | struct gpt_header { 8 | u8 signature[8]; 9 | u32 revision; 10 | u32 header_size; 11 | u32 header_crc32; 12 | u32 reserved; 13 | u64 current_lba; 14 | u64 backup_lba; 15 | u64 first_usable_lba; 16 | u64 last_usable_lba; 17 | u8 disk_guid[16]; 18 | u64 partition_entry_lba; 19 | u32 num_partition_entries; 20 | u32 size_partition_entry; 21 | u32 partition_entry_array_crc32; 22 | } __attribute__((packed)); 23 | 24 | struct gpt_partition_entry { 25 | u8 partition_type_guid[16]; 26 | u8 unique_partition_guid[16]; 27 | u64 first_lba; 28 | u64 last_lba; 29 | u64 attributes; 30 | u16 partition_name[36]; 31 | } __attribute__((packed)); 32 | 33 | bool partition_probe_gpt(storage_device_t* device, u8 buffer[512]) { 34 | struct gpt_header* gpt_header = (struct gpt_header*)buffer; 35 | if (memcmp(gpt_header->signature, "EFI PART", 8) != 0) { 36 | return false; 37 | } 38 | 39 | dprint("Found GPT on '"); 40 | dprint(device->model); 41 | dprintln("'"); 42 | 43 | // FIXME: Do error checking 44 | 45 | u8 partition_buffer[512]; 46 | u32 last_partition_lba = 0; 47 | 48 | for (u32 i = 0; i < gpt_header->num_partition_entries; i++) { 49 | u32 byte_offset = gpt_header->partition_entry_lba * device->sector_size + i * gpt_header->size_partition_entry; 50 | if (byte_offset / device->sector_size != last_partition_lba) { 51 | if (!device->read_sectors(device, partition_buffer, byte_offset / device->sector_size, 1)) { 52 | dprint("\e[33mFailed to read partition entry "); 53 | dprintint(i); 54 | dprintln("\e[m"); 55 | return false; 56 | } 57 | last_partition_lba = byte_offset / device->sector_size; 58 | } 59 | 60 | struct gpt_partition_entry* gpt_partition_entry = (struct gpt_partition_entry*)(partition_buffer + byte_offset % device->sector_size); 61 | u8 zero_guid[16] = { 0 }; 62 | if (memcmp(gpt_partition_entry->partition_type_guid, zero_guid, 16) == 0) { 63 | continue; 64 | } 65 | 66 | char name[37]; 67 | name[36] = '\0'; 68 | for (int j = 0; j < 36; j++) { 69 | name[j] = gpt_partition_entry->partition_name[j]; 70 | } 71 | 72 | partition_add_to_device( 73 | device, 74 | gpt_partition_entry->first_lba, 75 | gpt_partition_entry->last_lba, 76 | name 77 | ); 78 | } 79 | 80 | return true; 81 | } 82 | -------------------------------------------------------------------------------- /src/drivers/storage/gpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "device.h" 4 | 5 | bool partition_probe_gpt(storage_device_t*, u8 buffer[512]); 6 | -------------------------------------------------------------------------------- /src/drivers/storage/partition.c: -------------------------------------------------------------------------------- 1 | #include "../debug.h" 2 | #include "../utils.h" 3 | #include "device.h" 4 | #include "gpt.h" 5 | #include "partition.h" 6 | #include 7 | #include 8 | 9 | typedef struct { 10 | storage_device_t device; 11 | storage_device_t* disk; 12 | u64 first_sector; 13 | } partition_device_t; 14 | 15 | static bool partition_read_sectors(void* self, void* buffer, u64 sector, u64 count) { 16 | partition_device_t* device = (partition_device_t*)self; 17 | if (sector + count > device->device.sector_count) { 18 | dprintln("Partition read: sector out of range"); 19 | return false; 20 | } 21 | return device->disk->read_sectors(device->disk, buffer, device->first_sector + sector, count); 22 | } 23 | 24 | static bool partition_write_sectors(void* self, const void* buffer, u64 sector, u64 count) { 25 | partition_device_t* device = (partition_device_t*)self; 26 | if (sector + count > device->device.sector_count) { 27 | dprintln("Partition write: sector out of range"); 28 | return false; 29 | } 30 | return device->disk->write_sectors(device, buffer, device->first_sector + sector, count); 31 | } 32 | 33 | bool partition_probe(storage_device_t* device) { 34 | u8 buffer[512]; 35 | 36 | // Read the first sector of the device 37 | if (!device->read_sectors(device, buffer, 1, 1)) { 38 | dprint("\e[33mFailed to read sector 1 of '"); 39 | dprint(device->model); 40 | dprintln("'\e[m"); 41 | return false; 42 | } 43 | 44 | if (memcmp(buffer, "EFI PART", 8) == 0) { 45 | return partition_probe_gpt(device, buffer); 46 | } 47 | 48 | dprint("\e[33mNo known partition table found on '"); 49 | dprint(device->model); 50 | dprintln("'\e[m"); 51 | 52 | return false; 53 | } 54 | 55 | void partition_add_to_device(storage_device_t* disk, u64 first_sector, u64 last_sector, const char* name) { 56 | partition_device_t* partition = (partition_device_t*)kmalloc(sizeof(partition_device_t)); 57 | if (partition == NULL) { 58 | panic("Failed to allocate memory for partition"); 59 | } 60 | 61 | char* model = (char*)kmalloc(strlen(name) + 1); 62 | if (model == NULL) { 63 | panic("Failed to allocate memory for partition model"); 64 | } 65 | strcpy(model, name); 66 | 67 | partition->device.read_sectors = partition_read_sectors; 68 | partition->device.write_sectors = partition_write_sectors; 69 | partition->device.sector_count = last_sector - first_sector + 1; 70 | partition->device.sector_size = disk->sector_size; 71 | partition->device.model = model; 72 | partition->disk = disk; 73 | partition->first_sector = first_sector; 74 | 75 | storage_device_t** new_partitions = (storage_device_t**)kmalloc(sizeof(storage_device_t*) * (disk->partition_count + 1)); 76 | if (new_partitions == NULL) { 77 | panic("Failed to allocate memory for partitions"); 78 | } 79 | memcpy(new_partitions, disk->partitions, sizeof(storage_device_t*) * disk->partition_count); 80 | kfree(disk->partitions); 81 | new_partitions[disk->partition_count++] = (storage_device_t*)partition; 82 | disk->partitions = new_partitions; 83 | } 84 | -------------------------------------------------------------------------------- /src/drivers/storage/partition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "device.h" 4 | 5 | bool partition_probe(storage_device_t*); 6 | void partition_add_to_device(storage_device_t* disk, u64 first_sector, u64 last_sector, const char* name); 7 | -------------------------------------------------------------------------------- /src/drivers/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* Instead of using 'chars' to allocate non-character bytes, 9 | * we will use these new type with no semantic meaning */ 10 | typedef uint64_t u64; 11 | typedef int64_t s64; 12 | typedef uint32_t u32; 13 | typedef int32_t s32; 14 | typedef uint16_t u16; 15 | typedef int16_t s16; 16 | typedef uint8_t u8; 17 | typedef int8_t s8; 18 | 19 | typedef uintptr_t uptr; 20 | 21 | #define low_16(address) (u16)((address) & 0xFFFF) 22 | #define high_16(address) (u16)(((address) >> 16) & 0xFFFF) 23 | 24 | #endif -------------------------------------------------------------------------------- /src/drivers/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include 3 | 4 | void* memcpy(void* dst, const void* src, size_t len) { 5 | u8* dst_u8 = (u8*)dst; 6 | const u8* src_u8 = (const u8*)src; 7 | for (size_t i = 0; i < len; i++) { 8 | dst_u8[i] = src_u8[i]; 9 | } 10 | return dst; 11 | } 12 | 13 | void* memmove(void* dst, const void* src, size_t len) { 14 | u8* dst_u8 = (u8*)dst; 15 | const u8* src_u8 = (const u8*)src; 16 | if (dst_u8 < src_u8) { 17 | for (size_t i = 0; i < len; i++) { 18 | dst_u8[i] = src_u8[i]; 19 | } 20 | } else { 21 | for (u32 i = 1; i <= len; i++) { 22 | dst_u8[len - i] = src_u8[len - i]; 23 | } 24 | } 25 | return dst; 26 | } 27 | 28 | void* memset(void* dst, int val, size_t len) { 29 | u8* dst_u8 = (u8*)dst; 30 | for (size_t i = 0; i < len; i++) { 31 | dst_u8[i] = val; 32 | } 33 | return dst; 34 | } 35 | 36 | int memcmp(const void *a, const void *b, u32 len) { 37 | const u8* a_u8 = (const u8*)a; 38 | const u8* b_u8 = (const u8*)b; 39 | for (u32 i = 0; i < len; i++) { 40 | if (a_u8[i] != b_u8[i]) { 41 | return (int)a_u8[i] - (int)b_u8[i]; 42 | } 43 | } 44 | return 0; 45 | } 46 | 47 | void iota(int n, char str[]) { 48 | int i, sign; 49 | if ((sign = n) < 0) n = -n; 50 | i = 0; 51 | do { 52 | str[i++] = n % 10 + '0'; 53 | } while ((n /= 10) > 0); 54 | 55 | if (sign < 0) str[i++] = '-'; 56 | str[i] = '\0'; 57 | } 58 | 59 | atoi_result_t atoi(const char* str) { 60 | // parse optional sign 61 | bool negative = (*str == '-'); 62 | if (*str == '-' || *str == '+') { 63 | str++; 64 | } 65 | 66 | // parse digits 67 | int value = 0; 68 | while (*str) { 69 | if (*str < '0' || *str > '9') { 70 | atoi_result_t result = { .valid = false, .value = 0 }; 71 | return result; 72 | } 73 | value = (value * 10) + (*str - '0'); 74 | str++; 75 | } 76 | 77 | if (negative) { 78 | value = -value; 79 | } 80 | 81 | atoi_result_t result = { .valid = true, .value = value }; 82 | return result; 83 | } 84 | 85 | int abs(int x) { 86 | return x < 0 ? -x : x; 87 | } 88 | 89 | // VuleSuma 90 | float fmod(float x, float y) { 91 | return x - (x / y) * y; 92 | } 93 | 94 | // Fixed point sin 95 | float sin(float x) { 96 | x = fmod(x, 2 * M_PI); 97 | if (x < -M_PI) x += 2 * M_PI; 98 | if (x > M_PI) x -= 2 * M_PI; 99 | float term = x; 100 | float sinValue = term; 101 | for (int i = 1; i < 10; ++i) { 102 | term *= -x * x / ((2 * i) * (2 * i + 1)); 103 | sinValue += term; 104 | } 105 | return sinValue; 106 | } 107 | 108 | // Fixed point cos 109 | float cos(float x) { 110 | x = fmod(x, 2 * M_PI); 111 | if (x < -M_PI) x += 2 * M_PI; 112 | if (x > M_PI) x -= 2 * M_PI; 113 | 114 | float term = 1.0f; 115 | float cosValue = term; 116 | for (int i = 1; i < 10; ++i) { 117 | term *= -x * x / ((2 * i - 1) * (2 * i)); 118 | cosValue += term; 119 | } 120 | return cosValue; 121 | } 122 | 123 | int strlen(const char *str) { 124 | int i = 0; 125 | while (str[i]) { 126 | i++; 127 | } 128 | return i; 129 | } 130 | 131 | int strcmp(const char *str1, const char *str2) { 132 | while (*str1 && *str2 && *str1 == *str2) { 133 | str1++; 134 | str2++; 135 | } 136 | return *str1 - *str2; 137 | } 138 | 139 | char* strcpy(char* dest, const char* src) { 140 | int i = 0; 141 | while (src[i]) { 142 | dest[i] = src[i]; 143 | i++; 144 | } 145 | dest[i] = '\0'; 146 | return dest; 147 | } 148 | 149 | char* strcat(char* dest, const char* src) { 150 | int len = strlen(dest); 151 | int i = 0; 152 | while (src[i]) { 153 | dest[len + i] = src[i]; 154 | i++; 155 | } 156 | dest[len + i] = '\0'; 157 | return dest; 158 | } 159 | 160 | int tolower(int ch) { 161 | if (ch < 'A' || ch > 'Z') { 162 | return ch; 163 | } 164 | return ch - 'A' + 'a'; 165 | } 166 | 167 | int toupper(int ch) { 168 | if (ch < 'a' || ch > 'z') { 169 | return ch; 170 | } 171 | return ch - 'a' + 'A'; 172 | } 173 | 174 | /* This isn't an actual utility, it's just for uint64_to_string(). */ 175 | int get_num_length(uint64_t num) { 176 | int length = 0; 177 | do { 178 | length++; 179 | num /= 10; 180 | } while (num > 0); 181 | return length; 182 | } 183 | 184 | void uint64_to_string(uint64_t number, char* buffer) { 185 | int length = get_num_length(number); 186 | buffer[length] = '\0'; 187 | int index = length - 1; 188 | do { 189 | buffer[index--] = '0' + (number % 10); 190 | number /= 10; 191 | } while (number > 0); 192 | } 193 | -------------------------------------------------------------------------------- /src/drivers/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | void* memcpy(void *dest, const void *source, size_t nbytes); 6 | void* memmove(void *dest, const void *source, size_t nbytes); 7 | void* memset(void *dest, int val, size_t len); 8 | int memcmp(const void *a, const void *b, size_t len); 9 | 10 | typedef struct { 11 | bool valid; 12 | int value; 13 | } atoi_result_t; 14 | atoi_result_t atoi(const char*); 15 | 16 | #define M_PI 3.14159265358979323846 17 | 18 | int abs(int x); 19 | float fmod(float x, float y); 20 | float sin(float x); 21 | float cos(float x); 22 | 23 | void uint64_to_string(uint64_t number, char* buffer); 24 | int strlen(const char *str); 25 | int strcmp(const char *str1, const char *str2); 26 | char* strcpy(char *dest, const char *src); 27 | char* strcat(char *dest, const char *src); 28 | 29 | int tolower(int); 30 | int toupper(int); 31 | -------------------------------------------------------------------------------- /src/drivers/vbe.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | // Source: http://cvs.savannah.nongnu.org/viewvc/*checkout*/vgabios/vgabios/vbe_display_api.txt?revision=1.14 5 | #define VBE_DISPI_BANK_ADDRESS 0xA0000 6 | #define VBE_DISPI_BANK_SIZE_KB 64 7 | 8 | #define VBE_DISPI_MAX_XRES 1024 9 | #define VBE_DISPI_MAX_YRES 768 10 | 11 | #define VBE_DISPI_IOPORT_INDEX 0x01CE 12 | #define VBE_DISPI_IOPORT_DATA 0x01CF 13 | 14 | #define VBE_DISPI_INDEX_ID 0x0 15 | #define VBE_DISPI_INDEX_XRES 0x1 16 | #define VBE_DISPI_INDEX_YRES 0x2 17 | #define VBE_DISPI_INDEX_BPP 0x3 18 | #define VBE_DISPI_INDEX_ENABLE 0x4 19 | #define VBE_DISPI_INDEX_BANK 0x5 20 | #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 21 | #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 22 | #define VBE_DISPI_INDEX_X_OFFSET 0x8 23 | #define VBE_DISPI_INDEX_Y_OFFSET 0x9 24 | 25 | #define VBE_DISPI_ID0 0xB0C0 26 | #define VBE_DISPI_ID1 0xB0C1 27 | #define VBE_DISPI_ID2 0xB0C2 28 | #define VBE_DISPI_ID3 0xB0C3 29 | #define VBE_DISPI_ID4 0xB0C4 30 | 31 | #define VBE_DISPI_DISABLED 0x00 32 | #define VBE_DISPI_ENABLED 0x01 33 | #define VBE_DISPI_VBE_ENABLED 0x40 34 | #define VBE_DISPI_NOCLEARMEM 0x80 35 | 36 | #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 37 | 38 | 39 | #define VBE_DISPI_BPP_4 0x04 40 | #define VBE_DISPI_BPP_8 0x08 41 | #define VBE_DISPI_BPP_15 0x0F 42 | #define VBE_DISPI_BPP_16 0x10 43 | #define VBE_DISPI_BPP_24 0x18 44 | #define VBE_DISPI_BPP_32 0x20 45 | #define VBE_DISPI_LFB_ENABLED 0x40 46 | 47 | #define HD 1280,720 48 | #define FHD 1920,1080 49 | #define UHD 3840,2160 50 | 51 | typedef struct { 52 | unsigned char magic[2]; 53 | unsigned char mode; 54 | unsigned char charsize; 55 | } PSF1_HEADER; 56 | 57 | typedef struct { 58 | PSF1_HEADER* psf1_Header; 59 | void* glyphBuffer; 60 | } PSF1_FONT; 61 | 62 | void BgaSetVideoMode(unsigned int Width, unsigned int Height, unsigned int BitDepth, int UseLinearFrameBuffer, int ClearVideoMemory); 63 | void BgaSetBank(unsigned short BankNumber); 64 | #ifdef __cplusplus 65 | extern "C" { 66 | #endif 67 | void vbe_putpixel(u32 x, u32 y, u32 color); 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | void vbe_fillrect(u32 sx, u32 sy, u32 ex, u32 ey, u32 color); 72 | 73 | void vbe_clear_screen(u8 color); 74 | void vbe_drawline(u32 x1, u32 y1, u32 x2, u32 y2, u8 color); 75 | u32 vbe_getpixel(u32 x, u32 y); 76 | void putchar(int x, int y, char c, PSF1_FONT* font, uint32_t color); 77 | void putchar_custom(int x, int y, char c, PSF1_FONT* font, uint32_t color, uint32_t bg_color, int font_width, int font_height); 78 | void print(const char* str, PSF1_FONT* font, uint32_t color); 79 | void reset_cursor(); 80 | void set_cursor(int x, int y); 81 | 82 | void print_string(const char* str, u32 x, u32 y, u32 color); 83 | void print_chr_line(unsigned int line, u32 x, u32 y, u32 color); -------------------------------------------------------------------------------- /src/drivers/vga.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include "utils.h" 5 | 6 | /* 4-Bit (max. 16) Colour Stuff */ 7 | /* All of them are rendered on a black background (0x0~) */ 8 | #define TC_BLACK 0x00 9 | #define TC_BLUE 0x01 10 | #define TC_GREEN 0x02 11 | #define TC_CYAN 0x03 12 | #define TC_DKRED 0x04 13 | #define TC_MANGT 0x05 14 | #define TC_BROWN 0x06 // <-- More of a darker yellow then brown tbh. 15 | #define TC_WHITE 0x07 // <-- Renders Grey/White Text (Primary Text Style) 16 | #define TC_DGREY 0x08 17 | #define TC_LBLUE 0x09 18 | #define TC_LIME 0x0A 19 | #define TC_LCYAN 0x0B 20 | #define TC_LRED 0x0C 21 | #define TC_PINK 0x0D 22 | #define TC_YELLO 0x0E 23 | #define TC_BRIGHT 0x0F // <-- This makes it actually white and not light grey as used in TC_WHITE 24 | 25 | extern u32 VGA_width; 26 | extern u32 VGA_height; 27 | 28 | void vga_set_char(u32 x, u32 y, u8 ch, u8 color); 29 | void vga_move_cursor(u32 x, u32 y); 30 | void vga_graphics_init(u8 color); 31 | void vga_text_init(u8 color); 32 | void vga_fillrect(u32 sx, u32 sy, u32 ex, u32 ey, u8 color); 33 | void vga_drawchar(unsigned char c, u32 x, u32 y, u8 fgcolor, u8 bgcolor); 34 | void vga_drawline(u32 x1, u32 y1, u32 x2, u32 y2, u8 color); 35 | void vga_putpixel(u32 x, u32 y, u8 color); 36 | u8 vga_getpixel(u32 x, u32 y); 37 | -------------------------------------------------------------------------------- /src/gui/Point.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct { 4 | s32 X; 5 | s32 Y; 6 | } Point; 7 | -------------------------------------------------------------------------------- /src/gui/bitmap/bitmap.c: -------------------------------------------------------------------------------- 1 | #include "Bitmap.h" 2 | #include "../../drivers/vbe.h" 3 | 4 | // Mostly from the internet, modified to fit what we use and our naming and stuff. 5 | void draw_bitmap(int x, int y, const uint8_t *data) { 6 | BITMAPFILEHEADER *file_header = (BITMAPFILEHEADER *)data; 7 | BITMAPINFOHEADER *info_header = (BITMAPINFOHEADER *)(data + sizeof(BITMAPFILEHEADER)); 8 | 9 | // 4D42 is BM in HEX 10 | if(file_header->bfType != 0x4D42) { 11 | // Can't draw an image that isn't a bitmap 12 | return; 13 | } 14 | 15 | int row_size = ((info_header->biBitCount * info_header->biWidth + 31) / 32) * 4; 16 | const uint8_t *pixel_data = data + file_header->bfOffBits; 17 | 18 | for(int _y = 0; _y < abs(info_header->biHeight); _y++) { 19 | for(int _x = 0; _y < info_header->biWidth; _x++) { 20 | int idx = _y * row_size + _x * (info_header->biBitCount / 8); 21 | uint8_t g = pixel_data[idx + 2]; 22 | uint8_t b = pixel_data[idx]; 23 | uint8_t r = pixel_data[idx + 1]; 24 | uint8_t a = 256; 25 | 26 | // RGB -> HEX Red Green Blue Alpha 27 | vbe_putpixel(x + _x, y + _y, ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff) + ((a & 0xff) << 24)); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/gui/bitmap/bitmap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifndef BITMAP_H 6 | #define BITMAP_H 7 | 8 | #pragma pack(push, 1) 9 | typedef struct { 10 | uint16_t bfType; 11 | uint32_t bfSize; 12 | uint16_t bfReserved1; 13 | uint16_t bfReserved2; 14 | uint32_t bfOffBits; 15 | } BITMAPFILEHEADER; 16 | 17 | typedef struct { 18 | uint32_t biSize; 19 | int32_t biWidth; 20 | int32_t biHeight; 21 | uint16_t biPlanes; 22 | uint16_t biBitCount; 23 | uint32_t biCompression; 24 | uint32_t biSizeImage; 25 | int32_t biXPelsPerMeter; 26 | int32_t biYPelsPerMeter; 27 | uint32_t biClrUsed; 28 | uint32_t biClrImportant; 29 | } BITMAPINFOHEADER; 30 | #pragma pack(pop) 31 | 32 | // This has no resizing functionality 33 | void draw_bitmap(int x, int y, const uint8_t *data); 34 | 35 | #endif // BITMAP_H -------------------------------------------------------------------------------- /src/gui/desktop.c: -------------------------------------------------------------------------------- 1 | /* choacury gui */ 2 | #include "desktop.h" 3 | #include "Point.h" 4 | #include "bindraw.h" // <- so I can draw in binary without melting my brain. 5 | #include "../drivers/ps2_keyboard.h" 6 | #include "../drivers/ps2_mouse.h" 7 | #include "../drivers/vbe.h" 8 | #include "window/window.h" 9 | //#include "window/manager/manager.h" 10 | 11 | /* the mouse cursor */ 12 | static uint8_t Cursor[] = { 13 | /* this needs to be some 8 bit binary stuff */ 14 | /* if you're too lazy just chatgpt it */ 15 | 16 | __X_____,________, 17 | __XX____,________, 18 | __X_X___,________, 19 | __X__X__,________, 20 | __X___X_,________, 21 | __X____X,________, 22 | __X_____,X_______, 23 | __X_____,_X______, 24 | __X_____,__X_____, 25 | __X_____,___X____, 26 | __X_____,_XXXX___, 27 | __X__XX_,_X______, 28 | __X_X__X,__X_____, 29 | ___X____,X__X____, 30 | ________,_X__X___, 31 | ________,__XX____ 32 | }; 33 | 34 | static uint32_t MouseCursorBuffer[16 * 16]; 35 | static Point MousePosition; 36 | 37 | void draw_pointer(uint8_t* Cursor, Point position, u8 colour) { 38 | int xMax = 16; 39 | int yMax = 16; 40 | 41 | for (int y = 0; y < yMax && position.Y + y < (s32)1080; y++){ 42 | for (int x = 0; x < xMax && position.X + x < (s32)1920; x++){ 43 | int bit = y * 16 + x; 44 | int byte = bit / 8; 45 | if ((Cursor[byte] & (0b10000000 >> (x % 8)))) { 46 | MouseCursorBuffer[x + y * 16] = vbe_getpixel(position.X + x, position.Y + y); 47 | vbe_putpixel(position.X + x, position.Y + y, colour); 48 | } 49 | } 50 | } 51 | } 52 | 53 | void clear_pointer(uint8_t* Cursor, Point position) { 54 | s32 xMax = 16; 55 | s32 yMax = 16; 56 | 57 | for (s32 y = 0; y < yMax && position.Y + y < (s32)1080; y++) { 58 | for (s32 x = 0; x < xMax && position.X + x < (s32)1920; x++){ 59 | int bit = y * 16 + x; 60 | int byte = bit / 8; 61 | if ((Cursor[byte] & (0b10000000 >> (x % 8)))) { 62 | vbe_putpixel(position.X + x, position.Y + y, MouseCursorBuffer[x + y * 16]); 63 | } 64 | } 65 | } 66 | } 67 | 68 | void test_window_render(int64_t x, int64_t y, int64_t width, uint64_t height) { 69 | uint32_t color = 0x00000000; 70 | 71 | for (uint64_t _y = 0; _y < height; _y++) { 72 | for (uint64_t _x = 0; _x < width; _x++) { 73 | /*color += 0x1; 74 | color += 0x001; 75 | color += 0x0001; 76 | color += 0x00001;*/ 77 | color += 0x111111; 78 | 79 | vbe_putpixel(x + _x, y + _y, color); 80 | } 81 | } 82 | } 83 | 84 | void start_desktop(){ 85 | MousePosition.X = 0; 86 | MousePosition.Y = 0; 87 | vbe_clear_screen(0x000000ff); 88 | vbe_fillrect(0, 0, 20, 20, 0x00ff0000); 89 | 90 | draw_pointer(Cursor, MousePosition, 0x00000000); 91 | 92 | Window window; 93 | window.width = 100; //1000; 94 | window.height = 75; //750; 95 | window.x = 25; 96 | window.y = 25; 97 | window.title = "RGB window"; 98 | window.draw = test_window_render; 99 | window.drag_offset_x = 0; //150; 100 | window.drag_offset_y = 0; //150; 101 | //gui_window_initialise(window); 102 | 103 | //gui_window_render_titlebar(window); 104 | //gui_window_render(window); 105 | gui_window_manager_register_window(window); // This should handle all of the drawing and stuff 106 | 107 | Window window2; 108 | window2.width = 800; 109 | window2.height = 450; 110 | window2.x = 250; 111 | window2.y = 250; 112 | window.title = "RGB Window 2"; 113 | window2.draw = test_window_render; 114 | //gui_window_initialise(window2); 115 | 116 | //gui_window_render(window2); 117 | gui_window_manager_register_window(window2); 118 | 119 | gui_window_move(&window, 26, 26); 120 | 121 | for (;;) { 122 | /* If ESC is pressed, exit the desktop */ 123 | key_event_t key_event; 124 | ps2_get_key_event(&key_event); 125 | if (key_event.key == KEY_Escape) { 126 | break; 127 | } 128 | 129 | /* currently only handle mouse move events */ 130 | mouse_event_t mouse_event; 131 | ps2_get_mouse_event(&mouse_event); 132 | 133 | switch (mouse_event.type) 134 | { 135 | case MOUSE_EVENT_NONE: 136 | /* wait for new event */ 137 | asm volatile("hlt"); 138 | break; 139 | case MOUSE_BUTTON_EVENT: 140 | if (mouse_event.button_event.pressed) { 141 | gui_window_manager_handle_mouse_click(MousePosition.X, MousePosition.Y); 142 | 143 | if (MousePosition.X >= 0 && MousePosition.X < 20) { 144 | if (MousePosition.Y >= 0 && MousePosition.Y < 20) { 145 | /* does something if the boxed is clicked on */ 146 | vbe_fillrect(75, 75, 120, 90, 0x00964B00); 147 | } 148 | } 149 | } 150 | break; 151 | case MOUSE_MOVE_EVENT: 152 | clear_pointer(Cursor, MousePosition); 153 | MousePosition.X += mouse_event.move_event.rel_x; 154 | MousePosition.Y -= mouse_event.move_event.rel_y; 155 | draw_pointer(Cursor, MousePosition, 0x00000000); 156 | 157 | gui_window_manager_handle_mouse_move(MousePosition.X, MousePosition.Y); 158 | break; 159 | default: 160 | break; 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/gui/desktop.cpp: -------------------------------------------------------------------------------- 1 | #include "desktop.h" 2 | extern "C" { 3 | #include "Point.h" 4 | #include "bindraw.h" // <- so I can draw in binary without melting my brain. 5 | #include "../drivers/ps2_keyboard.h" 6 | #include "../drivers/ps2_mouse.h" 7 | #include "../drivers/vbe.h" 8 | #include "window/window.hpp" 9 | #include "window/manager/manager.hpp" 10 | } 11 | 12 | // Cursor 13 | static uint8_t Cursor[] = { 14 | __X_____,________, 15 | __XX____,________, 16 | __X_X___,________, 17 | __X__X__,________, 18 | __X___X_,________, 19 | __X____X,________, 20 | __X_____,X_______, 21 | __X_____,_X______, 22 | __X_____,__X_____, 23 | __X_____,___X____, 24 | __X_____,_XXXX___, 25 | __X__XX_,_X______, 26 | __X_X__X,__X_____, 27 | ___X____,X__X____, 28 | ________,_X__X___, 29 | ________,__XX____ 30 | }; 31 | 32 | static uint32_t MouseCursorBuffer[16 * 16]; 33 | static Point MousePosition; 34 | 35 | /// @brief Draw the cursor to the screen 36 | /// @param Cursor The cursor 37 | /// @param position Where on the screen 38 | /// @param colour What colour is it (0x00000000) 39 | void draw_pointer(uint8_t* Cursor, Point position, u8 colour) { 40 | int xMax = 16; 41 | int yMax = 16; 42 | 43 | for (int y = 0; y < yMax && position.Y + y < (s32)1080; y++){ 44 | for (int x = 0; x < xMax && position.X + x < (s32)1920; x++){ 45 | int bit = y * 16 + x; 46 | int byte = bit / 8; 47 | if ((Cursor[byte] & (0b10000000 >> (x % 8)))) { 48 | MouseCursorBuffer[x + y * 16] = vbe_getpixel(position.X + x, position.Y + y); 49 | vbe_putpixel(position.X + x, position.Y + y, colour); 50 | } 51 | } 52 | } 53 | } 54 | 55 | /// @brief Clear the cursor from the screen 56 | /// @param Cursor The cursor (Same on as used in `draw_pointer`) 57 | /// @param position Where on the screen 58 | void clear_pointer(uint8_t* Cursor, Point position) { 59 | s32 xMax = 16; 60 | s32 yMax = 16; 61 | 62 | for (s32 y = 0; y < yMax && position.Y + y < (s32)1080; y++) { 63 | for (s32 x = 0; x < xMax && position.X + x < (s32)1920; x++){ 64 | int bit = y * 16 + x; 65 | int byte = bit / 8; 66 | if ((Cursor[byte] & (0b10000000 >> (x % 8)))) { 67 | vbe_putpixel(position.X + x, position.Y + y, MouseCursorBuffer[x + y * 16]); 68 | } 69 | } 70 | } 71 | } 72 | 73 | /// @brief Initializes the desktop 74 | extern "C" void start_desktop() { 75 | // Reset mouse coords 76 | MousePosition.X = 0; 77 | MousePosition.Y = 0; 78 | 79 | // Clear the screen with a blue colour 80 | vbe_clear_screen(0x000000ff); 81 | 82 | // Draw the cursor 83 | draw_pointer(Cursor, MousePosition, 0x00000000); 84 | 85 | FallBackWM wm = FallBackWM(); 86 | 87 | Window window = Window(10, 10, 500, 500, WindowStyle::Standard, WindowState::Open, (char**)"Test"); 88 | wm.render_base(&window); 89 | window.render(); // The WM will deal with getting this part set up 90 | 91 | wm.register_window(&window); 92 | wm.make_window_active(1); 93 | 94 | print_string("Test", 10, 510, 0x00ffffff); // Test text 95 | 96 | for(;;) { 97 | // Handle keyboard events 98 | key_event_t key_event; 99 | ps2_get_key_event(&key_event); 100 | if(key_event.key == KEY_Escape) { 101 | break; 102 | } 103 | 104 | mouse_event_t mouse_event; 105 | ps2_get_mouse_event(&mouse_event); 106 | 107 | wm.handle_mouse_event(mouse_event, MousePosition.X, MousePosition.Y); 108 | 109 | switch(mouse_event.type) { 110 | case MOUSE_EVENT_NONE: 111 | // No mouse event, do nothing 112 | asm volatile("hlt"); 113 | break; 114 | case MOUSE_BUTTON_EVENT: 115 | if(mouse_event.button_event.pressed) { 116 | // Pass to basic window manager for it to deal with it 117 | //window.move(MousePosition.X, MousePosition.Y); 118 | } 119 | break; 120 | case MOUSE_MOVE_EVENT: 121 | // Clear and redraw the cursor in the new mouse position 122 | clear_pointer(Cursor, MousePosition); 123 | MousePosition.X += mouse_event.move_event.rel_x; 124 | MousePosition.Y -= mouse_event.move_event.rel_y; 125 | //draw_pointer(Cursor, MousePosition, 0x00000000); 126 | draw_pointer(Cursor, MousePosition, 0xFFFFFF00); 127 | break; 128 | default: 129 | break; 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /src/gui/desktop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../drivers/types.h" 4 | 5 | //extern "C" { 6 | //void start_desktop(); 7 | //void LMB(); 8 | //} 9 | 10 | #ifndef DESKTOP_H 11 | #define DESKTOP_H 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | void start_desktop(); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif // DESKTOP_H 24 | -------------------------------------------------------------------------------- /src/gui/pfont.h: -------------------------------------------------------------------------------- 1 | /* Choacurys Standard and Small Monospace font */ 2 | /* made for the GUI */ 3 | 4 | /* we probs need more includes then this lol */ 5 | #include "bindraw.h" 6 | 7 | /* add character maps here 8 | * We need 9 | * - All 27 letters of the Latin alphabet (both Upper and lower case) 10 | * - Numbers 0-9 11 | * - And some extra symbols like puncs. 12 | */ -------------------------------------------------------------------------------- /src/gui/window/headers/bitmap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma pack(push, 1) 4 | struct BITMAPFILEHEADER { 5 | uint16_t bfType; 6 | uint32_t bfSize; 7 | uint16_t bfReserved1; 8 | uint16_t bfReserved2; 9 | uint32_t bfOffBits; 10 | }; 11 | 12 | struct BITMAPINFOHEADER { 13 | uint32_t biSize; 14 | int32_t biWidth; 15 | int32_t biHeight; 16 | uint16_t biPlanes; 17 | uint16_t biBitCount; 18 | uint32_t biCompression; 19 | uint32_t biSizeImage; 20 | int32_t biXPelsPerMeter; 21 | int32_t biYPelsPerMeter; 22 | uint32_t biClrUsed; 23 | uint32_t biClrImportant; 24 | }; 25 | #pragma pack(pop) -------------------------------------------------------------------------------- /src/gui/window/headers/rim.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma pack(push, 1) 4 | struct RIMFILEHEADER { 5 | uint16_t bfType; 6 | uint32_t bfSize; 7 | uint16_t bfReserved1; 8 | uint16_t bfReserved2; 9 | uint32_t bfOffBits; 10 | }; 11 | 12 | struct RIMINFOHEADER { 13 | uint32_t biSize; 14 | int32_t biWidth; 15 | int32_t biHeight; 16 | uint16_t biPlanes; 17 | uint16_t biBitCount; 18 | uint32_t biCompression; 19 | uint32_t biSizeImage; 20 | int32_t biXPelsPerMeter; 21 | int32_t biYPelsPerMeter; 22 | uint32_t biClrUsed; 23 | uint32_t biClrImportant; 24 | }; 25 | #pragma pack(pop) -------------------------------------------------------------------------------- /src/gui/window/manager/manager.c.old: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../window.h" 3 | 4 | void gui_window_manager_register_window(Window window) { 5 | for (int32_t i = 0; i < sizeof(windows); i++) 6 | { 7 | if(*windows[i] == NULL) { 8 | windows[i] = &window; 9 | active_window = &window; 10 | gui_window_render(window); 11 | return 1; 12 | } 13 | } 14 | return 0; 15 | } 16 | 17 | int gui_window_manager_mouse_over_titlebar(Window* window, int mouse_x, int mouse_y) { 18 | if(mouse_x >= window->x && mouse_x <= window->x + window->width) { 19 | if(mouse_y >= window->y && mouse_y <= window->y + TITLEBAR_HEIGHT) { 20 | return 1; 21 | } 22 | } 23 | return 0; 24 | } 25 | 26 | void gui_window_manager_handle_mouse_move(int mouse_x, int mouse_y) { 27 | if(active_window != NULL) { 28 | if(active_window->is_dragging == 1) { 29 | int64_t new_x = mouse_x - active_window->drag_offset_x; 30 | int64_t new_y = mouse_y - active_window->drag_offset_y; 31 | 32 | //gui_window_move(&active_window, new_x, new_y); 33 | 34 | if(active_window->move) { 35 | //active_window->move(new_x, new_y); 36 | } 37 | 38 | //gui_window_render(*active_window); 39 | } 40 | } 41 | } 42 | 43 | void gui_window_manager_handle_mouse_click(int mouse_x, int mouse_y) { 44 | gui_window_move(active_window, 25, 25); 45 | 46 | if(active_window != NULL) { 47 | if(gui_window_manager_mouse_over_titlebar(&active_window, mouse_x, mouse_y) == 1) { 48 | if(active_window->is_dragging) { 49 | active_window->is_dragging = 0; 50 | } else { 51 | active_window->is_dragging = 1; 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/gui/window/manager/manager.cpp: -------------------------------------------------------------------------------- 1 | #include "../window.hpp" 2 | #include "manager.hpp" 3 | #include "../gui.hpp" 4 | #include "../icons.hpp" 5 | 6 | using namespace GUI; 7 | 8 | void FallBackWM::register_window(Window* window) { 9 | this->windows[this->window_count + 1] = *window; 10 | this->window_count++; 11 | } 12 | 13 | void FallBackWM::render_base(Window* window) { 14 | int titlebar_height = 30; 15 | 16 | fill_rect(window, uRect32(0, 0, window->width, titlebar_height), 0x8A8A8A00); 17 | rect(window, uRect32(0, 0, window->width, window->height), 0x8A8A8A00); 18 | 19 | fill_rect(window, uRect32(window->width - 25, 5, 20, 20), 0xFF0000); 20 | fill_rect(window, uRect32(window->width - (25 + 5 + 25), 5, 20, 20), 0xFFFF00); 21 | fill_rect(window, uRect32(window->width - (25 + 5 + 25 + 5 + 25), 5, 20, 20), 0x00FF00); 22 | 23 | PSF1_FONT default_font; 24 | Utils::data_to_psf1(&default_font, unifont); 25 | 26 | draw_text(window, uText((char*)window->title, 5, 5, &default_font, 0x00FFFFFF)); // Doesn't do anything for some reason 27 | 28 | //draw_rim(window, uRIM(window->width - 25, 5, minimise_rim_data)); 29 | //draw_rim(window, uRIM(window->width - (25 + 5 + 25), 5, maximise_rim_data)); 30 | //draw_rim(window, uRIM(window->width - (25 + 5 + 25 + 5 + 25), 5, close_rim_data)); 31 | 32 | // Testing 33 | draw_line(window, uPoint32(0, 30), uPoint32(500, 500), 0xFFFFFF); 34 | rect(window, uRect32(10, 10 + 30, 100, 100), 0xFF0000); 35 | fill_rect(window, uRect32(10 + 110, 10 + 30, 100, 100), 0xFF0000); 36 | draw_circle(window, uCircle32(10, 10 + 30 + 110, 50), 0x00FF00); 37 | draw_filled_circle(window, uCircle32(10 + 110, 10 + 30 + 110, 50), 0x00FF00); 38 | draw_line(window, uPoint32(0, 500), uPoint32(500, 30), 0xFFFFFF); 39 | 40 | draw_text(window, uText("Test", 5, 35, &default_font, 0x00FF0000)); 41 | } 42 | 43 | void FallBackWM::handle_mouse_event(mouse_event_t mouse_event, int32_t mouse_x, int32_t mouse_y) { 44 | int titlebar_height = 30; 45 | Window* active_window = &this->windows[this->active_window]; 46 | 47 | if(mouse_event.type == MOUSE_MOVE_EVENT) { 48 | if(mouse_x >= active_window->x && mouse_x < active_window->x + active_window->width) { 49 | if(mouse_y >= active_window->y && mouse_y < active_window->y + active_window->height) { 50 | active_window->handle_mouse_move(mouse_x, mouse_y); 51 | } 52 | } 53 | } else if(mouse_event.type == MOUSE_BUTTON_EVENT) { 54 | if(mouse_event.button_event.button == mouse_button_t::LEFT) { 55 | if(mouse_x >= active_window->x + active_window->width - 25 && 56 | mouse_x < active_window->x + active_window->width - 5) { 57 | if(mouse_y >= active_window->y + 5 && 58 | mouse_y < active_window->y + 25) { 59 | active_window->~Window(); 60 | // Unregister window 61 | } 62 | } else if(GUI::point_in_rect(uPoint32(mouse_x, mouse_y), uRect32(active_window->width - (25 + 5 + 25), 5, 20, 20))) { 63 | if(active_window->state == WindowState::Open) { 64 | active_window->change_state(WindowState::Maximized); 65 | if(active_window->style == WindowStyle::Standard) render_base(active_window); 66 | } else { 67 | active_window->change_state(WindowState::Open); 68 | if(active_window->style == WindowStyle::Standard) render_base(active_window); 69 | } 70 | } else { 71 | if(mouse_x >= active_window->x && mouse_x < active_window->x + active_window->width) { 72 | if(mouse_y >= active_window->y && mouse_y < active_window->y + titlebar_height) { 73 | if(active_window->state == WindowState::Fullscreen || WindowState::Maximized) return; 74 | if(active_window->is_dragging) { 75 | active_window->end_drag(); 76 | } else { 77 | active_window->set_drag_offset(active_window->x - mouse_x, active_window->y - mouse_y); 78 | active_window->begin_drag(); 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | 87 | void FallBackWM::make_window_active(uint32_t index) { 88 | this->active_window = index; 89 | } -------------------------------------------------------------------------------- /src/gui/window/manager/manager.hpp: -------------------------------------------------------------------------------- 1 | #include "../window.hpp" 2 | extern "C" { 3 | #include "../../../drivers/ps2_mouse.h" 4 | #include "../../../drivers/ps2_keyboard.h" 5 | } 6 | 7 | class WindowManager { 8 | private: 9 | Window* windows; 10 | size_t window_count; 11 | int32_t active_window; // -1 for none 12 | public: 13 | /// @brief Handles a mouse event 14 | /// @param mouse_event The mouse event 15 | /// @param mouse_position The mouse position 16 | void handle_mouse_event(mouse_event_t mouse_event, int32_t mouse_x, int32_t mouse_y); 17 | /// @brief Handles a key event 18 | /// @param key_event The key event 19 | void handle_key_event(key_event_t key_event); 20 | /// @brief Registers a window 21 | /// @param window The window 22 | void register_window(Window* window); 23 | }; 24 | 25 | class FallBackWM : WindowManager { 26 | private: 27 | Window* windows; 28 | size_t window_count; 29 | int32_t active_window; // -1 for none 30 | public: 31 | /// @brief Handles a mouse event 32 | /// @param mouse_event The mouse event 33 | /// @param mouse_position The mouse position 34 | void handle_mouse_event(mouse_event_t mouse_event, int32_t mouse_x, int32_t mouse_y); 35 | /// @brief Handles a key event 36 | /// @param key_event The key event 37 | void handle_key_event(key_event_t key_event); 38 | /// @brief Registers a window 39 | /// @param window The window 40 | void register_window(Window* window); 41 | /// @brief Renders the base fallback wm layout on the window buffer 42 | /// @param window The window 43 | void render_base(Window* window); 44 | /// @brief Sets the active window 45 | /// @param index The index of the active window 46 | void make_window_active(uint32_t index); 47 | }; -------------------------------------------------------------------------------- /src/gui/window/window.c.old: -------------------------------------------------------------------------------- 1 | #include "../../drivers/vbe.h" 2 | #include "../../shell/shell.h" 3 | #include "../../drivers/filesystem/fat.h" 4 | #include "../../memory/kmalloc.h" 5 | #include "../../drivers/utils.h" 6 | #include "../bitmap/bitmap.h" 7 | #include "window.h" 8 | 9 | //#define TITLEBAR_HEIGHT 30 // Moved to window.h 10 | 11 | void gui_window_render_titlebar(Window window) { 12 | vbe_fillrect(window.x, window.y, window.x + window.width, window.y + TITLEBAR_HEIGHT, 0x8A8A8A00); // Titlebar 13 | vbe_drawline(window.x, window.y, window.x, window.y + window.height, 0x8A8A8A00); // Top left -> Bottom left 14 | vbe_drawline(window.x, window.y, window.x + window.width, window.y, 0x8A8A8A00); // Top left -> Top right 15 | vbe_drawline(window.x, window.y + window.height, window.x + window.width, window.x + window.height, 0x8A8A8A00); // Bottom left -> Bottom right 16 | vbe_drawline(window.x + window.width, window.y, window.x + window.width, window.y + window.height, 0x8A8A8A00); // Top right -> Bottom right 17 | 18 | vbe_fillrect(window.x + 1, window.y + TITLEBAR_HEIGHT, window.x + window.width, window.y + window.height, 0x000000); 19 | 20 | //vbe_fillrect(window.x + window.width - (titlebar_height / 3), window.y + (titlebar_height / 3), window.x + window.width - (titlebar_height / 3) - 40, window.y + (titlebar_height / 3 * 2), 0xFF0000); 21 | vbe_fillrect(window.x + 5, window.y + 5, window.x + 20, window.y + 5, 0xFF0000); 22 | 23 | size_t title_length = sizeof(window.title); 24 | for(int i = 0; i < title_length; i++) { 25 | // 0xff is transparent 26 | putchar_custom(window.x + 3 + (9 * i), window.y + 3, window.title[i], font, 0xFFFFFF, 0xff, 8, 20); 27 | } 28 | 29 | FAT_file_t* test = FAT_OpenAbsolute(s_fat_fs, "/test.bmp"); 30 | void* testData = (void*)kmalloc(sizeof(test->file_size)); 31 | FAT_Read(testData, 0, 0, sizeof(test->file_size)); 32 | draw_bitmap(window.x + 10, window.y + 10, testData); 33 | } 34 | 35 | void gui_window_render(Window window) { 36 | gui_window_render_titlebar(window); 37 | //window.draw(window.x, window.y + TITLEBAR_HEIGHT, window.x + window.width, window.y + 30 + window.height); 38 | window.draw(window.x + 1, window.y + TITLEBAR_HEIGHT, window.width - 1, window.height - TITLEBAR_HEIGHT); 39 | } 40 | 41 | int gui_window_move(Window* window, int64_t new_x, int64_t new_y) { 42 | vbe_fillrect(window->x, window->y, window->width, window->height, 0x000000ff); 43 | 44 | window->x = new_x; 45 | window->y = new_y; 46 | 47 | gui_window_render(*window); 48 | 49 | return 1; 50 | } 51 | 52 | void gui_window_initialise(Window window) { 53 | 54 | } 55 | 56 | void gui_window_resize(Window window, int width, int height) { 57 | 58 | } -------------------------------------------------------------------------------- /src/gui/window/window.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include "../../drivers/vbe.h" 3 | #include "../../shell/shell.h" 4 | #include "../../drivers/filesystem/fat.h" 5 | #include "../../memory/kmalloc.h" 6 | #include "../../drivers/utils.h" 7 | #include "../bitmap/bitmap.h" 8 | } 9 | #include "window.hpp" 10 | 11 | inline void* operator new(size_t size) { return kmalloc(size); } 12 | 13 | Window::~Window() { 14 | this->derender(); 15 | kfree(this); 16 | } 17 | 18 | void Window::change_state(WindowState state) { 19 | this->state = state; 20 | if(state == WindowState::Maximized) { 21 | this->mm_x = this->x; 22 | this->mm_y = this->y; 23 | this->mm_width = this->width; 24 | this->mm_height = this->height; 25 | 26 | // This part needs to be more dynamic when we get mutliple sizes for vbe.c 27 | this->x = 0; 28 | this->y = 0; 29 | this->width = 1920; 30 | this->height = 1080; 31 | } else { 32 | this->x = this->mm_x; 33 | this->y = this->mm_y; 34 | this->width = this->mm_width; 35 | this->height = this->mm_height; 36 | } 37 | this->derender(); 38 | this->render(); 39 | } 40 | 41 | void Window::change_style(WindowStyle style) { 42 | this->style = style; 43 | } 44 | 45 | void Window::set_drag_offset(int32_t x, int32_t y) { 46 | this->drag_offset_x = x; 47 | this->drag_offset_y = y; 48 | } 49 | 50 | bool Window::move(int64_t x, int64_t y) { 51 | // De-render, move, render 52 | this->derender(); 53 | this->x = x; 54 | this->y = y; 55 | this->render(); 56 | return true; 57 | } 58 | 59 | bool Window::resize(int64_t width, int64_t height) { 60 | // (If new size smaller) De-render, reallocate buffer, render 61 | if(this->width > width || this->height > height) this->derender(); 62 | // Initialize the buffer 63 | buffer = (uint32_t*)kmalloc(width * height * sizeof(uint32_t)); 64 | 65 | // Clear it (Sometimes random data can be left behind) 66 | for(int64_t y = 0; y < this->height; y++) { 67 | for(int64_t x = 0; x < this->width; x++) { 68 | // Clear the buffer with black 69 | this->buffer[y * this->width + x] = 0x0; 70 | } 71 | } 72 | 73 | // Tell it to render 74 | render(); 75 | // Return success 76 | return true; 77 | } 78 | 79 | bool Window::render() { 80 | // If the buffer is empty, do nothing 81 | if(this->buffer == nullptr) return false; 82 | // Draw each pixel on the screen 83 | for(int64_t y = 0; y < this->height; y++) { 84 | for(int64_t x = 0; x < this->width; x++) { 85 | vbe_putpixel(this->x + x, this->y + y, this->buffer[y * this->width + x]); 86 | } 87 | } 88 | // Return success 89 | return true; 90 | } 91 | 92 | bool Window::render_part(int32_t _x, int32_t _y, int32_t width, int32_t height) { 93 | // If the buffer is empty, do nothing 94 | if(this->buffer == nullptr) return false; 95 | if(_x > this->width || _x < 0 || _y > this->height || _y < 0) return false; 96 | 97 | // Draw each pixel on the screen 98 | for(int64_t y = _y; y < height; y++) { 99 | for(int64_t x = _x; x < width; x++) { 100 | vbe_putpixel(this->x + x, this->y + y, this->buffer[y * this->width + x]); 101 | } 102 | } 103 | // Return success 104 | return true; 105 | } 106 | 107 | bool Window::derender() { 108 | // Replace everything with the default background colour 109 | // This needs to be done in future by figuring out if 110 | // anything needs to be drawn that is below it. 111 | vbe_fillrect(this->x, this->y, this->x + this->width, this->y + this->height, 0x000000ff); 112 | return true; 113 | } 114 | 115 | bool Window::begin_drag() { 116 | // This needs to be set (Even if it's set to 0) 117 | if(drag_offset_x == -1 || drag_offset_y == -1) { 118 | return false; 119 | } 120 | this->is_dragging = true; 121 | return true; 122 | } 123 | 124 | bool Window::end_drag() { 125 | this->is_dragging = false; 126 | return true; 127 | } 128 | 129 | void Window::handle_mouse_move(int32_t x, int32_t y) { 130 | if(this->is_dragging) { 131 | this->move(x + this->drag_offset_x, y + this->drag_offset_y); 132 | } 133 | } 134 | 135 | void Window::handle_mouse_press() { 136 | // For anything like buttons 137 | // (You can use set_drag_offset, which SHOULD be set when the mouse goes over the window) 138 | } 139 | 140 | void Window::handle_key_pressed(char key) { 141 | // No keyboard functionality as of now 142 | } -------------------------------------------------------------------------------- /src/gui/window/window.h.old: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define TITLEBAR_HEIGHT 30 4 | 5 | typedef enum { 6 | Standard, 7 | None 8 | } WindowStyle; 9 | 10 | typedef struct { 11 | int64_t x; 12 | int64_t y; 13 | uint64_t width; 14 | uint64_t height; 15 | WindowStyle style; 16 | char* title; 17 | int should_draw; // 1 = Yes, 0 = No 18 | int is_dragging; 19 | int drag_offset_x; 20 | int drag_offset_y; 21 | 22 | void (*destroy)(); 23 | void (*draw)(int64_t, int64_t, int64_t, uint64_t); 24 | void (*update)(); 25 | int (*move)(int64_t, int64_t); 26 | void (*maximise)(); 27 | void (*minimise)(); 28 | int (*resize)(int64_t, int64_t); 29 | } Window; 30 | 31 | void gui_window_initialise(Window window); 32 | void gui_window_resize(Window window, int width, int height); 33 | void gui_window_render_titlebar(Window window); 34 | void gui_window_render(Window window); // This will render the titlebar and then the draw function 35 | int gui_window_move(Window* window, int64_t new_x, int64_t new_y); 36 | 37 | // Drawing.h 38 | //uint32_t gui_window_getpixel(Window window, uint32_t x, uint32_t y); 39 | //void gui_window_drawline(Window window, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t color); 40 | //void gui_window_fillrect(Window window, uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t color); 41 | //void gui_window_putpixel(Window window, u32 x, u32 y, u32 color); 42 | 43 | // Manager.h 44 | static Window** windows[15]; 45 | static Window* active_window = NULL; 46 | 47 | void gui_window_manager_register_window(Window window); 48 | int gui_window_manager_mouse_over_titlebar(Window* window, int mouse_x, int mouse_y); 49 | void gui_window_manager_handle_mouse_move(int mouse_x, int mouse_y); 50 | void gui_window_manager_handle_mouse_click(int mouse_x, int mouse_y); -------------------------------------------------------------------------------- /src/gui/window/window.hpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include 3 | } 4 | 5 | #ifndef WINDOW_H 6 | #define WINDOW_H 7 | 8 | #define TITLEBAR_HEIGHT 30 9 | 10 | typedef enum { 11 | Standard, 12 | None 13 | } WindowStyle; 14 | 15 | typedef enum { 16 | Minimized, // Don't render 17 | Maximized, // Render with a border but fullscreen (Check `WindoeStyle` first though) 18 | Fullscreen, 19 | Open // Not Maximized nor fullscreen, just open 20 | } WindowState; 21 | 22 | class Window { 23 | public: 24 | // Normal 25 | int64_t x; 26 | int64_t y; 27 | int64_t width; 28 | int64_t height; 29 | // Maximized 30 | int64_t mm_x; 31 | int64_t mm_y; 32 | int64_t mm_width; 33 | int64_t mm_height; 34 | WindowStyle style; 35 | WindowState state; 36 | char** title; 37 | bool is_dragging = false; 38 | int32_t drag_offset_x = -1; 39 | int32_t drag_offset_y = -1; 40 | uint32_t* buffer = nullptr; 41 | 42 | /// @brief Window initializer 43 | /// @param _x Window position (X) 44 | /// @param _y Window position (Y) 45 | /// @param _width Window size (Width) 46 | /// @param _height Window size (height) 47 | /// @param _style Window style 48 | /// @param _state Windows state 49 | Window(int64_t _x, int64_t _y, 50 | int64_t _width, int64_t _height, 51 | WindowStyle _style, WindowState _state, 52 | char** _title) { 53 | x = _x; 54 | y = _y; 55 | width = _width; 56 | height = _height; 57 | style = _style; 58 | state = _state; 59 | 60 | //buffer = new uint32_t[_width * _height]; 61 | resize(_width, _height); 62 | } 63 | /// @brief Window deinitializer 64 | ~Window(); 65 | /// @brief Changes the window state 66 | /// @param state The new window state 67 | void change_state(WindowState state); 68 | /// @brief Changes the window style 69 | /// @param style The new window style 70 | void change_style(WindowStyle style); 71 | /// @brief Moves the window to the new coordinates 72 | /// @param x The new X 73 | /// @param y The new Y 74 | /// @return If it was successful or not 75 | bool move(int64_t x, int64_t y); 76 | /// @brief Resizes the window 77 | /// @param width The new width 78 | /// @param height The new height 79 | /// @return Ifi t was successful or not 80 | bool resize(int64_t width, int64_t height); 81 | /// @brief Renders the window on the screen 82 | /// @return If it was successful or not 83 | bool render(); 84 | /// @brief De-renders (Removes) the window from the screen 85 | /// @return If it was successful or not 86 | /// @note This only sets every pixel to 0x000000ff, needs to be done properly in future 87 | bool derender(); 88 | /// @brief Renders a specific part of the window on the screen 89 | /// @param x Start position (x) 90 | /// @param y Start position (y) 91 | /// @param width End position (width) 92 | /// @param height End position (height) 93 | bool render_part(int32_t _x, int32_t _y, int32_t width, int32_t height); 94 | // Dragging functionality 95 | /// @brief Sets the drag offset 96 | /// @param x The X drag offset 97 | /// @param y The Y drag offset 98 | /// @note This could be set to the relative coordinates of the mouse over the window so that the window doesn't just teleport to (0, 0) 99 | void set_drag_offset(int32_t x, int32_t y); 100 | /// @brief Begins dragging 101 | /// @returns If it was successful or not 102 | /// @attention You need to use set_drag_offset (Even if you just set it to 0) 103 | bool begin_drag(); 104 | /// @brief Ends dragging 105 | /// @return If it was successful or not 106 | bool end_drag(); 107 | // Mouse functionality 108 | /// @brief Handles a mouse move event 109 | /// @param x The X coordinate of the mouse 110 | /// @param y The Y coordinate of the mouse 111 | void handle_mouse_move(int32_t x, int32_t y); 112 | /// @brief Handles a mouse press event 113 | void handle_mouse_press(); 114 | // Keyboard functionality (Not implemented immidiately) 115 | /// @brief Handles a keyboard key event 116 | /// @param key The key that was pressed 117 | void handle_key_pressed(char key); 118 | }; 119 | 120 | #endif // WINDOW_H -------------------------------------------------------------------------------- /src/kernel/gdt.asm: -------------------------------------------------------------------------------- 1 | gdt_nulldesc: 2 | dd 0 3 | dd 0 4 | gdt_codedesc: 5 | dw 0xFFFF ; Limit 6 | dw 0x0000 ; Base (low) 7 | db 0x00 ; Base (medium) 8 | db 10011010b ; Flags 9 | db 11001111b ; Flags + Upper Limit 10 | db 0x00 ; Base (high) 11 | gdt_datadesc: 12 | dw 0xFFFF 13 | dw 0x0000 14 | db 0x00 15 | db 10010010b 16 | db 11001111b 17 | db 0x00 18 | 19 | gdt_end: 20 | 21 | gdt_descriptor: 22 | gdt_size: 23 | dw gdt_end - gdt_nulldesc - 1 24 | dd gdt_nulldesc 25 | 26 | codeseg equ gdt_codedesc - gdt_nulldesc 27 | dataseg equ gdt_datadesc - gdt_nulldesc -------------------------------------------------------------------------------- /src/kernel/kernel special stuff.txt: -------------------------------------------------------------------------------- 1 | NOTES: These contain string characters that can be used in any C string code in Choacury! 2 | All of these characters are from the Code page 437 (CCSID 437) character set, which can be seen in 3 | many versions of DOS. 4 | 5 | https://en.wikipedia.org/wiki/Code_page_437 6 | 7 | =================================================================================================== 8 | \n - New Line 9 | \1 - Happy Face (HEX 0x1) 10 | \2 - Happy Face (HEX 0x2) 11 | \3 - Heart (HEX 0x3) 12 | \4 - Diamond (HEX 0x4) 13 | \5 - Clubs (HEX 0x5) 14 | \6 - Spades (HEX 0x6) 15 | \7 - Dot (HEX 0x7) -------------------------------------------------------------------------------- /src/kernel/kernel.asm: -------------------------------------------------------------------------------- 1 | [org 0x7e00] 2 | jmp protectedmode 3 | 4 | %include "src/kernel/gdt.asm" ; Make sure its the exact location of the GDT file 5 | 6 | protectedmode: 7 | call EnableA20 8 | cli 9 | lgdt [gdt_descriptor] 10 | mov eax, cr0 11 | or eax, 1 12 | mov cr0, eax 13 | jmp codeseg:StartProtectedMode 14 | 15 | EnableA20: ;using FAST A20 16 | in al, 0x92 17 | or al, 2 18 | out 0x92, al 19 | ret 20 | [bits 32] 21 | [extern _main] 22 | StartProtectedMode: 23 | mov [0xb8000], byte 'X' 24 | 25 | ; Enable SSE 26 | ;; Set CR4.OSFXSR 27 | mov eax, cr4 28 | or eax, (1 << 9) 29 | mov cr4, eax 30 | 31 | ;; Disable CR0.EM 32 | mov eax, cr0 33 | and eax, ~(1 << 2) 34 | mov cr0, eax 35 | 36 | ;; Enable CR0.MP 37 | mov eax, cr0 38 | or eax, (1 << 1) 39 | mov cr0, eax 40 | 41 | ;; Clear CR0.TS 42 | mov eax, cr0 43 | and eax, ~(1 << 3) 44 | mov cr0, eax 45 | 46 | ; Now we should have SSE enabled. 47 | 48 | jmp _main 49 | ; We can now access up to 0xFFFFFFF0 memory (~4GB!) instead of 1MB (0xFFFFF) 50 | jmp $ 51 | 52 | 53 | times 2048-($-$$) db 0 ; allocate ≈2kb for the kernel 54 | ; Why this works is because memory from 0x7e00 -- 0x9fc00 is free (~638KB) 55 | ; and i think that GDT is mapped to the 2KB area and if we load more GDT will 56 | ; freak out and triple fault the CPU. -------------------------------------------------------------------------------- /src/kernel/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | The kernel of Choacury 3 | I call it the Choakern! The code still needs to be finished tho... 4 | */ 5 | 6 | /* Includes needed for the kernel to actually work.*/ 7 | #include "../drivers/gdt.h" 8 | #include "../drivers/idt.h" 9 | #include "../drivers/keymaps/ps2_keymap_us.h" // <-- US Keyboard Layout. 10 | #include "../drivers/mouse.h" 11 | #include "../drivers/pci.h" 12 | #include "../drivers/pic.h" 13 | #include "../drivers/pit.h" 14 | #include "../drivers/ports.h" 15 | #include "../drivers/ps2.h" 16 | #include "../drivers/sound.h" 17 | #include "../drivers/storage/device.h" 18 | #include "../drivers/types.h" 19 | #include "../drivers/utils.h" 20 | #include "../drivers/vga.h" 21 | //#include "../drivers/fat.h" 22 | #include "../memory/kmalloc.h" 23 | #include "../memory/pmm.h" 24 | #include "../shell/shell.h" 25 | #include "../shell/terminal.h" 26 | #include "multiboot.h" 27 | #include "panic.h" 28 | #include "process.h" 29 | 30 | extern void (*__init_array[])(); 31 | extern void (*__init_array_end[])(); 32 | 33 | /* Startup Beep*/ 34 | void StartUp_Beeps() { 35 | startbeep(450); 36 | pit_sleep_ms(100); 37 | mutebeep(); 38 | startbeep(775); 39 | pit_sleep_ms(50); 40 | mutebeep(); 41 | } 42 | 43 | /* A Simple kernel written in C 44 | * These parameters are pushed onto the stack by the assembly kernel entry file. 45 | */ 46 | 47 | void k_main(multiboot_info_t* mbd, uint32_t magic) { 48 | gdt_init(); 49 | idt_init(); 50 | kmalloc_init(); 51 | 52 | vga_text_init(TC_BLACK); 53 | 54 | u32 term_width = VGA_width; // Set this to the width of your VGA text mode 55 | u32 visible_height = VGA_height; // Set this to the height of your VGA text mode (visible height) 56 | u32 buffer_height = visible_height + 100; // Set this to a height larger than visible to allow scrolling 57 | 58 | term_init(term_width, buffer_height, visible_height, vga_set_char, vga_move_cursor); 59 | 60 | term_write("\n\xB0\xB1\xB2\xDB Welcome to Choacury! \xDB\xB2\xB1\xB0\n", TC_LIME); 61 | term_write("Version: Build " __DATE__ " (GUI Testing)\n", TC_WHITE); 62 | term_write("(C)opyright: \2 Pineconium 2023-2025.\n\n", TC_WHITE); 63 | 64 | if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { 65 | panic("Bootloader did not provide multiboot information\n"); 66 | } 67 | 68 | // For the stuff on lines 30-31 69 | for (size_t i = 0; &__init_array[i] != __init_array_end; i++) 70 | { 71 | __init_array[i](); 72 | } 73 | 74 | pmm_init(mbd); 75 | pic_init(); 76 | pit_init(); 77 | 78 | asm volatile("sti"); 79 | 80 | ps2_init(); 81 | ps2_init_keymap_us(); 82 | 83 | // StartUp_Beeps(); 84 | 85 | storage_device_init(); 86 | debug_print_pci(); 87 | 88 | 89 | shell_start(); 90 | } 91 | -------------------------------------------------------------------------------- /src/kernel/krnentry.asm: -------------------------------------------------------------------------------- 1 | bits 32 ;nasm directive 2 | 3 | section .multiboot 4 | ;multiboot spec 5 | align 4 6 | dd 0x1BADB002 ;magic 7 | dd 0x00 ;flags 8 | dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero 9 | 10 | section .bss 11 | boot_stack_bottom: 12 | resb 4096 13 | boot_stack_top: 14 | 15 | section .data 16 | boot_gdt: 17 | dq 0x0000000000000000 18 | dq 0x00CF9A000000FFFF 19 | dq 0x00CF92000000FFFF 20 | boot_gdtr: 21 | dw boot_gdtr - boot_gdt - 1 22 | dd boot_gdt 23 | 24 | section .text 25 | 26 | global start 27 | extern k_main ; <-- The k_main function is defined in kernel.c 28 | 29 | start: 30 | mov esp, boot_stack_top 31 | push eax ; <-|----pushes memory map from grub onto 32 | push ebx ; <-| the stack so the kernel can access it. 33 | lgdt [boot_gdtr] 34 | mov ax, 0x10 35 | mov ds, ax 36 | mov es, ax 37 | mov fs, ax 38 | mov gs, ax 39 | mov ss, ax 40 | jmp 0x08:flush_cs 41 | flush_cs: 42 | call k_main ; <-- Jumps to the kernel 43 | 44 | hlt ; <-- Halt the CPU 45 | -------------------------------------------------------------------------------- /src/kernel/panic.c: -------------------------------------------------------------------------------- 1 | #include "panic.h" 2 | #include "../drivers/vga.h" 3 | #include "../shell/terminal.h" 4 | 5 | __attribute__((noreturn)) 6 | void panic_impl(const char* location_prefix, const char* message) 7 | { 8 | term_write(location_prefix, TC_LRED); 9 | term_putchar(' ', TC_LRED); 10 | term_write(message, TC_LRED); 11 | 12 | asm volatile("cli"); 13 | for (;;) { 14 | asm volatile("hlt"); 15 | } 16 | __builtin_unreachable(); 17 | } 18 | -------------------------------------------------------------------------------- /src/kernel/panic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define __panic_stringify_helper(s) #s 4 | #define __panic_stringify(s) __panic_stringify_helper(s) 5 | 6 | #define panic(message) panic_impl("kernel panic at " __FILE__ ":" __panic_stringify(__LINE__), message) 7 | 8 | __attribute__((noreturn)) 9 | void panic_impl(const char* location_prefix, const char* message); 10 | -------------------------------------------------------------------------------- /src/kernel/process.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "../drivers/vga.h" 3 | #include "../shell/shell.h" 4 | 5 | PCB process_table[MAX_PROCESSES]; 6 | int current_process = -1; 7 | 8 | // Helper function to determine if there are any processes ready 9 | bool has_ready_process() { 10 | for (int i = 0; i < MAX_PROCESSES; i++) { 11 | if (process_table[i].state == PROCESS_READY) { 12 | return true; 13 | } 14 | } 15 | return false; 16 | } 17 | 18 | void context_switch(PCB* next_process) { 19 | if (current_process >= 0) { 20 | asm volatile("mov %%esp, %0" : "=r"(process_table[current_process].stack_pointer)); 21 | } 22 | 23 | current_process = next_process - process_table; 24 | 25 | term_write("Switching to new process...\n", TC_YELLO); 26 | asm volatile("mov %0, %%esp" : : "r"(next_process->stack_pointer)); 27 | next_process->program_counter(); // Now it correctly jumps to the function 28 | } 29 | 30 | bool all_processes_terminated() { 31 | for (int i = 0; i < MAX_PROCESSES; i++) { 32 | if (process_table[i].state != PROCESS_TERMINATED) { 33 | return false; // At least one process is still running 34 | } 35 | } 36 | return true; // All processes are terminated 37 | } 38 | 39 | void scheduler() { 40 | if (!has_ready_process()) { 41 | term_write("No processes ready, returning to shell.\n", TC_LRED); 42 | shell_start(); // Return control to the shell when no processes are ready 43 | return; 44 | } 45 | 46 | int next_process = (current_process + 1) % MAX_PROCESSES; 47 | 48 | while (process_table[next_process].state != PROCESS_READY) { 49 | next_process = (next_process + 1) % MAX_PROCESSES; 50 | if (next_process == current_process) { 51 | return; 52 | } 53 | } 54 | 55 | context_switch(&process_table[next_process]); 56 | } 57 | 58 | void create_process(void (*entry_point)(), process_priority_t priority) { 59 | for (int i = 0; i < MAX_PROCESSES; i++) { 60 | if (process_table[i].state == PROCESS_TERMINATED) { 61 | process_table[i].pid = i; 62 | process_table[i].stack_pointer = kmalloc(4096) + 4096; 63 | process_table[i].program_counter = entry_point; 64 | process_table[i].state = PROCESS_READY; 65 | process_table[i].priority = priority; 66 | 67 | term_write("Process created successfully.\n", TC_GREEN); 68 | return; 69 | } 70 | } 71 | term_write("Failed to create process: No available slots.\n", TC_LRED); 72 | } 73 | 74 | void terminate_process() { 75 | term_write("Terminating foreground process...\n", TC_LRED); 76 | process_table[current_process].state = PROCESS_TERMINATED; 77 | 78 | // Try to find the next process 79 | if (has_ready_process()) { 80 | scheduler(); 81 | } else { 82 | // If no processes are left, return to the shell 83 | term_write("No processes left, returning to shell.\n", TC_LRED); 84 | shell_start(); 85 | } 86 | } -------------------------------------------------------------------------------- /src/kernel/process.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESS_H 2 | #define PROCESS_H 3 | 4 | #include "../drivers/types.h" 5 | #include "../memory/kmalloc.h" 6 | #include "../shell/terminal.h" 7 | #include "../drivers/pit.h" 8 | 9 | #define MAX_PROCESSES 20 10 | 11 | #define PROCESS_READY 0 12 | #define PROCESS_RUNNING 1 13 | #define PROCESS_WAITING 2 14 | #define PROCESS_BLOCKED 3 15 | #define PROCESS_TERMINATED 4 16 | 17 | typedef enum { 18 | HIGH_PRIORITY, 19 | LOW_PRIORITY, 20 | } process_priority_t; 21 | 22 | typedef struct { 23 | uint32_t pid; // Process ID 24 | uint32_t* stack_pointer; // Stack pointer 25 | void (*program_counter)(); // Program counter 26 | uint32_t state; // Process state 27 | process_priority_t priority; // Process priority 28 | uint32_t waiting_time; // Waiting time 29 | uint32_t turnaround_time; // Turnaround time 30 | } PCB; 31 | 32 | extern PCB process_table[MAX_PROCESSES]; 33 | extern int current_process; 34 | extern int foreground_process; 35 | 36 | void scheduler(); 37 | void context_switch(PCB* next_process); 38 | void create_process(void (*entry_point)(), process_priority_t priority); 39 | void terminate_process(); 40 | bool all_processes_terminated(); 41 | 42 | #endif -------------------------------------------------------------------------------- /src/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf32-i386) 2 | ENTRY(start) 3 | SECTIONS 4 | { 5 | . = 0x100000; 6 | .text BLOCK(4K) : ALIGN(4K) { *(.multiboot) *(.text) } 7 | .rodata BLOCK(4K) : ALIGN(4K) { *(.data) } 8 | .data BLOCK(4K) : ALIGN(4K) { *(.data) } 9 | .bss BLOCK(4K) : ALIGN(4K) { *(.bss) } 10 | .init_array : { 11 | __init_array = .; 12 | KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 13 | KEEP(*(.init_array .ctors)) 14 | __init_array_end = .; 15 | } 16 | } -------------------------------------------------------------------------------- /src/memory/kmalloc.c: -------------------------------------------------------------------------------- 1 | #include "kmalloc.h" 2 | #include 3 | #include 4 | 5 | #define KMALLOC_STATIC_SIZE 1024 * 1024 6 | 7 | static u8 s_kmalloc_static[KMALLOC_STATIC_SIZE]; 8 | 9 | struct kmalloc_node { 10 | u32 data_size; 11 | bool free; 12 | _Alignas(16) u8 data[0]; 13 | }; 14 | 15 | struct kmalloc_node* next_node(struct kmalloc_node* node) { 16 | if (node->data + node->data_size >= s_kmalloc_static + sizeof(s_kmalloc_static)) { 17 | return NULL; 18 | } 19 | return (struct kmalloc_node*)(node->data + node->data_size); 20 | } 21 | 22 | void kmalloc_init() { 23 | struct kmalloc_node* node = (struct kmalloc_node*)s_kmalloc_static; 24 | node->free = 1; 25 | node->data_size = (s_kmalloc_static + sizeof(s_kmalloc_static)) - node->data; 26 | } 27 | 28 | void* kmalloc(size_t size) { 29 | /* Validate allocation size */ 30 | if (size == 0 || size >= sizeof(s_kmalloc_static)) { 31 | return NULL; 32 | } 33 | 34 | /* Aligns to 16 bytes */ 35 | if (size % 16 != 0) { 36 | size += 16 - (size % 16); 37 | } 38 | 39 | /* Find any free node... */ 40 | struct kmalloc_node* node = (struct kmalloc_node*)s_kmalloc_static; 41 | while (node->data_size < size || !node->free) { 42 | struct kmalloc_node* next = next_node(node); 43 | if (next == NULL) { 44 | return NULL; 45 | } 46 | if (node->free && next->free) { 47 | node->data_size += next->data_size + sizeof(struct kmalloc_node); 48 | } else { 49 | node = next; 50 | } 51 | } 52 | 53 | /* ..and split it if its too big */ 54 | if (node->data_size > size + sizeof(struct kmalloc_node)) { 55 | struct kmalloc_node* new_node = (struct kmalloc_node*)(node->data + size); 56 | new_node->data_size = node->data_size - size - sizeof(struct kmalloc_node); 57 | new_node->free = 1; 58 | node->data_size = size; 59 | } 60 | 61 | /* Mark it as used */ 62 | node->free = false; 63 | 64 | return node->data; 65 | } 66 | 67 | void kfree(void* ptr) { 68 | if (ptr == NULL) { 69 | return; 70 | } 71 | 72 | /* Check if the pointer is inside the vaild memory range */ 73 | if ((u8*)ptr < s_kmalloc_static || (u8*)ptr >= s_kmalloc_static + sizeof(s_kmalloc_static)) { 74 | panic("kfree called with pointer outside of the kmalloc memory"); 75 | } 76 | 77 | struct kmalloc_node* node = (struct kmalloc_node*)((u8*)ptr - sizeof(struct kmalloc_node)); 78 | 79 | /* Check if its used */ 80 | if (node->free) { 81 | panic("kfree called with an already free pointer"); 82 | } 83 | 84 | /* And mark it as free */ 85 | node->free = true; 86 | } 87 | -------------------------------------------------------------------------------- /src/memory/kmalloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void kmalloc_init(); 6 | void* kmalloc(size_t size); 7 | void kfree(void* ptr); 8 | -------------------------------------------------------------------------------- /src/memory/pmm.c: -------------------------------------------------------------------------------- 1 | #include "pmm.h" 2 | #include "../kernel/panic.h" 3 | 4 | u64 g_total_pmm_bytes; 5 | 6 | void pmm_init(const multiboot_info_t* multiboot_info) { 7 | if (!(multiboot_info->flags & MULTIBOOT_INFO_MEM_MAP)) { 8 | panic("Multiboot info does not contain memory map\n"); 9 | } 10 | 11 | g_total_pmm_bytes = 0; 12 | 13 | for (uint32_t offset = 0; offset < multiboot_info->mmap_length;) { 14 | const multiboot_memory_map_t* entry = (const multiboot_memory_map_t*)(multiboot_info->mmap_addr + offset); 15 | if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) { 16 | g_total_pmm_bytes += entry->len; 17 | } 18 | offset += entry->size + sizeof(entry->size); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/memory/pmm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../drivers/types.h" 4 | #include "../kernel/multiboot.h" 5 | 6 | extern u64 g_total_pmm_bytes; 7 | 8 | void pmm_init(const multiboot_info_t* multiboot_info); 9 | -------------------------------------------------------------------------------- /src/recovery/pong.hpp: -------------------------------------------------------------------------------- 1 | #include "../gui/window/gui.hpp" 2 | extern "C" { 3 | #include "../memory/kmalloc.h" 4 | } 5 | 6 | /// @brief A hidden pong game in the recovery mode 7 | class Pong { 8 | GUI::Buffer game_buffer = GUI::Buffer((uint32_t*)kmalloc(1920 * 108 * sizeof(uint32_t)), 1920, 1080); // Centre area (Where the circle is) 9 | 10 | uint16_t score_bot = 0; // Score always starts at 0 11 | uint16_t score_player = 0; 12 | uint8_t circle_radius = 50; 13 | GUI::uPoint32 ball = GUI::uPoint32((1920 / 2) - circle_radius, (1080 / 2) - circle_radius); // The ball starts at the centre 14 | uint8_t ball_direction = 180; // 0-360, 0 = toward the bot, 180 = toward the player 15 | uint8_t ball_speed = 10; 16 | 17 | // These positions are the middle of the paddle 18 | uint8_t bot_pos = 1080 / 2; 19 | uint8_t player_pos = 1080 / 2; 20 | // These are 100 pixels high, and 25 pixels wide, 10 padding on either side 21 | uint8_t paddle_height = 100; 22 | uint8_t paddle_width = 25; 23 | 24 | // Debug mode adds pink boxes as the background on surfaces that are drawn 25 | // It also adds green boxes around surfaces that are collidable 26 | // It also adds blue boxes around surfaces that bounce 27 | // It also adds red boxes around surfaces that mean game over 28 | bool debug = false; 29 | 30 | // Some basic keyboard locking, so the input doesn't get spammed 31 | uint8_t iteration = 0; 32 | bool input_locked = false; 33 | uint64_t tick = 0; 34 | 35 | // Pausing and redrawing 36 | bool paused = true; 37 | bool started = false; 38 | public: 39 | Pong() { 40 | //GUI::clear(game_buffer, 0x00000000); 41 | //GUI::vbe_render_all(game_buffer, GUI::uPoint32(0, 0)); 42 | } 43 | ~Pong() { 44 | kfree(&game_buffer); // Free the memory 45 | } 46 | Pong(GUI::Buffer buffer) : game_buffer(buffer) { } 47 | void init_pong(); 48 | void update_paddle_pos(uint8_t last_pos, uint8_t new_pos, uint8_t side); 49 | void update_ball_pos(GUI::uPoint32 last_pos, GUI::uPoint32 new_pos); 50 | void simulate_ball(); // Get it 51 | void simulate_bot(); 52 | 53 | void draw_main(); // Things like the line down the middle, and score at the top 54 | void draw_about(); // Box in the middle with some text 55 | }; -------------------------------------------------------------------------------- /src/recovery/recovery.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../drivers/types.h" 4 | 5 | #ifndef RECOVERY_H 6 | #define RECOVERY_H 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | void start_recovery(); 13 | 14 | #ifdef __cplusplus 15 | } 16 | #endif 17 | 18 | #endif // RECOVERY_H 19 | -------------------------------------------------------------------------------- /src/shell/commands/beep/beep.c: -------------------------------------------------------------------------------- 1 | #include "beep.h" 2 | 3 | #include "../../terminal.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | #include "../../../gui/desktop.h" 7 | 8 | int shell_beep_command(int argc, const char** argv) { 9 | if (argc != 2 && argc != 3) { 10 | //term_write("ERROR: Usage -> beep [freq.] [duration]\n", TC_LRED); 11 | return 2; 12 | } 13 | 14 | atoi_result_t frequency = atoi(argv[1]); 15 | if (!frequency.valid) { 16 | //term_write("ERROR: Frequency provided is not an interger\n", TC_LRED); 17 | return 2; 18 | } 19 | 20 | // Use the default beep length if no value has been set by the user 21 | atoi_result_t duration = { .valid = true, .value = 500 }; // <-- 500 ms 22 | if (argc >= 3) { 23 | duration = atoi(argv[2]); 24 | } 25 | if (!duration.valid) { 26 | //term_write("ERROR: Duration provided is not an interger\n", TC_LRED); 27 | return 2; 28 | } 29 | 30 | startbeep(frequency.value); 31 | pit_sleep_ms(duration.value); 32 | mutebeep(); 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /src/shell/commands/beep/beep.h: -------------------------------------------------------------------------------- 1 | int shell_beep_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/calc/calc.c: -------------------------------------------------------------------------------- 1 | #include "calc.h" 2 | 3 | #include "../../terminal.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | #include "../../../gui/desktop.h" 7 | 8 | typedef int (*math_op_t)(int, int); 9 | int add(int a, int b); 10 | int subtract(int a, int b); 11 | int divide(int a, int b); 12 | int multiply(int a, int b); 13 | typedef struct { 14 | const char *op; 15 | math_op_t func; 16 | } op_map_t; 17 | 18 | op_map_t operations[] = { 19 | {"+", add}, 20 | {"-a", add}, 21 | {"-", subtract}, 22 | {"-s", subtract}, 23 | {"/", divide}, 24 | {"-d", divide}, 25 | {"*", multiply}, 26 | {"-m", multiply}, 27 | {NULL, NULL} // <- End of map 28 | }; 29 | int add(int a, int b) { 30 | return a + b; 31 | } 32 | 33 | int subtract(int a, int b) { 34 | return a - b; 35 | } 36 | 37 | int divide(int a, int b) { 38 | return a / b; 39 | } 40 | 41 | int multiply(int a, int b) { 42 | return a * b; 43 | } 44 | 45 | int shell_calc_command(int argc, const char** argv) { 46 | if (argc != 4) { 47 | return 2; 48 | } 49 | 50 | atoi_result_t number1 = atoi(argv[1]); 51 | atoi_result_t number2 = atoi(argv[3]); 52 | if (!number1.valid || !number2.valid) { 53 | return 2; 54 | } 55 | 56 | math_op_t op_func = NULL; 57 | for (int i = 0; operations[i].op != NULL; i++) { 58 | if (strcmp(argv[2], operations[i].op) == 0) { 59 | op_func = operations[i].func; 60 | break; 61 | } 62 | } 63 | 64 | if (op_func == NULL) { 65 | return 2; 66 | } 67 | 68 | // Perform the calculation and handle division by zero 69 | int result = op_func(number1.value, number2.value); 70 | if (op_func == divide && number2.value == 0) { 71 | term_write("ERROR: Cannot divide by 0!\n", TC_LRED); 72 | } else { 73 | term_write_u32(result, 10, TC_WHITE); 74 | term_write("\n", TC_WHITE); 75 | } 76 | 77 | return 0; 78 | } -------------------------------------------------------------------------------- /src/shell/commands/calc/calc.h: -------------------------------------------------------------------------------- 1 | int shell_calc_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/cat/cat.c: -------------------------------------------------------------------------------- 1 | #include "cat.h" 2 | 3 | #include "../../shell.h" 4 | #include "../../terminal.h" 5 | #include "../../../drivers/vga.h" 6 | #include "../../../drivers/vbe.h" 7 | #include "../../../drivers/filesystem/fat.h" 8 | 9 | int shell_cat_command(int argc, const char** argv) { 10 | if (argc != 2) { 11 | return 2; 12 | } 13 | if (s_fat_fs == NULL) { 14 | term_write("ERROR: Not FAT filesystem initialized\n", TC_LRED); 15 | return; 16 | } 17 | 18 | char dest[256]; 19 | strcpy(dest,currentDir); 20 | strcat(dest,argv[1]); 21 | 22 | FAT_file_t* file = FAT_OpenAbsolute(s_fat_fs, dest); 23 | if (file == NULL) { 24 | term_write("ERROR: Not found: '", TC_LRED); 25 | term_write(argv[1], TC_LRED); 26 | term_write("'\n", TC_LRED); 27 | FAT_Close(file); 28 | return; 29 | } 30 | 31 | char buffer[513]; 32 | size_t total_read = 0; 33 | while (true) { 34 | size_t nread = FAT_Read(file, total_read, buffer, sizeof(buffer) - 1); 35 | if (nread == 0) { 36 | break; 37 | } 38 | 39 | buffer[nread] = '\0'; 40 | term_write(buffer, TC_WHITE); 41 | 42 | total_read += nread; 43 | } 44 | 45 | FAT_Close(file); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /src/shell/commands/cat/cat.h: -------------------------------------------------------------------------------- 1 | int shell_cat_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/cd/cd.c: -------------------------------------------------------------------------------- 1 | #include "cd.h" 2 | 3 | #include "../../shell.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | #include "../../../gui/desktop.h" 7 | 8 | int shell_cd_command(int argc, const char** argv) { 9 | if (argc != 2) { 10 | return 2; 11 | } 12 | 13 | if (s_fat_fs == NULL) { 14 | term_write("ERROR: FAT filesystem not initialized\n", TC_LRED); 15 | return 2; 16 | } 17 | 18 | const char* new_dir_path = argv[1]; 19 | char full_path[256]; 20 | int full_path_len = 0; 21 | 22 | // Handle ".." 23 | if (strcmp(new_dir_path, "..") == 0) { 24 | if (strcmp(currentDir, "root") == 0 || strcmp(currentDir, "") == 0) { 25 | } else { 26 | char* last_slash = find_last_slash(currentDir); 27 | if (last_slash != NULL) { 28 | *last_slash = '\0'; 29 | } else { 30 | strcpy(currentDir, "root"); // If somehow beyond root, reset to root 31 | } 32 | } 33 | return; 34 | } 35 | 36 | if (strcmp(currentDir, "root") != 0) { 37 | while (currentDir[full_path_len] != '\0') { 38 | full_path[full_path_len] = currentDir[full_path_len]; 39 | full_path_len++; 40 | } 41 | 42 | full_path[full_path_len] = '/'; 43 | full_path_len++; 44 | } 45 | 46 | int i = 0; 47 | while (new_dir_path[i] != '\0') { 48 | full_path[full_path_len] = new_dir_path[i]; 49 | full_path_len++; 50 | i++; 51 | } 52 | 53 | full_path[full_path_len] = '\0'; 54 | 55 | FAT_file_t* new_dir = FAT_OpenAbsolute(s_fat_fs, full_path); 56 | if (new_dir == NULL) { 57 | term_write("ERROR: Directory not found: '", TC_LRED); 58 | term_write(full_path, TC_LRED); 59 | term_write("'\n", TC_LRED); 60 | return 1; 61 | } 62 | 63 | if (!FAT_IsDirectory(new_dir)) { 64 | term_write("ERROR: Not a directory: '", TC_LRED); 65 | term_write(full_path, TC_LRED); 66 | term_write("'\n", TC_LRED); 67 | FAT_Close(new_dir); 68 | return 1; 69 | } 70 | 71 | // Update the current dir 72 | strcpy(currentDir, full_path); 73 | 74 | term_write(currentDir, TC_WHITE); 75 | term_write("\n", TC_WHITE); 76 | 77 | FAT_Close(new_dir); 78 | 79 | return 0; 80 | } -------------------------------------------------------------------------------- /src/shell/commands/cd/cd.h: -------------------------------------------------------------------------------- 1 | int shell_cd_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/chstat/chstat.c: -------------------------------------------------------------------------------- 1 | #include "chstat.h" 2 | 3 | #include "../../terminal.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | #include "../../../memory/pmm.h" 7 | 8 | int shell_chstat_command(int argc, const char** argv) { 9 | /* this is basically a stupid neofetch clone */ 10 | char mem_mib_buffer[20]; 11 | uint64_to_string(g_total_pmm_bytes / 1024 / 1024, mem_mib_buffer); 12 | mem_mib_buffer[19] = 0; // <-- to prevent undefined behaviour 13 | char cpu_vendor[13]; 14 | char cpu_brand[49]; 15 | 16 | get_cpu_info(cpu_vendor, cpu_brand); 17 | 18 | term_write("BUILD: ", TC_LBLUE); 19 | term_write(__DATE__ " @ " __TIME__ "\n", TC_WHITE); 20 | term_write("KERNEL: ", TC_LBLUE); 21 | term_write("Choacury Standard\n", TC_WHITE); // <-- aka. stock kernel. 22 | term_write("SHELL: ", TC_LBLUE); 23 | term_write("chsh-0.0.0.0041e-dev\n", TC_WHITE); // <-- Could be more automated ngl. 24 | term_write("RAM: ", TC_LBLUE); 25 | term_write(mem_mib_buffer, TC_WHITE); 26 | term_write(" MiB\n", TC_WHITE); 27 | term_write("CPU Vendor: ", TC_LBLUE); 28 | term_write(cpu_vendor, TC_WHITE); 29 | term_write("\n", TC_WHITE); 30 | term_write("CPU Brand: ", TC_LBLUE); 31 | term_write(cpu_brand[0] ? cpu_brand : "Unknown", TC_WHITE); // <-- Show "Unknown" as fallback if the 32 | // CPU brand can't be fetched 33 | term_write("\n", TC_WHITE); 34 | 35 | /* TODO: If the user enters GUI mode, fetch the users D.E., display size, WM, etc. */ 36 | 37 | // Commented out because we don't have a functioning terminal in GUI mode yet 38 | /*term_write("Build: ", TC_LBLUE); 39 | term_write(__DATE__ " @ " __TIME__ "\n", TC_WHITE); 40 | term_write("Kernel: ", TC_LBLUE); 41 | term_write("Choacury Standard\n", TC_WHITE); // <-- aka. stock kernel. 42 | term_write("Shell: ", TC_LBLUE); 43 | term_write("chsh-0.0.0.0045a\n", TC_WHITE); // <-- Could be more automated ngl. 44 | term_write("RAM: ", TC_LBLUE); 45 | term_write(mem_mib_buffer, TC_WHITE); 46 | term_write(" MiB\n", TC_WHITE); 47 | term_write("CPU Vendor: ", TC_LBLUE); 48 | term_write(cpu_vendor, TC_WHITE); 49 | term_write("\n", TC_WHITE); 50 | term_write("CPU Brand: ", TC_LBLUE); 51 | term_write(cpu_brand[0] ? cpu_brand : "Unknown", TC_WHITE); // <-- Show "Unknown" as fallback if the 52 | // CPU brand can't be fetched 53 | term_write("\n", TC_WHITE);*/ 54 | } 55 | -------------------------------------------------------------------------------- /src/shell/commands/chstat/chstat.h: -------------------------------------------------------------------------------- 1 | int shell_chstat_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/clear/clear.c: -------------------------------------------------------------------------------- 1 | #include "clear.h" 2 | #include "../../terminal.h" 3 | 4 | int shell_clear_command(int argc, const char** argv) { 5 | term_clear(); 6 | 7 | return 0; 8 | } -------------------------------------------------------------------------------- /src/shell/commands/clear/clear.h: -------------------------------------------------------------------------------- 1 | int shell_clear_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/command.c: -------------------------------------------------------------------------------- 1 | #include "command.h" 2 | 3 | // Command includes 4 | #include "help/help.c" 5 | #include "guiload/guiload.h" 6 | #include "clear/clear.h" 7 | #include "beep/beep.h" 8 | #include "calc/calc.h" 9 | #include "compdate/compdate.h" 10 | #include "echo/echo.h" 11 | #include "pause/pause.h" 12 | #include "pl/pl.h" 13 | #include "chstat/chstat.h" 14 | #include "cd/cd.h" 15 | #include "cat/cat.h" 16 | #include "ls/ls.h" 17 | #include "vbetest/vbetest.h" 18 | #include "whereami/whereami.h" 19 | #include "recovery/recovery.h" 20 | 21 | // Temp 22 | int example_command(int argc, const char** argv) { 23 | 24 | } 25 | 26 | int temp_shell_guiload_command(int argc, char** argv) { 27 | return 0; 28 | } 29 | 30 | int temp_shell_notimplemented_command(int argc, const char** argv) { 31 | return 0; 32 | } 33 | 34 | void shell_init_commands_list() { 35 | /*static Command shell_commands_list[] = { 36 | //{"example", "arg1 arg2", "Example command", example_command}, 37 | {"guiload", "No args.", "Loads up the GUI (WIP!)", shell_guiload_command} 38 | };*/ 39 | } 40 | 41 | /** 42 | * How should commands be defined? 43 | * Like this: {"command name", {"alias1", "alias2", NULL}, "Command description", link_to_command} 44 | * 45 | * Arguments should be defined like this: 46 | * Short version with a single dash and from 1-2 letters, e.g. -a 47 | * Long/full version with two dashes, e.g. --args 48 | */ 49 | 50 | Command shell_commands_list[] = { 51 | // Command Alias(es) Args Description Function: 52 | {"help", {NULL}, " (args)", "Shows all of the available commands", shell_help_command}, 53 | {"beep", {NULL}, "[int:freq.] [int:duration]", "PC Beeper control.", shell_beep_command}, 54 | {"calc", {NULL}, "[int:number1] [str:func] [int:number2]", "Literally a calculator.", shell_calc_command}, 55 | {"cat", {NULL}, "[str:file]", "Print a file contents.", shell_cat_command}, 56 | {"cd", {NULL}, "[str:directory]", "Changes the current directory.", shell_cd_command}, 57 | {"compdate", {NULL}, "No args.", "Shows the compilation date.", shell_compdate_command}, 58 | {"clear", {"cls", NULL}, "No args.", "Clears the screen.", shell_clear_command}, 59 | {"echo", {NULL}, "No args.", "Prints string to the console.", shell_echo_command}, 60 | {"guiload", {NULL}, "No args.", "Loads up the GUI (WIP!)", shell_guiload_command}, 61 | {"ls", {NULL}, "(str:directory)", "List files in a directory.", shell_ls_command}, 62 | // {"mkdir", {NULL}, "(str:directory)", "Creates a empty directory.", shell_mkdir_command}, // <-- TODO 63 | {"pause", {NULL}, "(-t int:time) (-k)", "Pauses the terminal until a keyboard input.", shell_pause_command}, 64 | {"pl", {NULL}, "No args.", "Shows the connected data devices.", shell_pl_command}, 65 | {"chstat", {NULL}, "No args.", "Display system information.", shell_chstat_command}, 66 | {"vbetest", {NULL}, "No args.", "Test Bochs VBE extensions", shell_vbetest_command}, 67 | {"whereami", {NULL}, "No args.", "Prints the current directory", shell_whereami_command}, 68 | {"recovery", {NULL}, "No args.", "Recovery mode (WIP)", shell_recovery_command} 69 | }; 70 | int shell_commands_count = sizeof(shell_commands_list) / sizeof(Command); 71 | -------------------------------------------------------------------------------- /src/shell/commands/command.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include 4 | 5 | void shell_init_commands_list(); 6 | 7 | // Command type definition 8 | typedef struct { 9 | char* name; // <-- Name of the command 10 | const char* aliases[16]; 11 | //char** aliases; // <-- Other names for the command (E.g. cls for clear) - Displayed in help after name (Comma seperated) 12 | char* args; // <-- Argument information 13 | char* description; // <-- Description of the command 14 | int (*func)(int, const char**); // <-- The command returns a return code (Look in structure.md for more info on return codes) 15 | } Command; 16 | 17 | //extern Command shell_commands[]; 18 | 19 | int temp_shell_guiload_command(int argc, char** argv); 20 | 21 | /*extern Command shell_commands_list[] = { 22 | //{"example", "arg1 arg2", "Example command", example_command}, 23 | {"guiload", "No args.", "Loads up the GUI (WIP!)", temp_shell_guiload_command} 24 | };*/ 25 | 26 | //extern Command* shell_commands_list; 27 | extern Command shell_commands_list[]; 28 | extern int shell_commands_count; -------------------------------------------------------------------------------- /src/shell/commands/compdate/compdate.c: -------------------------------------------------------------------------------- 1 | #include "compdate.h" 2 | 3 | #include "../../terminal.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | 7 | int shell_compdate_command(int argc, const char** argv) { 8 | term_write(__DATE__ "\n", TC_WHITE); 9 | } -------------------------------------------------------------------------------- /src/shell/commands/compdate/compdate.h: -------------------------------------------------------------------------------- 1 | int shell_compdate_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/echo/echo.c: -------------------------------------------------------------------------------- 1 | #include "echo.h" 2 | 3 | #include "../../terminal.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | 7 | int shell_echo_command(int argc, const char** argv) { 8 | for (int i = 1; i < argc; i++) { 9 | if (i > 1) 10 | term_write(" ", TC_WHITE); 11 | term_write(argv[i], TC_WHITE); 12 | } 13 | term_write("\n", TC_WHITE); 14 | } -------------------------------------------------------------------------------- /src/shell/commands/echo/echo.h: -------------------------------------------------------------------------------- 1 | int shell_echo_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/guiload/guiload.c: -------------------------------------------------------------------------------- 1 | #include "./guiload.h" 2 | #include "../../terminal.h" 3 | #include "../../../drivers/vga.h" 4 | #include "../../../drivers/vbe.h" 5 | #include "../../../gui/desktop.h" 6 | #include "../../../drivers/vbe.h" 7 | 8 | int shell_guiload_command(int argc, const char** argv) { 9 | /* Initialize graphics mode and start desktop */ 10 | BgaSetVideoMode(FHD,VBE_DISPI_BPP_32,1,1); 11 | start_desktop(); 12 | 13 | /* If desktop exits, reinitialize text mode and render terminal */ 14 | vga_text_init(TC_BLACK); 15 | term_rerender_buffer(); 16 | 17 | return 0; 18 | } -------------------------------------------------------------------------------- /src/shell/commands/guiload/guiload.h: -------------------------------------------------------------------------------- 1 | //#include "../command.h" // Add if needed 2 | 3 | int shell_guiload_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/help/help.c: -------------------------------------------------------------------------------- 1 | #include "../../terminal.h" 2 | #include "../../../drivers/vga.h" 3 | #include "../../../drivers/vbe.h" 4 | #include "../../../gui/desktop.h" 5 | #include "../command.h" 6 | 7 | // Put used_alias as -1 or 17 to set it as nothing btw 8 | void print_specific_command_help(int argc, const char** argv, Command command, int used_alias) { 9 | term_write("Information for command ", TC_WHITE); 10 | term_write(command.name, TC_BRIGHT); 11 | term_write("\n", TC_WHITE); 12 | 13 | term_write("Command description: ", TC_WHITE); 14 | term_write(command.description, TC_BRIGHT); 15 | term_write("\n\n", TC_WHITE); 16 | 17 | term_write("Command usage:\nAliases (Includes name): ", TC_WHITE); 18 | term_write(command.name, used_alias == -1 ? TC_LBLUE : TC_BRIGHT); 19 | for (size_t j = 0; command.aliases[j] != NULL; j++) 20 | { 21 | term_write(", ", TC_WHITE); 22 | term_write(command.aliases[j], used_alias == j ? TC_LBLUE : TC_BRIGHT); 23 | } 24 | 25 | term_write("\n\nArgument information: ", TC_WHITE); 26 | term_write(command.args, TC_BRIGHT); 27 | term_write("\n", TC_WHITE); 28 | } 29 | 30 | void print_specific_command_args_help(int argc, const char** argv, Command command) { 31 | term_write("Args: ", TC_WHITE); 32 | term_write(command.args, TC_BRIGHT); 33 | term_write("\n", TC_WHITE); 34 | } 35 | 36 | int shell_help_command(int argc, const char** argv) { 37 | if(argc == 1) { 38 | // Display the standard help screen 39 | term_write("Commands list:\n", TC_WHITE); 40 | //term_write("Attach the -a or --args flag to the help command for argument information.\n", TC_WHITE); 41 | term_write("Use 'help ' for command-specific information.\n", TC_BRIGHT); 42 | 43 | term_write("Command Description\n", TC_LBLUE); 44 | 45 | for (size_t i = 0; i < shell_commands_count; i++) { 46 | term_write(shell_commands_list[i].name, TC_WHITE); 47 | int cmdlength = strlen(shell_commands_list[i].name); 48 | for (size_t j = 0; shell_commands_list[i].aliases[j] != NULL; j++) 49 | { 50 | term_write(", ", TC_WHITE); 51 | term_write(shell_commands_list[i].aliases[j], TC_WHITE); 52 | 53 | cmdlength += strlen(shell_commands_list[i].aliases[j]) + 2; // + 2 for the comma and space 54 | } 55 | 56 | for (size_t i = 0; i < (20 - cmdlength); i++) 57 | { 58 | term_write(" ", TC_WHITE); 59 | } 60 | 61 | //term_write(" - ", TC_WHITE); 62 | term_write(shell_commands_list[i].description, TC_WHITE); 63 | 64 | term_write("\n", TC_WHITE); 65 | } 66 | } else if(argc == 2) { 67 | for (size_t i = 0; i < shell_commands_count; i++) 68 | { 69 | if(strcmp(argv[1], shell_commands_list[i].name) == 0) { 70 | // Found command 71 | 72 | /*term_write("Information for command ", TC_WHITE); 73 | term_write(shell_commands_list[i].name, TC_BRIGHT); 74 | term_write("\n", TC_WHITE); 75 | 76 | term_write("Command description: ", TC_WHITE); 77 | term_write(shell_commands_list[i].description, TC_BRIGHT); 78 | term_write("\n\n", TC_WHITE); 79 | 80 | term_write("Command usage:\nAliases (Includes name): ", TC_WHITE); 81 | term_write(shell_commands_list[i].name, TC_BRIGHT); 82 | for (size_t j = 0; shell_commands_list[i].aliases[j] != NULL; j++) 83 | { 84 | term_write(", ", TC_WHITE); 85 | term_write(shell_commands_list[i].aliases[j], TC_BRIGHT); 86 | } 87 | 88 | term_write("\n\nArgument information: ", TC_WHITE); 89 | term_write(shell_commands_list[i].args, TC_BRIGHT); 90 | term_write("\n", TC_WHITE);*/ 91 | 92 | print_specific_command_help(argc, argv, shell_commands_list[i], -1); 93 | 94 | return 0; 95 | } 96 | 97 | for (size_t j = 0; shell_commands_list[i].aliases[j] != NULL; j++) 98 | { 99 | if(strcmp(argv[1], shell_commands_list[i].aliases[j]) == 0) { 100 | // Found command 101 | 102 | print_specific_command_help(argc, argv, shell_commands_list[i], j); 103 | 104 | return 0; 105 | } 106 | } 107 | } 108 | 109 | // No command exists 110 | term_write("No command ", TC_YELLO); 111 | term_write(argv[1], TC_YELLO); 112 | term_write(" found, run '", TC_YELLO); 113 | term_write("help", TC_BRIGHT); 114 | term_write("' for the list of the available commands.\n", TC_YELLO); 115 | return 1; 116 | } else if(argc == 3) { 117 | for (size_t i = 0; i < shell_commands_count; i++) 118 | { 119 | if(strcmp(argv[1], shell_commands_list[i].name) == 0) { 120 | // Found command 121 | 122 | if(strcmp(argv[2], "args") == 0) { 123 | print_specific_command_args_help(argc, argv, shell_commands_list[i]); 124 | } 125 | 126 | return 0; 127 | } 128 | 129 | for (size_t j = 0; shell_commands_list[i].aliases[j] != NULL; j++) 130 | { 131 | if(strcmp(argv[1], shell_commands_list[i].aliases[j]) == 0) { 132 | // Found command 133 | 134 | if(strcmp(argv[2], "args") == 0) { 135 | print_specific_command_args_help(argc, argv, shell_commands_list[i]); 136 | } 137 | 138 | return 0; 139 | } 140 | } 141 | } 142 | } 143 | 144 | return 0; 145 | } -------------------------------------------------------------------------------- /src/shell/commands/help/help.h: -------------------------------------------------------------------------------- 1 | int shell_help_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/ls/ls.c: -------------------------------------------------------------------------------- 1 | #include "ls.h" 2 | 3 | #include "../../shell.h" 4 | #include "../../terminal.h" 5 | #include "../../../drivers/vga.h" 6 | #include "../../../drivers/vbe.h" 7 | #include "../../../drivers/filesystem/fat.h" 8 | 9 | int shell_ls_command(int argc, const char** argv) { 10 | if (argc > 2) { 11 | return 2; 12 | } 13 | if (s_fat_fs == NULL) { 14 | term_write("ERROR: Not FAT filesystem initialized\n", TC_LRED); 15 | return 1; 16 | } 17 | 18 | const char* path = (argc == 2) ? argv[1] : currentDir; 19 | 20 | if (strcmp(path, "root") == 0 || strcmp(path, "/") == 0) { 21 | path = ""; 22 | } 23 | 24 | //shitty implementation to get rid of FAT_OpenAbsolute not being able to find root/BOOT for example 25 | if(starts_with(path,"root/")) { 26 | path += 5; 27 | } 28 | 29 | FAT_file_t* file = FAT_OpenAbsolute(s_fat_fs, path); 30 | if (file == NULL) { 31 | term_write("ERROR: Not found: '", TC_LRED); 32 | term_write(path, TC_LRED); 33 | term_write("'\n", TC_LRED); 34 | return 1; 35 | } 36 | 37 | char** names = NULL; 38 | size_t count = FAT_ListFiles(file, &names); 39 | if (names == NULL) { 40 | term_write("ERROR: Failed to list files\n", TC_LRED); 41 | FAT_Close(file); 42 | return 1; 43 | } 44 | 45 | term_write("Name Type\n", TC_LBLUE); 46 | for (size_t i = 0; i < count; i++) { 47 | term_write(names[i], TC_WHITE); 48 | 49 | for (size_t j = 0; j < 20 - strlen(names[i]); j++) 50 | { 51 | term_putchar(' ', TC_WHITE); 52 | } 53 | 54 | FAT_file_t* file = FAT_OpenAbsolute(s_fat_fs, names[i]); 55 | 56 | if(FAT_IsDirectory(file)) { 57 | term_write("DIR", TC_WHITE); 58 | } else { 59 | term_write("FILE", TC_WHITE); 60 | } 61 | kfree(file); 62 | term_putchar('\n', TC_WHITE); 63 | kfree(names[i]); 64 | } 65 | term_putchar('\n', TC_WHITE); 66 | kfree(names); 67 | 68 | FAT_Close(file); 69 | 70 | return 0; 71 | } -------------------------------------------------------------------------------- /src/shell/commands/ls/ls.h: -------------------------------------------------------------------------------- 1 | int shell_ls_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/mkdir/mkdir.c: -------------------------------------------------------------------------------- 1 | #include "mkdir.h" 2 | 3 | #include "../../shell.h" 4 | #include "../../terminal.h" 5 | #include "../../../drivers/vga.h" 6 | #include "../../../drivers/vbe.h" 7 | #include "../../../drivers/filesystem/fat.h" 8 | 9 | int shell_mkdir_command(int argc, const char** argv) { 10 | if (argc > 2) { 11 | return 2; 12 | } 13 | if (s_fat_fs == NULL) { 14 | term_write("ERROR: Not FAT filesystem initialized\n", TC_LRED); 15 | return 1; 16 | } 17 | 18 | const char* path = (argc == 2) ? argv[1] : currentDir; 19 | 20 | term_write("TEMP! While Choacury DOES support file making, its currently a WIP. I'll be gone soon once I am finished.\n", TC_YELLO); 21 | 22 | /* PATH is the current directory. */ 23 | // FAT_CreateDirectory(path, argv[2]); -------------------------------------------------------------------------------- /src/shell/commands/mkdir/mkdir.h: -------------------------------------------------------------------------------- 1 | int shell_mkdir_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/pause/pause.c: -------------------------------------------------------------------------------- 1 | #include "pause.h" 2 | 3 | #include "../../terminal.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | 7 | int shell_pause_command(int argc, const char** argv) { 8 | if(strcmp(argv[1], "-t") == 0) { 9 | atoi_result_t duration = { .valid = true, .value = 500 }; // <-- 500 ms 10 | if (argc >= 3) { 11 | duration = atoi(argv[2]); 12 | } 13 | if (!duration.valid) { 14 | return 2; 15 | } 16 | pit_sleep_ms(duration.value); 17 | } 18 | else if(strcmp(argv[1], "-k") == 0) { 19 | term_write("Press any key to continue.\n", TC_WHITE); 20 | asm("hlt"); 21 | } 22 | else { 23 | return 2; 24 | } 25 | 26 | return 0; 27 | } -------------------------------------------------------------------------------- /src/shell/commands/pause/pause.h: -------------------------------------------------------------------------------- 1 | int shell_pause_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/pl/pl.c: -------------------------------------------------------------------------------- 1 | #include "pl.h" 2 | 3 | #include "../../terminal.h" 4 | #include "../../../drivers/vga.h" 5 | #include "../../../drivers/vbe.h" 6 | #include "../../../drivers/storage/device.h" 7 | 8 | int shell_pl_command(int argc, const char** argv) { 9 | term_write("Detected Devices: ", TC_WHITE); 10 | term_write_u32(g_storage_device_count, 10, TC_WHITE); 11 | term_write("\n", TC_WHITE); 12 | for (int i = 0; i < g_storage_device_count; i++) { 13 | storage_device_t* device = g_storage_devices[i]; 14 | u64 device_size = device->sector_count * device->sector_size; 15 | 16 | term_write(" ", TC_WHITE); 17 | term_write(device->model, TC_WHITE); 18 | term_write(" (", TC_WHITE); 19 | term_write_u32(device_size / 1024 / 1024, 10, TC_WHITE); 20 | term_write(" MiB)\n", TC_WHITE); 21 | 22 | for (u32 j = 0; j < device->partition_count; j++) { 23 | storage_device_t* partition = device->partitions[j]; 24 | u64 partition_size = partition->sector_count * partition->sector_size; 25 | 26 | term_write(" \xC0 ", TC_WHITE); // <- Stylistic choice. 27 | // TOFIX: Use Hex C4 (├) for any other partition 28 | // and save Hex C0 (└) for that last partition in each list 29 | term_write(partition->model, TC_WHITE); 30 | term_write(" (", TC_WHITE); 31 | term_write_u32(partition_size / 1024 / 1024, 10, TC_WHITE); 32 | term_write(" MiB)\n", TC_WHITE); 33 | } 34 | } 35 | 36 | return 0; 37 | } -------------------------------------------------------------------------------- /src/shell/commands/pl/pl.h: -------------------------------------------------------------------------------- 1 | int shell_pl_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/recovery/recovery.c: -------------------------------------------------------------------------------- 1 | #include "./recovery.h" 2 | #include "../../terminal.h" 3 | #include "../../../drivers/vga.h" 4 | #include "../../../drivers/vbe.h" 5 | #include "../../../recovery/recovery.h" 6 | #include "../../../drivers/vbe.h" 7 | 8 | int shell_recovery_command(int argc, const char** argv) { 9 | /* Initialize graphics mode and start recovery */ 10 | BgaSetVideoMode(FHD,VBE_DISPI_BPP_32,1,1); 11 | start_recovery(); 12 | 13 | /* If recovery exits, reinitialize text mode and render terminal */ 14 | vga_text_init(TC_BLACK); 15 | term_rerender_buffer(); 16 | 17 | return 0; 18 | } -------------------------------------------------------------------------------- /src/shell/commands/recovery/recovery.h: -------------------------------------------------------------------------------- 1 | //#include "../command.h" // Add if needed 2 | 3 | int shell_recovery_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/structure.md: -------------------------------------------------------------------------------- 1 | # How to structure a command 2 | 3 | A command is contained in this folder, under this every command has it's own folder with their designated c and header file, 4 | if you need any other functions or any other files, they can be in this folder. 5 | 6 | They will all need to be defined and added via the list which the Shell can recognise and take into account when searching 7 | for what the user has entered. 8 | 9 | ## Return codes 10 | 11 | When returning a code in a command, different numbers meen different things: 12 | 13 | | Code | Silent | Description | 14 | |------|--------|------------------------------------------------------| 15 | | `0` | Yes | Success | 16 | | `1` | Yes | Generic fail (Command expected to print error) | 17 | | `2` | No | Incorrect args (Called help command to display args) | -------------------------------------------------------------------------------- /src/shell/commands/vbetest/vbetest.c: -------------------------------------------------------------------------------- 1 | #include "vbetest.h" 2 | 3 | #include "../../shell.h" 4 | #include "../../terminal.h" 5 | #include "../../../drivers/vga.h" 6 | #include "../../../drivers/vbe.h" 7 | 8 | int shell_vbetest_command(int argc, const char** argv) { 9 | //BgaSetVideoMode(FHD,VBE_DISPI_BPP_32,1,1); 10 | //BgaSetVideoMode(1024, 768, 32, 1, 1) 11 | BgaSetVideoMode(1920, 1080, 32, 1, 1); 12 | vbe_putpixel(0,0, 0xffffff); 13 | int width = 1920; 14 | int height = 1080; 15 | for (size_t x = 0; x < width; x++) 16 | { 17 | for (size_t y = 0; y < height; y++) 18 | { 19 | uint8_t red = (x * 255) / width; 20 | uint8_t green = (y * 255) / height; 21 | uint8_t blue = ((x + y) * 255) / (width + height); 22 | 23 | uint32_t color = (red << 16) | (green << 8) | blue; 24 | 25 | vga_putpixel(x, y, color); 26 | } 27 | } 28 | 29 | for (size_t x = 0; x < 1024; x++) 30 | { 31 | for (size_t y = 0; y < 768; y++) 32 | { 33 | vga_putpixel(x, y, 0xffffff); 34 | vbe_putpixel(x, y, 0xffffff); 35 | } 36 | } 37 | 38 | return 0; 39 | } -------------------------------------------------------------------------------- /src/shell/commands/vbetest/vbetest.h: -------------------------------------------------------------------------------- 1 | int shell_vbetest_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/commands/whereami/whereami.c: -------------------------------------------------------------------------------- 1 | #include "whereami.h" 2 | 3 | #include "../../shell.h" 4 | #include "../../terminal.h" 5 | #include "../../../drivers/vga.h" 6 | #include "../../../drivers/vbe.h" 7 | 8 | int shell_whereami_command(int argc, const char** argv) { 9 | term_write(currentDir, TC_WHITE); 10 | term_write("\n", TC_WHITE); 11 | 12 | return 0; 13 | } -------------------------------------------------------------------------------- /src/shell/commands/whereami/whereami.h: -------------------------------------------------------------------------------- 1 | int shell_whereami_command(int argc, const char** argv); -------------------------------------------------------------------------------- /src/shell/shell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void shell_start(); 4 | 5 | #include "../drivers/filesystem/fat.h" 6 | 7 | extern FAT_filesystem_t* s_fat_fs; 8 | extern char currentDir[256]; 9 | 10 | // PSF1 11 | #include "../drivers/vbe.h" 12 | extern PSF1_FONT* font; -------------------------------------------------------------------------------- /src/shell/string_mang.h: -------------------------------------------------------------------------------- 1 | /* 2 | String Mangement System 3 | This shit makes the terminal actually work. 4 | */ 5 | 6 | int strlen(char s[]) { 7 | int i = 0; 8 | while (s[i] != '\0') ++i; 9 | return i; 10 | } 11 | 12 | void append(char s[], char n) { 13 | int len = strlen(s); 14 | s[len] = n; 15 | s[len+1] = '\0'; 16 | } 17 | 18 | int strcmp(char s1[], char s2[]) { 19 | int i; 20 | for (i = 0; s1[i] == s2[i]; i++) { 21 | if (s1[i] == '\0') return 0; 22 | } 23 | return s1[i] - s2[i]; 24 | } 25 | 26 | void backspace(char s[]) { 27 | int len = strlen(s); 28 | s[len-1] = '\0'; 29 | } -------------------------------------------------------------------------------- /src/shell/terminal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../drivers/types.h" 4 | #include "../drivers/filesystem/fat.h" 5 | 6 | #define COMMAND_HISTORY_SIZE 50 7 | #define COMMAND_MAX_LENGTH 256 8 | 9 | typedef void (*set_char_t)(u32, u32, u8, u8); 10 | typedef void (*move_cursor_t)(u32, u32); 11 | typedef struct { 12 | u8 ch; 13 | u8 color; 14 | } term_cell_t; 15 | 16 | typedef struct { 17 | u32 width; 18 | u32 height; 19 | u32 visible_height; 20 | u32 buffer_start_row; 21 | 22 | set_char_t set_char; 23 | move_cursor_t move_cursor; 24 | 25 | u32 row; 26 | u32 col; 27 | 28 | term_cell_t* buffer; 29 | } term_info_t; 30 | typedef struct { 31 | char commands[COMMAND_HISTORY_SIZE][COMMAND_MAX_LENGTH]; 32 | int current_index; 33 | int history_count; 34 | int history_position; 35 | } command_history_t; 36 | 37 | extern term_info_t s_term_info; 38 | extern command_history_t cmd_history; 39 | 40 | void save_command_history_to_file(FAT_filesystem_t* fs); 41 | void load_command_history_from_file(FAT_filesystem_t* fs); 42 | void add_command_to_history(const char* command); 43 | const char* get_previous_command(); 44 | const char* get_next_command(); 45 | void term_init(u32 width, u32 height, u32 visible_height, set_char_t set_char, move_cursor_t move_cursor); 46 | void term_rerender_buffer(); 47 | void term_clear(); 48 | void term_putchar(char ch, u8 color); 49 | void term_set_cursor(u32 x, u32 y); 50 | void term_write(const char* message, u8 color); 51 | void term_write_u32(u32 value, u8 base, u8 color); 52 | void term_write_hex(uint32_t value); 53 | void term_scroll(); 54 | // debug 55 | void dprintf(const char* format, ...); 56 | -------------------------------------------------------------------------------- /src/shell/user_input.h: -------------------------------------------------------------------------------- 1 | void userinput(char* buffer){ 2 | if(strcmp(buffer,"test")==0){ 3 | // command working 4 | } 5 | } -------------------------------------------------------------------------------- /test.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamChoacury/ChoacuryOS/be0f83de9b6a63be032fd272e170b4234d28d5a6/test.bmp --------------------------------------------------------------------------------