├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── Commands.txt ├── LICENSE ├── README.md ├── docker-buildenv └── Dockerfile └── main64 ├── .vscode └── settings.json ├── BigFile.txt ├── MemoryMap.txt ├── SFile.txt ├── ScanCodes.png ├── StringHashing.txt ├── bochsrc.bxrc ├── boot ├── bootsector.asm └── functions.asm ├── build.sh ├── clean.sh ├── fatgen.bat ├── kaosldr_16 ├── functions.asm ├── kaosldr_entry.asm ├── longmode.asm └── makefile ├── kaosldr_64 ├── ata.c ├── ata.h ├── fat12.c ├── fat12.h ├── kaosldr.c ├── kernel.asm ├── link.ld ├── makefile ├── misc.c └── misc.h ├── kernel ├── common.c ├── common.h ├── date.c ├── date.h ├── drivers │ ├── keyboard.c │ ├── keyboard.h │ ├── screen.c │ ├── screen.h │ ├── timer.c │ └── timer.h ├── io │ ├── ata.c │ ├── ata.h │ ├── fat12.c │ └── fat12.h ├── isr │ ├── idt.asm │ ├── idt.c │ ├── idt.h │ ├── irq.asm │ ├── irq.c │ ├── irq.h │ ├── pic.c │ └── pic.h ├── kernel.c ├── kernel.h ├── link.ld ├── list.c ├── list.h ├── makefile ├── memory │ ├── heap.c │ ├── heap.h │ ├── physical-memory.c │ ├── physical-memory.h │ ├── virtual-memory.c │ └── virtual-memory.h ├── multitasking │ ├── contextswitching.asm │ ├── gdt.asm │ ├── gdt.c │ ├── gdt.h │ ├── multitasking.c │ ├── multitasking.h │ └── spinlock.h └── syscalls │ ├── syscall.asm │ ├── syscall.c │ └── syscall.h ├── libc ├── libc.c ├── libc.h ├── syscall.asm ├── syscall.c └── syscall.h └── programs ├── program1 ├── link.ld ├── makefile ├── program.c └── program.h ├── program2 ├── link.ld ├── makefile ├── program.c └── program.h └── shell ├── link.ld ├── makefile ├── shell.c └── shell.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | *.bin 39 | *.img 40 | *.vfd 41 | 42 | # Debug files 43 | *.dSYM/ 44 | *.su 45 | *.idb 46 | *.pdb 47 | 48 | # Kernel Module Compile Results 49 | *.mod* 50 | *.cmd 51 | .tmp_versions/ 52 | modules.order 53 | Module.symvers 54 | Mkfile.old 55 | dkms.conf 56 | 57 | *.generated 58 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "common.h": "c", 4 | "idt.h": "c", 5 | "screen.h": "c", 6 | "irq.h": "c", 7 | "keyboard.h": "c", 8 | "date.h": "c", 9 | "pic.h": "c", 10 | "fat12.h": "c", 11 | "timer.h": "c", 12 | "physical-memory.h": "c", 13 | "heap.h": "c", 14 | "task.h": "c", 15 | "virtual-memory.h": "c", 16 | "spinlock.h": "c", 17 | "multitasking.h": "c", 18 | "gdt.h": "c", 19 | "syscall.h": "c", 20 | "kernel.h": "c", 21 | "libc.h": "c", 22 | "ata.h": "c" 23 | }, 24 | "C_Cpp.errorSquiggles": "disabled", 25 | "cmake.configureOnOpen": false 26 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": 4 | [ 5 | { 6 | "label": "Build KAOS", 7 | "type": "docker-run", 8 | "dockerRun": { 9 | "image": "sqlpassion/kaos-buildenv", 10 | "command": "/bin/sh /src/main64/build.sh", 11 | "remove": true, 12 | "volumes": [ 13 | { 14 | "localPath": "${workspaceFolder}", 15 | "containerPath": "/src" 16 | } 17 | ] 18 | }, 19 | "problemMatcher": [], 20 | "group": { 21 | "kind": "build", 22 | "isDefault": true 23 | } 24 | }, 25 | { 26 | "label": "Clean up KAOS", 27 | "type": "docker-run", 28 | "dockerRun": { 29 | "image": "sqlpassion/kaos-buildenv", 30 | "command": "/bin/sh /src/main64/clean.sh", 31 | "remove": true, 32 | "volumes": [ 33 | { 34 | "localPath": "${workspaceFolder}", 35 | "containerPath": "/src" 36 | } 37 | ] 38 | } 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /Commands.txt: -------------------------------------------------------------------------------- 1 | ########################## 2 | # Building on Windows x64 3 | ########################## 4 | - Open Terminal Shell (PowerShell): 5 | terminal 6 | d: 7 | - Start the Build Environment: 8 | docker run --rm -it -v d:\GitHub\SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/clean.sh 9 | docker run --rm -it -v d:\GitHub\SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh 10 | - Write the final FAT12 image to a virtual disk (on Windows): http://www.chrysocome.net/dd 11 | ./dd.exe if=d:\github\sqlpassion\osdev\main64\kaos64.img of=d:\HDD-flat.vmdk 12 | - Everything in one command: 13 | clear; docker run --rm -it -v d:\GitHub\SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/clean.sh; docker run --rm -it -v d:\GitHub\SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh; ./dd.exe if=d:\github\sqlpassion\osdev\main64\kaos64.img of=d:\HDD-flat.vmdk 14 | - Write the Virtual Disk back to a FAT12 image 15 | ./dd.exe if=d:\HDD-flat.vmdk of=d:\kaos64.ima bs=512 count=2880 16 | 17 | ########################## 18 | # Building on Windows ARM 19 | ########################## 20 | - Start WSL2 on the command line: 21 | wsl 22 | - Start Docker inside WSL2: 23 | sudo service docker Start 24 | - Start the Build Environment: 25 | sudo docker run --rm -it -v /mnt/c/Users/klaus/documents/github/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/clean.sh 26 | sudo docker run --rm -it -v /mnt/c/Users/klaus/documents/github/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh 27 | - Build the final image on the Windows ARM command line 28 | fatgen.bat 29 | - Execute 30 | bochsrc.bxrc 31 | 32 | ##################### 33 | # Building on Mac OS 34 | ##################### 35 | - Open Terminal: 36 | docker run --rm -it -v $HOME/dev/GitHub/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/clean.sh 37 | docker run --rm -it -v $HOME/dev/GitHub/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh 38 | - Write the final FAT12 image to a virtual disk: 39 | dd if="$HOME/dev/GitHub/SQLpassion/osdev/main64/kaos64.img" of="$HOME/dev/Virtual Machines/KAOS.vmwarevm/Virtual Disk-flat.vmdk" conv=notrunc 40 | - Write the final FAT12 image to a .qcow2 file for UTM (on Apple Silicon): 41 | qemu-img convert -O qcow2 kaos64.img kaos64.qcow2 42 | - Everything in one command: 43 | clear && docker run --rm -it -v $HOME/dev/GitHub/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/clean.sh && docker run --rm -it -v $HOME/Documents/GitHub/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh && dd if="$HOME/Documents/GitHub/SQLpassion/osdev/main64/kaos64.img" of="$HOME/Documents/Virtual Machines/KAOS.vmwarevm/Virtual Disk-flat.vmdk" conv=notrunc 44 | 45 | ########################### 46 | # Run on physical Notebook 47 | ########################### 48 | - Write the final FAT12 image to a physical disk: 49 | Mac: 50 | ls /dev/d* 51 | sudo dd if=kaos64.img of=/dev/disk2 (where /dev/disk2 is the attached physical hard disk!) 52 | Windows: 53 | wmic diskdrive list brief 54 | ./dd.exe if=d:\github\sqlpassion\osdev\main64\kaos64.img of=\\.\PhysicalDrive2 (where \\.\PhysicalDrive2 is the attached physical hard disk!) 55 | ./dd.exe if=\\.\PhysicalDrive2 of=d:\kaos64.ima bs=512 count=2880 56 | 57 | ############### 58 | # Git Commands 59 | ############### 60 | 61 | # Merge feature branch into main: 62 | git checkout main 63 | git merge --no-ff MyFeatureBranch 64 | git push origin main 65 | 66 | # Delete branch locally and remote: 67 | git branch -d MyFeatureBranch 68 | git push origin --delete MyFeatureBranch 69 | 70 | # Tag the current state, and push it to the remote repository 71 | git tag MyTagName main 72 | git push origin MyTagName -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 - 2023 Klaus Aschenbrenner, www.SQLpassion.at 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OS Development 2 | 3 | This repository contains OS development specific code. 4 | More information: https://www.SQLpassion.at/archive/category/osdev/ 5 | -------------------------------------------------------------------------------- /docker-buildenv/Dockerfile: -------------------------------------------------------------------------------- 1 | ############### 2 | # Image Build 3 | ############### 4 | # If the image is built on Apple Silicon (M1, M2), you have to disable the setting "Use Rosetta for x86/amd64 emulation on Apple Sillicon" 5 | # within the Docker Desktop settings. 6 | # On lower end machines (like the Apple Air M1 with 8 GB RAM), you also have to specify a lower value for the "make -j" flag (like "-j 4"). 7 | # Otherwise you could run into Out-Of-Memory conditions during the GCC build. 8 | 9 | # docker image build -t sqlpassion/kaos-buildenv:latest . 10 | 11 | # Use the latest Alpine image as a base 12 | FROM --platform=linux/amd64 alpine:latest as builder 13 | 14 | # Install all needed packages 15 | RUN apk add wget 16 | RUN apk add g++ 17 | RUN apk add make 18 | RUN apk add flex 19 | RUN apk add bison 20 | RUN apk add texinfo 21 | RUN apk add gmp-dev 22 | RUN apk add mpfr-dev 23 | RUN apk add mpc1-dev 24 | 25 | # Create a new souce directory 26 | RUN mkdir $HOME/src 27 | WORKDIR $HOME/src 28 | 29 | # Download the current version of GCC and the binutils 30 | RUN wget ftp://ftp.gnu.org/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.gz 31 | RUN wget https://ftp.gnu.org/gnu/binutils/binutils-2.40.tar.gz 32 | 33 | RUN tar -xf binutils-2.40.tar.gz 34 | RUN tar -xf gcc-12.2.0.tar.gz 35 | 36 | ############################### 37 | # Build the x64 Cross Compiler 38 | ############################### 39 | 40 | ENV PREFIX="$HOME/opt/cross" 41 | ENV TARGET=x86_64-elf 42 | ENV PATH="$PREFIX/bin:$PATH" 43 | 44 | RUN mkdir build-binutils 45 | WORKDIR build-binutils 46 | 47 | RUN ../binutils-2.40/configure --target=$TARGET --prefix=$PREFIX --with-sysroot --disable-nls --disable-werror 48 | RUN make -j 8 49 | RUN make -j 8 install 50 | 51 | WORKDIR $HOME/src 52 | 53 | RUN mkdir build-gcc 54 | WORKDIR build-gcc 55 | 56 | RUN ../gcc-12.2.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers 57 | RUN make -j 8 all-gcc 58 | RUN make -j 8 install-gcc 59 | 60 | ############# 61 | # fat_imgen 62 | ############# 63 | 64 | RUN mkdir /build 65 | WORKDIR build 66 | RUN wget https://sourceforge.net/projects/fatimgen/files/fat_imgen%202.2.4/fat_imgen-2.2.4-Linux-amd64.tar.bz2 67 | RUN tar -xf fat_imgen-2.2.4-Linux-amd64.tar.bz2 68 | WORKDIR fat_imgen-2.2.4 69 | RUN cp fat_imgen /opt/cross/bin/fat_imgen 70 | 71 | ###################################### 72 | # Building of the final Docker Image 73 | ###################################### 74 | 75 | # Create a new image and copy the built cross compiler into it 76 | FROM --platform=linux/amd64 alpine:latest 77 | COPY --from=builder /opt /opt 78 | 79 | # Install additional needed packages 80 | RUN apk add nasm 81 | RUN apk add make 82 | RUN apk add gmp-dev 83 | RUN apk add mpfr-dev 84 | RUN apk add mpc1-dev 85 | RUN apk add build-base gcompat 86 | 87 | # Export the cross compilers 88 | ENV PATH="$HOME/opt/cross/bin:$PATH" 89 | 90 | ######## 91 | # Usage 92 | ######## 93 | # If you run the image on Apple Silicon (M1, M2), you have to *enable* the setting "Use Rosetta for x86/amd64 emulation on Apple Sillicon" 94 | # within the Docker Desktop settings. 95 | 96 | # docker run --rm -it -v d:\GitHub\SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh 97 | # docker run --rm -it -v $HOME/Documents/GitHub/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh 98 | 99 | # Windows ARM with WSL2 100 | # sudo docker run --rm -it -v /mnt/c/Users/klaus/documents/github/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/build.sh 101 | # sudo docker run --rm -it -v /mnt/c/Users/klaus/documents/github/SQLpassion/osdev:/src sqlpassion/kaos-buildenv /bin/sh /src/main64/clean.sh -------------------------------------------------------------------------------- /main64/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "keyboard.h": "c" 4 | } 5 | } -------------------------------------------------------------------------------- /main64/MemoryMap.txt: -------------------------------------------------------------------------------- 1 | Real Mode 2 | ========= 3 | 0x000500 - 0x004500: FAT Root Directory and FAT Tables (32 Sectors) 4 | 0x001000 - 0x0011FF: BIOS Information Block 5 | 0x001200 - 0x001FFF: Memory Map 6 | 0x002000 - 0x002FFF: KLDR16.BIN 7 | 0x003000 - 0x007BFF: KLDR64.BIN 8 | 0x007c00 - 0x007e00: Boot Sector 9 | 0x007e00 - 0x008000: Real Mode Stack (512 Bytes) 10 | 0x009000 to 0x009FFF: Page Map Level 4 11 | 0x010000 to 0x010FFF: Page Directory Pointer Table 12 | 0x011000 to 0x011FFF: Page Directory Table 13 | 0x012000 to 0x012FFF: Page Table 1 (Identity Mapping of 0 - 2 MB: 0x000000 to 0x1FFFFF) 14 | 0x014000 to 0x014FFF: Page Directory Pointer Table for the Higher Half Mapping of the Kernel 15 | 0x015000 to 0x015FFF: Page Directory Table for the Higher Half Mapping of the Kernel 16 | 0x016000 to 0x016FFF: Page Table for the Higher Half Mapping of the Kernel 17 | 18 | Long Mode Physical Memory 19 | ========================= 20 | 0x001000 - 0x001FFF: BIOS Information Block 21 | 0x030000 - 0x031BFF: Root Directory Buffer used by KLDR64.BIN 22 | 0x031C00 - 0x033FFF: FAT Buffer used by KLDR64.BIN 23 | 0x034000 - 0x050000: x64 Kernel Stack 24 | 0x060000 - 0x060FFF: x64 IDT Table 25 | 0x061000 - 0x061FFF: x64 GDT Table 26 | 0x062000 - 0x062FFF: x64 TSS Table 27 | 0x063000 - 0x063FFF: Structure "RegisterState" for Exception Handlers 28 | 0x064000 - 0x064FFF: Structure "SysCallRegisters" for Sys Calls 29 | 0x100000 - 0x1?????: KERNEL.BIN 30 | Afterwards: Physical Memory Manager Structures 31 | Physical Page Frames allocated by the Physical Memory Manager 32 | 33 | Long Mode Virtual Memory 34 | ======================== 35 | 0xFFFF800000030000 - 0xFFFF800000050000: x64 Kernel Stack 36 | 0xFFFF800000060000 - 0xFFFF800000060FFF: x64 IDT Table 37 | 0xFFFF800000061000 - 0xFFFF800000061FFF: Structure "RegisterState" for Exception Handlers 38 | 0xFFFF800000100000 - 0xFFFF8000001?????: KERNEL.BIN 39 | Afterwards: Physical Memory Manager Structures -------------------------------------------------------------------------------- /main64/SFile.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor 2 | incididunt ut labore et dolore magna aliqua. Velit scelerisque in dictum non 3 | consectetur a erat. Sit amet justo donec enim diam vulputate. Id aliquet 4 | lectus proin nibh nisl condimentum id venenatis a. Eget gravida cum sociis 5 | natoque penatibus et magnis dis. Habitant morbi tristique senectus et netus 6 | et. Interdum consectetur libero id faucibus nisl tincidunt eget nullam. 7 | Aliquam purus sit amet luctus. Fringilla ut morbi tincidunt augue interdum 8 | velit. Neque sodales ut etiam sit. Quam viverra orci sagittis eu volutpat 9 | odio facilisis mauris. Ornare suspendisse sed nisi lacus sed. Iaculis at 10 | erat pellentesque adipiscing commodo elit at imperdiet dui. Quam nulla 11 | porttitor massa id neque aliquam vestibulum morbi. Dignissim diam quis 12 | enim lobortis scelerisque fermentum dui faucibus. Turpis egestas integer 13 | eget aliquet. 14 | 15 | End of File... -------------------------------------------------------------------------------- /main64/ScanCodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLpassion/osdev/d191745b1548b519c3d21d6a45532e045f0c0b12/main64/ScanCodes.png -------------------------------------------------------------------------------- /main64/StringHashing.txt: -------------------------------------------------------------------------------- 1 | Source: https://www.codingninjas.com/studio/library/string-hashing-2425 2 | 3 | String Hashing 4 | 5 | Introduction 6 | In this blog, we will discuss the topic of string hashing. String hashing is a very interesting as well as an important topic. String hashing based-coding problems are widely asked in coding contests and various coding interviews. 7 | 8 | String Hashing 9 | String hashing is the technique or process of mapping string and integer. In other words, String hashing is the way to convert the string into an integer, and that integer is known as the hash of a string. 10 | 11 | String hashing is used to compare two strings whether they are equal or not. They both are equal if the hash value of both the string is equal. The hash value of the string is calculated by using a hash function. Let’s discuss the hash function to convert a string into an integer. 12 | 13 | What is Hash Function? 14 | String hash function is the function that converts a string into an integer. The hash of a string can be calculated as: 15 | 16 | Hash(S) =(S[0] * P^0 + S[1] * P^1 +S[2] * P^2 + …….+ S[N-1] * P^(N-1)) % M 17 | 18 | Where, 19 | 20 | ‘S’ is the given string. 21 | 22 | ‘P’ is the prime number that must be greater than or equal to the number of distinct characters in the string ‘S’. 23 | 24 | ‘M’ should be large to avoid the collision. 25 | 26 | The above function is known as the polynomial rolling hash function. 27 | 28 | Collision 29 | It may be possible that two different strings have the same hash values. This may occur because we take modulo ‘M’ in the final hash value. In that case, two different strings may have the same hash values, called a collision. We need to design our hash function so that the collision probability is very low. One way to reduce the chances of collision is that not take the mod of the final hash value with ‘M’. But this is not efficient as the hash value may be very large, and our storage memory is limited. 30 | 31 | Another way to reduce the collision probability is to take the value of ‘M’ as large as possible. 32 | 33 | The probability of collision is 1 / M. 34 | 35 | Example 36 | The hash of string S = “cat” can be calculated as: 37 | 38 | hash(S) = (‘c’ - ‘a’) + (‘a’ - ‘a’) * 31 + (‘c’ - ‘a’) * 31^2. 39 | 40 | Here, P = 31 as all the characters are in lowercase, so the count of all distinct lowercase characters is 26, and 31 is the prime number and greater than 26. 41 | 42 | Problem Statement 43 | You are given ‘N’ string. Write a program to check whether all the strings are distinct or not using string hashing. 44 | 45 | Algorithm 46 | Define a function hashing(): 47 | Function details: 48 | Takes string ‘S’ as a parameter. 49 | This function returns the hash value of ‘S’. 50 | Working: 51 | Create variable ANS = 0. 52 | Create variable P = 1. 53 | Create variable M = 10e9 +7. 54 | Iterate loop for each character of string: 55 | ANS += (S[i] - 'a') * P; 56 | P *= 31; 57 | Return ‘ANS’. 58 | Call the hashing function for all strings and store their hash values in the array. 59 | Sort the array. 60 | Check whether the adjacent hash values are equal or not. 61 | Program 62 | // Program to check whether all the strings are distinct or not using string hashing. 63 | #include 64 | #include 65 | #include 66 | #include 67 | using namespace std; 68 | 69 | // Function to find the hash of string. 70 | int hashing(string s) 71 | { 72 | // To store the hash value. 73 | int ans = 0; 74 | 75 | // To store 'P'. 76 | int p = 1; 77 | 78 | // For taking modulo. 79 | int m = 1000000007; 80 | for (int i = 0; i < s.size(); i++) 81 | { 82 | ans += (s[i] - 'a') * p; 83 | ans = ans % m; 84 | p *= 31; 85 | } 86 | return ans; 87 | } 88 | 89 | int main() 90 | { 91 | 92 | // Taking number of strings as input. 93 | int n; 94 | cin >> n; 95 | 96 | // Taking strings as an input. 97 | vector> vec(n); 98 | for (int i = 0; i < n; i++) 99 | { 100 | string temp; 101 | cin >> temp; 102 | 103 | // Function call. 104 | vec[i].first = hashing(temp); 105 | vec[i].second = temp; 106 | } 107 | 108 | // Sort the vector. 109 | sort(vec.begin(), vec.end()); 110 | int i; 111 | for (i = 0; i < n - 1; i++) 112 | { 113 | if (vec[i] == vec[i + 1]) 114 | { 115 | break; 116 | } 117 | } 118 | if (i == n - 1) 119 | cout << "All strings are distinct"; 120 | else 121 | cout << "All strings are not distinct"; 122 | } 123 | 124 | Input 1 125 | 126 | 4 127 | cat 128 | bat 129 | cat 130 | gat 131 | Output 1 132 | All strings are not distinct 133 | Input 2 134 | 4 135 | cat 136 | bat 137 | gat 138 | Output 2 139 | All strings are distinct 140 | Time Complexity 141 | O(N * K), where ‘N’ is the number of strings and ‘K’ is the maximum length of string among them. 142 | Hashing function traverses each character of the string, which takes O(K) time. And total number of strings is N. Hence total time complexity for this program is O(N * K). 143 | 144 | Space Complexity 145 | O(1). 146 | As we didn’t use extra space except for a few variables. 147 | Check out this problem - Longest String Chain 148 | 149 | Also Read - hash function in data structure -------------------------------------------------------------------------------- /main64/bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # configuration file generated by Bochs 2 | plugin_ctrl: voodoo=false, unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, busmouse=false, e1000=false, es1370=false, gameport=true, ne2k=false, sb16=false, usb_uhci=false, usb_ohci=false, usb_ehci=false, usb_xhci=false 3 | config_interface: win32config 4 | display_library: win32 5 | memory: host=1024, guest=1024 6 | romimage: file="C:\Program Files\Bochs-2.7/BIOS-bochs-latest", address=0x00000000, options=none 7 | vgaromimage: file="C:\Program Files\Bochs-2.7/VGABIOS-lgpl-latest" 8 | boot: disk 9 | floppy_bootsig_check: disabled=0 10 | floppya: type=1_44 11 | # no floppyb 12 | ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 13 | ata0-master: type=disk, path="D:\GitHub\SQLpassion\osdev\main64\kaos64.img", mode=flat, cylinders=1, heads=2, spt=18, sect_size=512, model="Generic 1234", biosdetect=auto, translation=lba 14 | ata0-slave: type=none 15 | ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15 16 | ata1-master: type=none 17 | ata1-slave: type=none 18 | ata2: enabled=false 19 | ata3: enabled=false 20 | optromimage1: file=none 21 | optromimage2: file=none 22 | optromimage3: file=none 23 | optromimage4: file=none 24 | optramimage1: file=none 25 | optramimage2: file=none 26 | optramimage3: file=none 27 | optramimage4: file=none 28 | pci: enabled=1, chipset=i440fx, slot1=none, slot2=none, slot3=none, slot4=none, slot5=none 29 | vga: extension=vbe, update_freq=5, realtime=1, ddc=builtin 30 | cpu: count=1, ips=4000000, model=corei7_sandy_bridge_2600k, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 31 | print_timestamps: enabled=0 32 | port_e9_hack: enabled=0 33 | private_colormap: enabled=0 34 | clock: sync=none, time0=local, rtc_sync=0 35 | # no cmosimage 36 | log: - 37 | logprefix: %t%e%d 38 | debug: action=ignore 39 | info: action=report 40 | error: action=report 41 | panic: action=ask 42 | keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none 43 | mouse: type=ps2, enabled=false, toggle=ctrl+mbutton 44 | sound: waveoutdrv=win, waveout=none, waveindrv=win, wavein=none, midioutdrv=win, midiout=none 45 | speaker: enabled=true, mode=sound, volume=15 46 | parport1: enabled=true, file=none 47 | parport2: enabled=false 48 | com1: enabled=true, mode=null 49 | com2: enabled=false 50 | com3: enabled=false 51 | com4: enabled=false 52 | -------------------------------------------------------------------------------- /main64/boot/bootsector.asm: -------------------------------------------------------------------------------- 1 | ; Tell the Assembler that the boot sector is loaded at the offset 0x7C00 2 | [ORG 0x7C00] 3 | [BITS 16] 4 | 5 | JMP Main ; Jump over the BPB directly to start of the boot loader 6 | NOP ; This padding of 1 additional byte is needed, because the 7 | ; BPB starts at offset 0x03 in the boot sector 8 | 9 | ;********************************************* 10 | ; BIOS Parameter Block (BPB) for FAT12 11 | ;********************************************* 12 | bpbOEM DB "KAOS " 13 | bpbBytesPerSector: DW 512 14 | bpbSectorsPerCluster: DB 1 15 | bpbReservedSectors: DW 1 16 | bpbNumberOfFATs: DB 2 17 | bpbRootEntries: DW 224 18 | bpbTotalSectors: DW 2880 19 | bpbMedia: DB 0xF0 20 | bpbSectorsPerFAT: DW 9 21 | bpbSectorsPerTrack: DW 18 22 | bpbHeadsPerCylinder: DW 2 23 | bpbHiddenSectors: DD 0 24 | bpbTotalSectorsBig: DD 0 25 | bsDriveNumber: DB 0 26 | bsUnused: DB 0 27 | bsExtBootSignature: DB 0x29 28 | bsSerialNumber: DD 0xa0a1a2a3 29 | bsVolumeLabel: DB "KAOS DRIVE " 30 | bsFileSystem: DB "FAT12 " 31 | 32 | Main: 33 | ; Setup the DS and ES register 34 | XOR AX, AX 35 | MOV DS, AX 36 | MOV ES, AX 37 | 38 | ; Prepare the stack 39 | ; Otherwise we can't call a function... 40 | MOV AX, 0x7000 41 | MOV SS, AX 42 | MOV BP, 0x8000 43 | MOV SP, BP 44 | 45 | ; Print out a boot message 46 | MOV SI, BootMessage 47 | CALL PrintLine 48 | 49 | ; Load the KLDR64.BIN file into memory 50 | MOV CX, 11 51 | LEA SI, [SecondStageFileName64] 52 | LEA DI, [FileName] 53 | REP MOVSB 54 | MOV WORD [Loader_Offset], KAOSLDR64_OFFSET 55 | CALL LoadFileIntoMemory 56 | 57 | ; Load the KLDR16.BIN file into memory 58 | MOV CX, 11 59 | LEA SI, [SecondStageFileName16] 60 | LEA DI, [FileName] 61 | REP MOVSB 62 | MOV WORD [Loader_Offset], KAOSLDR16_OFFSET 63 | CALL LoadFileIntoMemory 64 | 65 | ; Execute the KLDR16.BIN file... 66 | CALL KAOSLDR16_OFFSET 67 | 68 | ; Include some helper functions 69 | %INCLUDE "../boot/functions.asm" 70 | 71 | ; OxA: New Line 72 | ; 0xD: Carriage Return 73 | ; 0x0: Null Terminated String 74 | BootMessage: DB 'Booting KAOS...', 0xD, 0xA, 0x0 75 | ROOTDIRECTORY_AND_FAT_OFFSET EQU 0x500 76 | KAOSLDR16_OFFSET EQU 0x2000 77 | KAOSLDR64_OFFSET EQU 0x3000 78 | Loader_Offset DW 0x0000 79 | FileName DB 11 DUP (" ") 80 | SecondStageFileName16 DB "KLDR16 BIN" 81 | SecondStageFileName64 DB "KLDR64 BIN" 82 | FileReadError DB 'Failure', 0 83 | Cluster DW 0x0000 84 | CRLF: DB 0xD, 0xA, 0x0 85 | 86 | ; Padding and magic number 87 | TIMES 510 - ($-$$) DB 0 88 | DW 0xAA55 -------------------------------------------------------------------------------- /main64/boot/functions.asm: -------------------------------------------------------------------------------- 1 | ;================================================ 2 | ; This function prints a whole string, where the 3 | ; input string is stored in the register "SI" 4 | ;================================================ 5 | PrintLine: 6 | ; Set the TTY mode 7 | MOV AH, 0xE 8 | INT 10 9 | 10 | ; Set the input string 11 | MOV AL, [SI] 12 | CMP AL, 0 13 | JE PrintLine_End 14 | 15 | INT 0x10 16 | INC SI 17 | JMP PrintLine 18 | 19 | PrintLine_End: 20 | RET 21 | 22 | ;================================================ 23 | ; This function prints out a decimal number 24 | ; that is stored in the register AX. 25 | ;================================================ 26 | PrintDecimal: 27 | MOV CX, 0 28 | MOV DX, 0 29 | 30 | .PrintDecimal_Start: 31 | CMP AX ,0 32 | JE .PrintDecimal_Print 33 | MOV BX, 10 34 | DIV BX 35 | PUSH DX 36 | INC CX 37 | XOR DX, DX 38 | JMP .PrintDecimal_Start 39 | .PrintDecimal_Print: 40 | CMP CX, 0 41 | JE .PrintDecimal_Exit 42 | POP DX 43 | 44 | ; Add 48 so that it represents the ASCII value of digits 45 | MOV AL, DL 46 | ADD AL, 48 47 | MOV AH, 0xE 48 | INT 0x10 49 | 50 | DEC CX 51 | JMP .PrintDecimal_Print 52 | .PrintDecimal_Exit: 53 | RET 54 | 55 | ;================================================ 56 | ; This function checks the ATA PIO BSY flag. 57 | ;================================================ 58 | Check_ATA_BSY: 59 | MOV DX, 0x1F7 60 | IN AL, DX 61 | TEST AL, 0x80 62 | JNZ Check_ATA_BSY 63 | RET 64 | 65 | ;================================================ 66 | ; This function checks the ATA PIO DRQ flag. 67 | ;================================================ 68 | Check_ATA_DRQ: 69 | MOV DX, 0x1F7 70 | IN AL, DX 71 | TEST AL, 0x08 72 | JZ Check_ATA_DRQ 73 | RET 74 | 75 | ;================================================ 76 | ; This function reads a sector through ATA PIO. 77 | ; BX: Nunber of sectors to read 78 | ; ECX: Starting LBA 79 | ; EDI: Destination Address 80 | ;================================================ 81 | ReadSector: 82 | ; Sector count 83 | MOV DX, 0x1F2 84 | MOV AL, BL 85 | OUT DX, AL 86 | 87 | ; LBA - Low Byte 88 | MOV DX, 0x1F3 89 | MOV AL, CL 90 | OUT DX, AL 91 | 92 | ; LBA - Middle Byte 93 | MOV DX, 0x1F4 94 | MOV AL, CH 95 | OUT DX, AL 96 | 97 | ; LBA - High Byte 98 | BSWAP ECX 99 | MOV DX, 0x1F5 100 | MOV AL, CH 101 | OUT DX, AL 102 | 103 | ; Read Command 104 | MOV DX, 0x1F7 105 | MOV AL, 0x20 ; Read Command 106 | OUT DX, AL 107 | 108 | .ReadNextSector: 109 | CALL Check_ATA_BSY 110 | CALL Check_ATA_DRQ 111 | 112 | ; Read the sector of 512 bytes into ES:EDI 113 | ; EDI is incremented by 512 bytes automatically 114 | MOV DX, 0x1F0 115 | MOV CX, 256 116 | REP INSW 117 | 118 | ; Decrease the number of sectors to read and compare it to 0 119 | DEC BX 120 | CMP BX, 0 121 | JNE .ReadNextSector 122 | RET 123 | 124 | ;================================= 125 | ; Loads a given file into memory. 126 | ;================================= 127 | LoadFileIntoMemory: 128 | .LoadRootDirectory: 129 | ; Load the Root Directory into memory. 130 | ; It starts at the LBA 19, and consists of 14 sectors. 131 | MOV BL, 0xE ; 14 sectors to be read 132 | MOV ECX, 0x13 ; The LBA is 19 133 | MOV EDI, ROOTDIRECTORY_AND_FAT_OFFSET ; Destination address 134 | CALL ReadSector ; Loads the complete Root Directory into memory 135 | 136 | .FindFileInRootDirectory: 137 | ; Now we have to find our file in the Root Directory 138 | MOV CX, [bpbRootEntries] ; The number of root directory entries 139 | MOV DI, ROOTDIRECTORY_AND_FAT_OFFSET ; Address of the Root directory 140 | .Loop: 141 | PUSH CX 142 | MOV CX, 11 ; We compare 11 characters (8.3 convention) 143 | MOV SI, FileName ; Compare against the file name 144 | PUSH DI 145 | REP CMPSB ; Test for string match 146 | 147 | POP DI 148 | JE .LoadFAT ; When we have a match, we load the FAT 149 | POP CX 150 | ADD DI, 32 ; When we don't have a match, we go to next root directory entry (+ 32 bytes) 151 | LOOP .Loop 152 | JMP Failure ; The file image wasn't found in the root directory 153 | 154 | .LoadFAT: 155 | ; Store the first FAT cluster of the file to be read in the variable "Cluster" 156 | MOV DX, WORD [DI + 0x001A] ; Add 26 bytes to the current entry of the root directory, so that we get the start cluster 157 | MOV WORD [Cluster], DX ; Store the 2 bytes of the start cluster (byte 26 & 27 of the root directory entry) in the variable "cluster" 158 | 159 | ; Load the FATs into memory. 160 | ; It starts at the LBA 1 (directly after the boot sector), and consists of 18 sectors (2 x 9). 161 | MOV BL, 0x12 ; 18 sectors to be read 162 | MOV ECX, 0x1 ; The LBA is 1 163 | MOV EDI, ROOTDIRECTORY_AND_FAT_OFFSET ; Offset in memory at which we want to load the FATs 164 | CALL ReadSector ; Call the load routine 165 | MOV EDI, [Loader_Offset] ; Address where the first cluster should be stored 166 | 167 | .LoadImage: 168 | ; Print out the current offset where the cluster is loaded into memory 169 | MOV AX, DI 170 | CALL PrintDecimal 171 | MOV SI, CRLF 172 | CALL PrintLine 173 | 174 | ; Load the first sector of the file into memory 175 | MOV AX, WORD [Cluster] ; First FAT cluster to read 176 | ADD AX, 0x1F ; Add 31 sectors to the retrieved FAT cluster to get the LBA address of the first FAT cluster 177 | MOV ECX, EAX ; LBA 178 | MOV BL, 1 ; 1 sector to be read 179 | CALL ReadSector ; Read the cluster into memory 180 | 181 | ; Compute the next cluster that we have to load from disk 182 | MOV AX, WORD [Cluster] ; identify current cluster 183 | MOV CX, AX ; copy current cluster 184 | MOV DX, AX ; copy current cluster 185 | SHR DX, 0x0001 ; divide by two 186 | ADD CX, DX ; sum for (3/2) 187 | MOV BX, ROOTDIRECTORY_AND_FAT_OFFSET ; location of FAT in memory 188 | ADD BX, CX ; index into FAT 189 | MOV DX, WORD [BX] ; read two bytes from FAT 190 | TEST AX, 0x0001 191 | JNZ .LoadRootDirectoryOddCluster 192 | 193 | .LoadRootDirectoryEvenCluster: 194 | AND DX, 0000111111111111b ; Take the lowest 12 bits 195 | JMP .LoadRootDirectoryDone 196 | 197 | .LoadRootDirectoryOddCluster: 198 | SHR DX, 0x0004 ; Take the highest 12 bits 199 | 200 | .LoadRootDirectoryDone: 201 | MOV WORD [Cluster], DX ; store new cluster 202 | CMP DX, 0x0FF0 ; Test for end of file 203 | JB .LoadImage 204 | 205 | .LoadRootDirectoryEnd: 206 | ; Restore the stack, so that we can do a RET 207 | POP BX 208 | RET 209 | 210 | Failure: 211 | MOV SI, FileReadError 212 | CALL PrintLine 213 | 214 | ; Endless loop 215 | JMP $ -------------------------------------------------------------------------------- /main64/build.sh: -------------------------------------------------------------------------------- 1 | # Builds the KLDR16 2 | cd /src/main64/kaosldr_16 3 | make clean && make 4 | 5 | # Builds the KLDR64 6 | cd /src/main64/kaosldr_64 7 | make clean && make 8 | 9 | # Build the program1 10 | cd /src/main64/programs/program1 11 | make clean && make 12 | 13 | # Build the program2 14 | cd /src/main64/programs/program2 15 | make clean && make 16 | 17 | # Builds the command shell 18 | cd /src/main64/programs/shell 19 | make clean && make 20 | 21 | # Builds the kernel 22 | cd /src/main64/kernel 23 | make clean && make -------------------------------------------------------------------------------- /main64/clean.sh: -------------------------------------------------------------------------------- 1 | # Remove the built KLDR16.BIN 2 | cd /src/main64/kaosldr_16 3 | make clean 4 | 5 | # Remove the built KLDR64.BIN 6 | cd /src/main64/kaosldr_64 7 | make clean 8 | 9 | # Remove the built kernel 10 | cd /src/main64/kernel 11 | make clean 12 | 13 | # Remove the program1 14 | cd /src/main64/programs/program1 15 | make clean 16 | 17 | # Remove the program2 18 | cd /src/main64/programs/program2 19 | make clean 20 | 21 | # Removes the command shell 22 | cd /src/main64/programs/shell 23 | make clean -------------------------------------------------------------------------------- /main64/fatgen.bat: -------------------------------------------------------------------------------- 1 | REM The following commands are building the kaos64.img file from which we can boot the OS 2 | fat_imgen -c -s boot/bootsector.bin -f kaos64.img 3 | fat_imgen -m -f kaos64.img -i kaosldr_16/kldr16.bin 4 | fat_imgen -m -f kaos64.img -i kaosldr_64/kldr64.bin 5 | fat_imgen -m -f kaos64.img -i kernel/kernel.bin -------------------------------------------------------------------------------- /main64/kaosldr_16/functions.asm: -------------------------------------------------------------------------------- 1 | ;************************************************; 2 | ; This file contains some helper functions. 3 | ;************************************************; 4 | 5 | ; This structure stores all the information that we retrieve from the BIOS while we are in x16 Real Mode 6 | STRUC BiosInformationBlock 7 | .Year: RESD 1 8 | .Month: RESW 1 9 | .Day: RESW 1 10 | .Hour: RESW 1 11 | .Minute: RESW 1 12 | .Second: RESW 1 13 | 14 | .MemoryMapEntries RESW 1 ; Number of Memory Map entries 15 | .AvailableMemory RESQ 1 ; Available Memory - will be calculated by the Kernel 16 | ENDSTRUC 17 | 18 | ; This structure represents a memory map entry that we have retrieved from the BIOS 19 | STRUC MemoryMapEntry 20 | .BaseAddress RESQ 1 ; base address of address range 21 | .Length RESQ 1 ; length of address range in bytes 22 | .Type RESD 1 ; type of address range 23 | .ACPI_NULL RESD 1 ; reserved 24 | ENDSTRUC 25 | 26 | ;================================================ 27 | ; This function prints a whole string, where the 28 | ; input string is stored in the register "SI" 29 | ;================================================ 30 | PrintString: 31 | ; Set the TTY mode 32 | MOV AH, 0xE 33 | INT 10 34 | 35 | ; Set the input string 36 | MOV AL, [SI] 37 | CMP AL, 0 38 | JE PrintString_End 39 | 40 | INT 0x10 41 | INC SI 42 | JMP PrintString 43 | 44 | PrintString_End: 45 | RET 46 | 47 | ;================================================ 48 | ; This function prints out a decimal number 49 | ; that is stored in the register AX. 50 | ;================================================ 51 | PrintDecimal: 52 | MOV CX, 0 53 | MOV DX, 0 54 | 55 | PrintDecimal_Start: 56 | CMP AX ,0 57 | JE PrintDecimal_Print 58 | MOV BX, 10 59 | DIV BX 60 | PUSH DX 61 | INC CX 62 | XOR DX, DX 63 | JMP PrintDecimal_Start 64 | PrintDecimal_Print: 65 | CMP CX, 0 66 | JE PrintDecimal_Exit 67 | POP DX 68 | 69 | ; Add 48 so that it represents the ASCII value of digits 70 | MOV AL, DL 71 | ADD AL, 48 72 | MOV AH, 0xE 73 | INT 0x10 74 | 75 | DEC CX 76 | JMP PrintDecimal_Print 77 | PrintDecimal_Exit: 78 | RET 79 | 80 | ;================================================ 81 | ; This function converts a BCD number to a 82 | ; decimal number. 83 | ;================================================ 84 | Bcd2Decimal: 85 | MOV CL, AL 86 | SHR AL, 4 87 | MOV CH, 10 88 | MUL CH 89 | AND CL, 0Fh 90 | ADD AL, CL 91 | RET 92 | 93 | ;================================================= 94 | ; This function retrieves the date from the BIOS. 95 | ;================================================= 96 | GetDate: 97 | ; Get the current date from the BIOS 98 | MOV AH, 0x4 99 | INT 0x1A 100 | 101 | ; Century 102 | PUSH CX 103 | MOV AL, CH 104 | CALL Bcd2Decimal 105 | MOV [Year1], AX 106 | POP CX 107 | 108 | ; Year 109 | MOV AL, CL 110 | CALL Bcd2Decimal 111 | MOV [Year2], AX 112 | 113 | ; Month 114 | MOV AL, DH 115 | CALL Bcd2Decimal 116 | MOV WORD [ES:DI + BiosInformationBlock.Month], AX 117 | 118 | ; Day 119 | MOV AL, DL 120 | CALL Bcd2Decimal 121 | MOV WORD [ES:DI + BiosInformationBlock.Day], AX 122 | 123 | ; Calculate the whole year (e.g. "20" * 100 + "22" = 2022) 124 | MOV AX, [Year1] 125 | MOV BX, 100 126 | MUL BX 127 | MOV BX, [Year2] 128 | ADD AX, BX 129 | MOV WORD [ES:DI + BiosInformationBlock.Year], AX 130 | RET 131 | 132 | ;================================================= 133 | ; This function retrieves the time from the BIOS. 134 | ;================================================= 135 | GetTime: 136 | ; Get the current time from the BIOS 137 | MOV AH, 0x2 138 | INT 0x1A 139 | 140 | ; Hour 141 | PUSH CX 142 | MOV AL, CH 143 | CALL Bcd2Decimal 144 | MOV WORD [ES:DI + BiosInformationBlock.Hour], AX 145 | POP CX 146 | 147 | ; Minute 148 | MOV AL, CL 149 | CALL Bcd2Decimal 150 | MOV WORD [ES:DI + BiosInformationBlock.Minute], AX 151 | 152 | ; Second 153 | MOV AL, DH 154 | CALL Bcd2Decimal 155 | MOV WORD [ES:DI + BiosInformationBlock.Second], AX 156 | RET 157 | 158 | ;============================================= 159 | ; This function enables the A20 gate 160 | ;============================================= 161 | EnableA20: 162 | CLI ; Disables interrupts 163 | PUSH AX ; Save AX on the stack 164 | MOV AL, 2 165 | OUT 0x92, AL 166 | POP AX ; Restore the value of AX from the stack 167 | STI ; Enable the interrupts again 168 | RET 169 | 170 | ;================================================= 171 | ; This function gets the Memory Map from the BIOS 172 | ;================================================= 173 | GetMemoryMap: 174 | MOV DI, MEM_OFFSET ; Set DI to the memory location, where we store the memory map entries 175 | 176 | PUSHAD 177 | XOR EBX, EBX 178 | XOR BP, BP ; Number of entries are stored in the BP register 179 | MOV EDX, 'PAMS' 180 | MOV EAX, 0xe820 181 | MOV ECX, 24 ; The size of a Memory Map entry is 24 bytes long 182 | INT 0x15 ; Get the first entry 183 | JC .Error 184 | CMP EAX, 'PAMS' 185 | JNE .Error 186 | TEST EBX, EBX ; If EBX = 0, then there is only 1 entry, and we are finished 187 | JECXZ .Error 188 | JMP .Start 189 | .NextEntry: 190 | MOV EDX, 'PAMS' 191 | MOV ECX, 24 ; The size of a Memory Map entry is 24 bytes long 192 | MOV EAX, 0xe820 193 | INT 0x15 ; Get the next entry 194 | .Start: 195 | JCXZ .SkipEntry ; If 0 bytes are returned, we skip this entry 196 | MOV ECX, [ES:DI + MemoryMapEntry.Length] ; Get the length (lower DWORD) 197 | TEST ECX, ECX ; If the length is 0, we skip the entry 198 | JNE SHORT .GoodEntry 199 | MOV ECX, [ES:DI + MemoryMapEntry.Length + 4] ; Get the length (upper DWORD) 200 | JECXZ .SkipEntry ; If the length is 0, we skip the entry 201 | .GoodEntry: 202 | INC BP ; Increment the number of entries 203 | ADD DI, 24 ; Point DI to the next memory entry buffer 204 | .SkipEntry: 205 | CMP EBX, 0 ; If EBX = 0, we are finished 206 | JNE .NextEntry ; Get the next entry 207 | JMP .Done 208 | .Error: 209 | XOR BX, BX 210 | MOV AH, 0x0e 211 | MOV AL, 'E' 212 | INT 0x10 213 | 214 | STC 215 | .Done: 216 | MOV DI, BIB_OFFSET 217 | MOV WORD [ES:DI + BiosInformationBlock.MemoryMapEntries], BP 218 | POPAD 219 | RET -------------------------------------------------------------------------------- /main64/kaosldr_16/kaosldr_entry.asm: -------------------------------------------------------------------------------- 1 | ; Tell the Assembler that KLDR16.BIN is loaded at the offset 0x2000 2 | [ORG 0x2000] 3 | [BITS 16] 4 | 5 | Main: 6 | ; Get the current date from the BIOS 7 | MOV DI, BIB_OFFSET 8 | CALL GetDate 9 | 10 | ; Get the current time from the BIOS 11 | CALL GetTime 12 | 13 | ; Get the Memory Map from the BIOS 14 | CALL GetMemoryMap 15 | 16 | ; Enables the A20 gate 17 | CALL EnableA20 18 | 19 | ; Print out a boot message 20 | MOV SI, BootMessage 21 | CALL PrintString 22 | 23 | ; Switch to x64 Long Mode and and execute the KLDR64.BIN file 24 | CALL SwitchToLongMode 25 | 26 | RET 27 | 28 | ; Include some helper functions 29 | %INCLUDE "functions.asm" 30 | %INCLUDE "longmode.asm" 31 | 32 | BIB_OFFSET EQU 0x1000 ; BIOS Information Block 33 | MEM_OFFSET EQU 0X1200 ; Memmory Map 34 | Year1 DW 0x00 35 | Year2 DW 0x00 36 | BootMessage: DB 'Booting KLDR16.BIN...', 0xD, 0xA, 0x0 -------------------------------------------------------------------------------- /main64/kaosldr_16/longmode.asm: -------------------------------------------------------------------------------- 1 | ; ================================================================= 2 | ; This file implements the functionality to identity map the first 3 | ; 2MB of physical memory (physical address == virtual address), 4 | ; and to switch the CPU into x64 Long Mode. 5 | ; 6 | ; It finally jumps to 0x3000 and executes the KLDR64.BIN file. 7 | ; ================================================================= 8 | 9 | %define PAGE_PRESENT (1 << 0) 10 | %define PAGE_WRITE (1 << 1) 11 | 12 | %define CODE_SEG 0x0008 13 | %define DATA_SEG 0x0010 14 | 15 | ALIGN 4 16 | 17 | IDT: 18 | .Length dw 0 19 | .Base dd 0 20 | 21 | ; ========================================= 22 | ; Memory Layout of the various Page Tables 23 | ; ========================================= 24 | ; [Page Map Level 4 at 0x9000] 25 | ; Entry 000: 0x10000 (ES:DI + 0x1000) 26 | ; Entry ... 27 | ; Entry 511 28 | 29 | ; [Page Directory Pointer Table at 0x10000] 30 | ; Entry 000: 0x11000 (ES:DI + 0x2000) 31 | ; Entry ... 32 | ; Entry 511 33 | 34 | ; [Page Directory Table at 0x11000] 35 | ; Entry 000: 0x12000 (ES:DI + 0x3000) 36 | ; Entry ... 37 | ; Entry 511 38 | 39 | ; [Page Table 1 at 0x12000] 40 | ; Entry 000: 0x000000 41 | ; Entry ... 42 | ; Entry 511: 0x1FF000 43 | 44 | ; ============================================================================= 45 | ; The following tables are needed for the Higher Half Mapping of the Kernel 46 | ; 47 | ; Beginning virtual address: 48 | ; 0xFFFF800000000000 49 | ; 1111111111111111 100000000 000000000 000000000 000000000 000000000000 50 | ; Sign Extension PML4T PDPT PDT PT Offset 51 | ; Entry 256 Entry 0 Entry 0 Entry 0 52 | ; ============================================================================= 53 | ; [Page Directory Pointer Table at 0x14000] 54 | ; Entry 000: 0x15000 (ES:DI + 0x6000) 55 | ; Entry ... 56 | ; Entry 511 57 | 58 | ; [Page Directory Table at 0x15000] 59 | ; Entry 000: 0x16000 (ES:DI + 0x7000) 60 | ; Entry ... 61 | ; Entry 511 62 | 63 | ; [Page Table 1 at 0x16000] 64 | ; Entry 000: 0x000000 65 | ; Entry 001: 0x001000 66 | ; Entry 002: 0x002000 67 | ; Entry ... 68 | ; Entry 511: 0x1FF000 69 | 70 | SwitchToLongMode: 71 | MOV EDI, 0x9000 72 | 73 | ; Zero out the 16KiB buffer. 74 | ; Since we are doing a rep stosd, count should be bytes/4. 75 | PUSH DI ; REP STOSD alters DI. 76 | MOV ECX, 0x1000 77 | XOR EAX, EAX 78 | CLD 79 | REP STOSD 80 | POP DI ; Get DI back. 81 | 82 | ; Build the Page Map Level 4 (PML4) 83 | ; es:di points to the Page Map Level 4 table. 84 | LEA EAX, [ES:DI + 0x1000] ; Put the address of the Page Directory Pointer Table in to EAX. 85 | OR EAX, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writable flag. 86 | MOV [ES:DI], EAX ; Store the value of EAX as the first PML4E. 87 | 88 | ; ================================================= 89 | ; Needed for the Higher Half Mapping of the Kernel 90 | ; ================================================= 91 | ; Add the 256th entry to the PML4... 92 | LEA EAX, [ES:DI + 0x5000] 93 | OR EAX, PAGE_PRESENT | PAGE_WRITE 94 | MOV [ES:DI + 0x800], EAX ; 256th entry * 8 bytes per entry 95 | ; END ================================================= 96 | 97 | ; Build the Page Directory Pointer Table (PDP) 98 | LEA EAX, [ES:DI + 0x2000] ; Put the address of the Page Directory in to EAX. 99 | OR EAX, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writable flag. 100 | MOV [ES:DI + 0x1000], EAX ; Store the value of EAX as the first PDPTE. 101 | 102 | ; ================================================= 103 | ; Needed for the Higher Half Mapping of the Kernel 104 | ; ================================================= 105 | ; Build the Page Directory Pointer Table (PDP) 106 | LEA EAX, [ES:DI + 0x6000] ; Put the address of the Page Directory in to EAX. 107 | OR EAX, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writable flag. 108 | MOV [ES:DI + 0x5000], EAX ; Store the value of EAX as the first PDPTE. 109 | ; END ================================================= 110 | 111 | ; Build the Page Directory (PD Entry 1 for 0 - 2 MB) 112 | LEA EAX, [ES:DI + 0x3000] ; Put the address of the Page Table in to EAX. 113 | OR EAX, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writeable flag. 114 | MOV [ES:DI + 0x2000], EAX ; Store to value of EAX as the first PDE. 115 | 116 | ; ================================================= 117 | ; Needed for the Higher Half Mapping of the Kernel 118 | ; ================================================= 119 | ; Build the Page Directory (PD Entry 1) 120 | LEA EAX, [ES:DI + 0x7000] ; Put the address of the Page Table in to EAX. 121 | OR EAX, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writeable flag. 122 | MOV [ES:DI + 0x6000], EAX ; Store to value of EAX as the first PDE. 123 | ; END ================================================= 124 | 125 | PUSH DI ; Save DI for the time being. 126 | LEA DI, [DI + 0x3000] ; Point DI to the page table. 127 | MOV EAX, PAGE_PRESENT | PAGE_WRITE ; Move the flags into EAX - and point it to 0x0000. 128 | 129 | ; Build the Page Table (PT) 130 | .LoopPageTable: 131 | MOV [ES:DI], EAX 132 | ADD EAX, 0x1000 133 | ADD DI, 8 134 | CMP EAX, 0x200000 ; If we did all 2MiB, end. 135 | JB .LoopPageTable 136 | 137 | ; ================================================= 138 | ; Needed for the Higher Half Mapping of the Kernel 139 | ; ================================================= 140 | POP DI 141 | PUSH DI 142 | 143 | LEA DI, [DI + 0x7000] ; Load the address of the 1st Page Table for the Higher Half Mapping of the Kernel 144 | MOV EAX, PAGE_PRESENT | PAGE_WRITE ; Move the flags into EAX - and point it to 0x0000. 145 | 146 | ; Build the Page Table (PT 1) 147 | .LoopPageTableHigherHalf: 148 | MOV [ES:DI], EAX 149 | ADD EAX, 0x1000 150 | ADD DI, 8 151 | CMP EAX, 0x200000 ; If we did all 2MiB, end. 152 | JB .LoopPageTableHigherHalf 153 | ; END ================================================= 154 | 155 | POP DI ; Restore DI. 156 | 157 | ; Disable IRQs 158 | MOV AL, 0xFF ; Out 0xFF to 0xA1 and 0x21 to disable all IRQs. 159 | OUT 0xA1, AL 160 | OUT 0x21, AL 161 | 162 | NOP 163 | NOP 164 | 165 | LIDT [IDT] ; Load a zero length IDT so that any NMI causes a triple fault. 166 | 167 | ; Enter long mode. 168 | MOV EAX, 10100000b ; Set the PAE and PGE bit. 169 | MOV CR4, EAX 170 | MOV EDX, EDI ; Point CR3 at the PML4. 171 | MOV CR3, EDX 172 | MOV ECX, 0xC0000080 ; Read from the EFER MSR. 173 | RDMSR 174 | 175 | OR EAX, 0x00000100 ; Set the LME bit. 176 | WRMSR 177 | 178 | MOV EBX, CR0 ; Activate long mode - 179 | OR EBX, 0x80000001 ; - by enabling paging and protection simultaneously. 180 | MOV CR0, EBX 181 | 182 | LGDT [GDT.Pointer] ; Load GDT.Pointer defined below. 183 | 184 | JMP CODE_SEG:LongMode ; Load CS with 64 bit segment and flush the instruction cache 185 | 186 | CheckCPU: 187 | ; Check whether CPUID is supported or not. 188 | PUSHFD ; Get flags in EAX register. 189 | 190 | POP EAX 191 | MOV ECX, EAX 192 | XOR EAX, 0x200000 193 | PUSH EAX 194 | POPFD 195 | 196 | PUSHFD 197 | POP EAX 198 | XOR EAX, ECX 199 | SHR EAX, 21 200 | AND EAX, 1 ; Check whether bit 21 is set or not. If EAX now contains 0, CPUID isn't supported. 201 | PUSH ECX 202 | POPFD 203 | 204 | TEST EAX, EAX 205 | JZ .NoLongMode 206 | 207 | MOV EAX, 0x80000000 208 | CPUID 209 | 210 | CMP EAX, 0x80000001 ; Check whether extended function 0x80000001 is available are not. 211 | JB .NoLongMode ; If not, long mode not supported. 212 | 213 | MOV EAX, 0x80000001 214 | CPUID 215 | TEST EDX, 1 << 29 ; Test if the LM-bit, is set or not. 216 | JZ .NoLongMode ; If not Long mode not supported. 217 | 218 | ret 219 | 220 | .NoLongMode: 221 | ; Print out a character 222 | XOR BX, BX 223 | MOV AH, 0x0E 224 | MOV AL, 'E' 225 | INT 0x10 226 | 227 | JMP $ 228 | 229 | ; Global Descriptor Table 230 | GDT: 231 | .Null: 232 | DQ 0x0000000000000000 ; Null Descriptor - should be present. 233 | 234 | .Code: 235 | DQ 0x00209A0000000000 ; 64-bit code descriptor (exec/read). 236 | DQ 0x0000920000000000 ; 64-bit data descriptor (read/write). 237 | 238 | ALIGN 4 239 | DW 0 ; Padding to make the "address of the GDT" field aligned on a 4-byte boundary 240 | 241 | .Pointer: 242 | DW $ - GDT - 1 ; 16-bit Size (Limit) of GDT. 243 | DD GDT ; 32-bit Base Address of GDT. (CPU will zero extend to 64-bit) 244 | 245 | [BITS 64] 246 | LongMode: 247 | MOV AX, DATA_SEG 248 | MOV DS, AX 249 | MOV ES, AX 250 | MOV FS, AX 251 | MOV GS, AX 252 | MOV SS, AX 253 | 254 | ; Setup the stack at the virtual address 0xFFFF800000050000 255 | ; This doesn't work on Apple Silicon with UTM... 256 | ; MOV RAX, QWORD 0xFFFF800000050000 257 | 258 | ; To be able to run KAOS on Apple Silicon with UTM, we have to set the stack 259 | ; pointer to 0x50000 instead of 0xFFFF800000050000 260 | MOV RAX, QWORD 0x50000 261 | 262 | ; The remaining part works as expected 263 | MOV RSP, RAX 264 | MOV RBP, RSP 265 | XOR RBP, RBP 266 | 267 | ; Execute the KLDR64.BIN 268 | JMP 0x3000 -------------------------------------------------------------------------------- /main64/kaosldr_16/makefile: -------------------------------------------------------------------------------- 1 | # Builds the KLDR16.BIN 2 | kldr16.bin: kaosldr_entry.asm 3 | nasm -fbin kaosldr_entry.asm -o kldr16.bin 4 | 5 | # Clean up 6 | clean: 7 | rm -f kldr16.bin -------------------------------------------------------------------------------- /main64/kaosldr_64/ata.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | #include "ata.h" 3 | 4 | // Reads a given number of disk sectors (512 bytes) from the starting LBA address into the target memory address. 5 | void ReadSectors(unsigned char *TargetAddress, unsigned int LBA, unsigned char SectorCount) 6 | { 7 | WaitForBSYFlag(); 8 | 9 | outb(0x1F2, SectorCount); 10 | outb(0x1F3, (unsigned char) LBA); 11 | outb(0x1F4, (unsigned char)(LBA >> 8)); 12 | outb(0x1F5, (unsigned char)(LBA >> 16)); 13 | outb(0x1F6, 0xE0 | ((LBA >> 24) & 0xF)); 14 | outb(0x1F7, 0x20); 15 | 16 | for (int j =0; j < SectorCount; j++) 17 | { 18 | WaitForBSYFlag(); 19 | WaitForDRQFlag(); 20 | 21 | for (int i = 0; i < 256; i++) 22 | { 23 | // Retrieve a single 16-byte value from the input port 24 | unsigned short readBuffer = inw(0x1F0); 25 | 26 | // Write the 2 retrieved 8-byte values to their target address 27 | TargetAddress[i] = readBuffer & 0xFF; 28 | TargetAddress++; 29 | TargetAddress[i] = (readBuffer >> 8) & 0xFF; 30 | } 31 | 32 | TargetAddress += 512; 33 | } 34 | } 35 | 36 | // Writes a given number of disk sectors (512 bytes) to the starting LBA address of the disk from the source memory address. 37 | void WriteSectors(unsigned int *SourceAddress, unsigned int LBA, unsigned char SectorCount) 38 | { 39 | WaitForBSYFlag(); 40 | 41 | outb(0x1F2, SectorCount); 42 | outb(0x1F3, (unsigned char) LBA); 43 | outb(0x1F4, (unsigned char)(LBA >> 8)); 44 | outb(0x1F5, (unsigned char)(LBA >> 16)); 45 | outb(0x1F6, 0xE0 | ((LBA >>24) & 0xF)); 46 | outb(0x1F7, 0x30); 47 | 48 | for (int j = 0; j < SectorCount; j++) 49 | { 50 | WaitForBSYFlag(); 51 | WaitForDRQFlag(); 52 | 53 | for (int i = 0; i < 256; i++) 54 | { 55 | outl(0x1F0, SourceAddress[i]); 56 | } 57 | } 58 | } 59 | 60 | // Waits until the BSY flag is cleared. 61 | static void WaitForBSYFlag() 62 | { 63 | while (inb(0x1F7) & STATUS_BSY); 64 | } 65 | 66 | // Waits until the DRQ flag is set. 67 | static void WaitForDRQFlag() 68 | { 69 | while (!(inb(0x1F7) & STATUS_DRQ)); 70 | } -------------------------------------------------------------------------------- /main64/kaosldr_64/ata.h: -------------------------------------------------------------------------------- 1 | #ifndef ATA_H 2 | #define ATA_H 3 | 4 | #define STATUS_BSY 0x80 5 | #define STATUS_RDY 0x40 6 | #define STATUS_DRQ 0x08 7 | #define STATUS_DF 0x20 8 | #define STATUS_ERR 0x01 9 | 10 | // Reads a given number of disk sectors (512 bytes) from the starting LBA address into the target memory address. 11 | void ReadSectors(unsigned char *TargetAddress, unsigned int LBA, unsigned char SectorCount); 12 | 13 | // Writes a given number of disk sectors (512 bytes) to the starting LBA address of the disk from the source memory address. 14 | void WriteSectors(unsigned int *SourceAddress, unsigned int LBA, unsigned char SectorCount); 15 | 16 | // Waits until the BSY flag is cleared. 17 | static void WaitForBSYFlag(); 18 | 19 | // Waits until the DRQ flag is set. 20 | static void WaitForDRQFlag(); 21 | 22 | #endif -------------------------------------------------------------------------------- /main64/kaosldr_64/fat12.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | #include "fat12.h" 3 | #include "ata.h" 4 | 5 | const int EOF = 0x0FF0; 6 | 7 | unsigned char *rootDirectoryBuffer = (unsigned char *)0x30000; 8 | unsigned char *fatBuffer = (unsigned char *)0x31C00; 9 | unsigned char *kernelBuffer = (unsigned char *)0xFFFF800000100000; 10 | 11 | // Loads the given Kernel file into memory 12 | int LoadKernelIntoMemory(char *FileName) 13 | { 14 | // Load the whole Root Directory (14 sectors) into memory 15 | ReadSectors(rootDirectoryBuffer, 19, 14); 16 | 17 | // Find the Root Directory Entry for KERNEL.BIN 18 | RootDirectoryEntry *entry = FindRootDirectoryEntry(FileName); 19 | 20 | if (entry != NULL) 21 | { 22 | // Load the whole FAT (18 sectors) into memory 23 | ReadSectors(fatBuffer, 1, 18); 24 | 25 | // Load the Kernel into memory 26 | return LoadFileIntoMemory(entry); 27 | } 28 | else 29 | { 30 | // The Kernel was not found on the disk 31 | printf("The requested Kernel file "); 32 | printf(FileName); 33 | printf(" was not found."); 34 | printf("\n"); 35 | 36 | // Halt the system 37 | while (1 == 1) {} 38 | } 39 | } 40 | 41 | // Finds a given Root Directory Entry by its Filename 42 | static RootDirectoryEntry* FindRootDirectoryEntry(char *FileName) 43 | { 44 | RootDirectoryEntry *entry = (RootDirectoryEntry *)rootDirectoryBuffer; 45 | int i; 46 | 47 | for (i = 0; i < 16; i++) 48 | { 49 | if (entry->FileName[0] != 0x00) 50 | { 51 | // Check if we got the Root Directory Entry in which we are interested in 52 | if (strcmp(entry->FileName, FileName, 11) == 0) 53 | return entry; 54 | } 55 | 56 | // Move to the next Root Directory Entry 57 | entry = entry + 1; 58 | } 59 | 60 | // The requested Root Directory Entry was not found 61 | return NULL; 62 | } 63 | 64 | // Load all Clusters for the given Root Directory Entry into memory 65 | static int LoadFileIntoMemory(RootDirectoryEntry *Entry) 66 | { 67 | int sectorCount = 0; 68 | 69 | // Read the first cluster of the file into memory 70 | ReadSectors(kernelBuffer, Entry->FirstCluster + 33 - 2, 1); 71 | sectorCount++; 72 | unsigned short nextCluster = FATRead(Entry->FirstCluster); 73 | 74 | // Read the whole file into memory until we reach the EOF mark 75 | while (nextCluster < EOF) 76 | { 77 | kernelBuffer += 512; 78 | ReadSectors(kernelBuffer, nextCluster + 33 - 2, 1); 79 | sectorCount++; 80 | 81 | // Read the next Cluster from the FAT table 82 | nextCluster = FATRead(nextCluster); 83 | } 84 | 85 | // Return the number of read sectors 86 | return sectorCount; 87 | } 88 | 89 | // Reads the next FAT Entry from the FAT Tables 90 | static unsigned short FATRead(unsigned short Cluster) 91 | { 92 | // Calculate the offset into the FAT table 93 | unsigned int fatOffset = (Cluster / 2) + Cluster; 94 | 95 | // CAUTION! 96 | // The following line generates a warning during the compilation ("incompatible-pointer-types"). 97 | // But we can't cast the right side to "(unsigned long *)", because then the loader component 98 | // will not work anymore! 99 | unsigned long *offset = fatBuffer + fatOffset; 100 | 101 | // Read the entry from the FAT 102 | unsigned short val = *offset; 103 | 104 | if (Cluster & 0x0001) 105 | { 106 | // Odd Cluster 107 | return val >> 4; // Highest 12 Bits 108 | } 109 | else 110 | { 111 | // Even Cluster 112 | return val & 0x0FFF; // Lowest 12 Bits 113 | } 114 | } -------------------------------------------------------------------------------- /main64/kaosldr_64/fat12.h: -------------------------------------------------------------------------------- 1 | #ifndef FAT12_H 2 | #define FAT12_H 3 | 4 | // Represents a Root Directory Entry 5 | struct _RootDirectoryEntry 6 | { 7 | unsigned char FileName[8]; 8 | unsigned char Extension[3]; 9 | unsigned char Attributes[1]; 10 | unsigned char Reserved[2]; 11 | unsigned char CreationTime[2]; 12 | unsigned char CreationDate[2]; 13 | unsigned char LastAccessDate[2]; 14 | unsigned char Ignore[2]; 15 | unsigned char LastWriteTime[2]; 16 | unsigned char LastWriteDate[2]; 17 | unsigned short FirstCluster; 18 | unsigned int FileSize; 19 | } __attribute__ ((packed)); 20 | typedef struct _RootDirectoryEntry RootDirectoryEntry; 21 | 22 | // Loads the given Kernel file into memory 23 | int LoadKernelIntoMemory(char *FileName); 24 | 25 | // Finds a given Root Directory Entry by its Filename 26 | static RootDirectoryEntry* FindRootDirectoryEntry(char *FileName); 27 | 28 | // Load all Clusters for the given Root Directory Entry into memory 29 | static int LoadFileIntoMemory(RootDirectoryEntry *Entry); 30 | 31 | // Reads the next FAT Entry from the FAT Tables 32 | static unsigned short FATRead(unsigned short Cluster); 33 | 34 | #endif -------------------------------------------------------------------------------- /main64/kaosldr_64/kaosldr.c: -------------------------------------------------------------------------------- 1 | #include "fat12.h" 2 | 3 | // Implemented in assembly, continues at memory location 0x100000 where the Kernel was loaded 4 | extern void ExecuteKernel(int KernelSize); 5 | 6 | // Entry point of KLDR64.BIN 7 | // The only purpose of the KLDR64.BIN file is to load the KERNEL.BIN file to the physical 8 | // memory address 0x100000 and execute it from there. 9 | // 10 | // This task must be done in KLDR64.BIN, because the CPU is now already in x64 Long Mode, 11 | // and therefore we can access higher memory addresses like 0x100000. 12 | // This would be impossible to do in KLDR16.BIN, because the CPU is at that point in time still in x16 Real Mode. 13 | void kaosldr_main() 14 | { 15 | // Load the x64 OS Kernel into memory for its execution... 16 | int kernelSize = LoadKernelIntoMemory("KERNEL BIN"); 17 | kernelSize *= 512; 18 | 19 | // Execute the Kernel. 20 | // This function call will never return... 21 | ExecuteKernel(kernelSize); 22 | 23 | // This code block will never be reached - it's just there for safety 24 | while (1 == 1) {} 25 | } -------------------------------------------------------------------------------- /main64/kaosldr_64/kernel.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | [GLOBAL ExecuteKernel] 3 | 4 | ; C Declaration: void ExecuteKernel(int KernelSize); 5 | ; Executes the loaded x64 OS Kernel 6 | ExecuteKernel: 7 | ; Make a call to the memory location where the Kernel was loaded... 8 | ; The register RDI contains the size of the loaded Kernel in bytes. 9 | ; This information will be passed as the first input parameter to the 10 | ; startup function of the KERNEL.BIN file. 11 | MOV RAX, QWORD 0xFFFF800000100000 12 | CALL RAX -------------------------------------------------------------------------------- /main64/kaosldr_64/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(kaosldr_main) 2 | 3 | SECTIONS 4 | { 5 | . = 0x3000; 6 | .text : AT(ADDR(.text)) 7 | { 8 | *(.text .text.*) 9 | . = ALIGN(4K); 10 | } 11 | 12 | .data : AT(ADDR(.data)) 13 | { 14 | *(.data .data.*) 15 | } 16 | 17 | .bss : AT(ADDR(.bss)) 18 | { 19 | *(.bss .bss.*) 20 | } 21 | } -------------------------------------------------------------------------------- /main64/kaosldr_64/makefile: -------------------------------------------------------------------------------- 1 | # Automatically generate lists of sources using wildcards. 2 | C_SOURCES = $(wildcard *.c) 3 | HEADERS = $(wildcard *.h) 4 | 5 | # Convert the *.c filenames to *.o to give a list of object files to build 6 | OBJ = ${C_SOURCES:.c=.o} 7 | 8 | # Links the KLDR64.BIN 9 | kldr64.bin: kaosldr.o kernel.o ${OBJ} 10 | x86_64-elf-ld -o $@ -Tlink.ld $^ --oformat binary -z max-page-size=0x1000 11 | 12 | # Compiles the KLDR64.BIN 13 | %.o : %.c ${HEADERS} 14 | x86_64-elf-gcc -ffreestanding -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -c $< -o $@ 15 | 16 | # Build the Kernel loader 17 | kernel.o : kernel.asm 18 | nasm kernel.asm -f elf64 -o kernel.o 19 | 20 | # Clean up 21 | clean: 22 | rm -f *.bin *.o -------------------------------------------------------------------------------- /main64/kaosldr_64/misc.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | 3 | // Define a variable for the screen location information 4 | ScreenLocation screenLocation; 5 | 6 | char tbuf[64]; 7 | char tbuf_long[64]; 8 | char bchars[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 9 | 10 | // Reads a single char (8 bytes) from the specified port. 11 | unsigned char inb(unsigned short Port) 12 | { 13 | unsigned char ret; 14 | asm volatile("inb %1, %0" : "=a" (ret) : "dN" (Port)); 15 | 16 | return ret; 17 | } 18 | 19 | // Reads a single short (16 bytes) from the specific port. 20 | unsigned short inw(unsigned short Port) 21 | { 22 | unsigned short ret; 23 | asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (Port)); 24 | 25 | return ret; 26 | } 27 | 28 | // Writes a single char (8 bytes) to the specified port. 29 | void outb(unsigned short Port, unsigned char Value) 30 | { 31 | asm volatile ("outb %1, %0" : : "dN" (Port), "a" (Value)); 32 | } 33 | 34 | // Writes a single short (16 bytes) to the specified port. 35 | void outw(unsigned short Port, unsigned short Value) 36 | { 37 | asm volatile ("outw %1, %0" : : "dN" (Port), "a" (Value)); 38 | } 39 | 40 | // Writes a single int (32 bytes) to the specified port. 41 | void outl(unsigned short Port, unsigned int Value) 42 | { 43 | asm volatile ("outl %1, %0" : : "dN" (Port), "a" (Value)); 44 | } 45 | 46 | // Initializes the screen. 47 | void InitializeScreen() 48 | { 49 | screenLocation.Row = 1; 50 | screenLocation.Col = 1; 51 | screenLocation.Attributes = COLOR_WHITE; 52 | ClearScreen(); 53 | } 54 | 55 | // Clears the screen 56 | void ClearScreen() 57 | { 58 | char *video_memory = (char *)VIDEO_MEMORY; 59 | int row, col; 60 | 61 | for (row = 0; row < ROWS; row++) 62 | { 63 | for (col = 0; col < COLS; col++) 64 | { 65 | int offset = row * COLS * 2 + col * 2; 66 | video_memory[offset] = 0x20; // Blank 67 | video_memory[offset + 1] = screenLocation.Attributes; 68 | } 69 | } 70 | 71 | // Reset the cursor to the beginning 72 | screenLocation.Row = 1; 73 | screenLocation.Col = 1; 74 | MoveCursor(); 75 | } 76 | 77 | // Returns the current cursor position 78 | void GetCursorPosition(int *Row, int *Col) 79 | { 80 | *Row = screenLocation.Row; 81 | *Col = screenLocation.Col; 82 | } 83 | 84 | // Sets the current cursor position 85 | void SetCursorPosition(int Row, int Col) 86 | { 87 | screenLocation.Row = Row; 88 | screenLocation.Col = Col; 89 | MoveCursor(); 90 | } 91 | 92 | // Moves the screen cursor to the current location on the screen. 93 | void MoveCursor() 94 | { 95 | // Calculate the linear offset of the cursor 96 | short cursorLocation = (screenLocation.Row - 1) * COLS + (screenLocation.Col - 1); 97 | 98 | // Setting the cursor's high byte 99 | outb(0x3D4, 14); 100 | outb(0x3D5, cursorLocation >> 8); 101 | 102 | // Setting the cursor's low byte 103 | outb(0x3D4, 15); 104 | outb(0x3D5, cursorLocation); 105 | } 106 | 107 | // Prints a single character on the screen. 108 | void print_char(char character) 109 | { 110 | char* video_memory = (char *)VIDEO_MEMORY; 111 | 112 | switch(character) 113 | { 114 | case '\n': 115 | { 116 | // New line 117 | screenLocation.Row++; 118 | screenLocation.Col = 1; 119 | 120 | break; 121 | } 122 | case '\t': 123 | { 124 | // Tab 125 | screenLocation.Col = (screenLocation.Col + 8) & ~ (8 - 1); 126 | break; 127 | } 128 | default: 129 | { 130 | int offset = (screenLocation.Row - 1) * COLS * 2 + (screenLocation.Col - 1) * 2; 131 | video_memory[offset] = character; 132 | video_memory[offset + 1] = screenLocation.Attributes; 133 | screenLocation.Col++; 134 | 135 | break; 136 | } 137 | } 138 | 139 | MoveCursor(); 140 | } 141 | 142 | // Prints out a null-terminated string. 143 | void printf(char *string) 144 | { 145 | while (*string != '\0') 146 | { 147 | print_char(*string); 148 | string++; 149 | } 150 | } 151 | 152 | // Prints out an integer value for a specific base (base 10 => decimal, base 16 => hex). 153 | void printf_int(int i, int base) 154 | { 155 | char str[32] = ""; 156 | itoa(i, base, str); 157 | printf(str); 158 | } 159 | 160 | // Converts an integer value to a string value for a specific base (base 10 => decimal, base 16 => hex) 161 | void itoa(int i, unsigned base, char *buf) 162 | { 163 | if (base > 16) return; 164 | 165 | if (i < 0) 166 | { 167 | *buf++ = '-'; 168 | i *= -1; 169 | } 170 | 171 | itoa_helper(i, base, buf); 172 | } 173 | 174 | // Helper function for the itoa function. 175 | // The static keyword means that this function is only available within the scope of this object file. 176 | static void itoa_helper(unsigned short i, unsigned base, char *buf) 177 | { 178 | int pos = 0; 179 | int opos = 0; 180 | int top = 0; 181 | 182 | if (i == 0 || base > 16) 183 | { 184 | buf[0] = '0'; 185 | buf[1] = '\0'; 186 | return; 187 | } 188 | 189 | while (i != 0) 190 | { 191 | tbuf[pos] = bchars[i % base]; 192 | pos++; 193 | i /= base; 194 | } 195 | 196 | top = pos--; 197 | 198 | for (opos = 0; opos < top; pos--,opos++) 199 | { 200 | buf[opos] = tbuf[pos]; 201 | } 202 | 203 | buf[opos] = 0; 204 | } 205 | 206 | // A simple strcmp implementation 207 | int strcmp(char *s1, char *s2, int len) 208 | { 209 | int i = 0; 210 | 211 | while (*s1 && (*s1 == *s2) && i < len) 212 | { 213 | s1++; 214 | s2++; 215 | i++; 216 | } 217 | 218 | return *(unsigned char *)s1 - *(unsigned char *)s2; 219 | } -------------------------------------------------------------------------------- /main64/kaosldr_64/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef MISC_H 2 | #define MISC_H 3 | 4 | // Defines the NULL pointer 5 | #define NULL ((void *) 0) 6 | 7 | // Video output memory address 8 | #define VIDEO_MEMORY 0xB8000 9 | 10 | // The number of rows of the video memory 11 | #define ROWS 25 12 | 13 | // The number of columns of the video memory 14 | #define COLS 80 15 | 16 | // The offset where the BIOS Information Block is stored 17 | #define BIB_OFFSET 0x1000 18 | 19 | // This structure stores all the information that we retrieve from the BIOS while we are in x16 Real Mode 20 | typedef struct BiosInformationBlock 21 | { 22 | int Year; 23 | short Month; 24 | short Day; 25 | short Hour; 26 | short Minute; 27 | short Second; 28 | } BiosInformationBlock; 29 | 30 | // Text mode color constants 31 | enum VGA_Color 32 | { 33 | COLOR_BLACK = 0, 34 | COLOR_BLUE = 1, 35 | COLOR_GREEN = 2, 36 | COLOR_CYAN = 3, 37 | COLOR_RED = 4, 38 | COLOR_MAGENTA = 5, 39 | COLOR_BROWN = 6, 40 | COLOR_LIGHT_GREY = 7, 41 | COLOR_DARK_GREY = 8, 42 | COLOR_LIGHT_BLUE = 9, 43 | COLOR_LIGHT_GREEN = 10, 44 | COLOR_LIGHT_CYAN = 11, 45 | COLOR_LIGHT_RED = 12, 46 | COLOR_LIGHT_MAGENTA = 13, 47 | COLOR_LIGHT_BROWN = 14, 48 | COLOR_WHITE = 15 49 | }; 50 | 51 | // This struct contains information about the screen 52 | typedef struct ScreenLocation 53 | { 54 | // The current row on the screen 55 | int Row; 56 | 57 | // The current column on the screen 58 | int Col; 59 | 60 | // The used attributes 61 | int Attributes; 62 | } ScreenLocation; 63 | 64 | // Reads a single char (8 bytes) from the specified port. 65 | unsigned char inb(unsigned short Port); 66 | 67 | // Reads a single short (16 bytes) from the specific port. 68 | unsigned short inw(unsigned short Port); 69 | 70 | // Writes a single char (8 bytes) to the specified port. 71 | void outb(unsigned short Port, unsigned char Value); 72 | 73 | // Writes a single short (16 bytes) to the specified port. 74 | void outw(unsigned short Port, unsigned short Value); 75 | 76 | // Writes a single int (32 bytes) to the specified port. 77 | void outl(unsigned short Port, unsigned int Value); 78 | 79 | // Initializes and clears the screen 80 | void InitializeScreen(); 81 | 82 | // Clears the screen 83 | void ClearScreen(); 84 | 85 | // Returns the current cursor position 86 | void GetCursorPosition(int *Row, int *Col); 87 | 88 | // Sets the current cursor position 89 | void SetCursorPosition(int Row, int Col); 90 | 91 | // Moves the screen cursor to the current location on the screen. 92 | void MoveCursor(); 93 | 94 | // Prints a single character 95 | void print_char(char character); 96 | 97 | // Prints a null-terminated string 98 | void printf(char *string); 99 | 100 | // Prints out an integer value for a specific base (base 10 => decimal, base 16 => hex). 101 | void printf_int(int i, int base); 102 | 103 | // Converts an integer value to a string value for a specific base (base 10 => decimal, base 16 => hex) 104 | void itoa(int i, unsigned base, char *buf); 105 | 106 | // Helper function for the itoa function. 107 | // The static keyword means that this function is only available within the scope of this object file. 108 | static void itoa_helper(unsigned short i, unsigned base, char *buf); 109 | 110 | // A simple strcmp implementation 111 | int strcmp(char *s1, char *s2, int len); 112 | 113 | #endif -------------------------------------------------------------------------------- /main64/kernel/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include "memory/physical-memory.h" 5 | 6 | // Defines the NULL pointer 7 | #define NULL ((void *) 0) 8 | 9 | // The physical memory offset where the BIOS Information Block is stored 10 | #define BIB_OFFSET 0x1000 11 | 12 | // The physical memory offset where the KERNEL.BIN file was loaded 13 | #define KERNEL_OFFSET 0x100000 14 | 15 | #define SERIAL_PORT_COM1 0x3F8 16 | 17 | // This structure stores all the information that we retrieve from the BIOS while we are in x16 Real Mode 18 | typedef struct BiosInformationBlock 19 | { 20 | int Year; 21 | short Month; 22 | short Day; 23 | short Hour; 24 | short Minute; 25 | short Second; 26 | 27 | // The number of Memory Map Entries that the BIOS reported 28 | short MemoryMapEntries; 29 | 30 | // The maximum physical RAM reported by the BIOS 31 | long MaxMemory; 32 | 33 | // The current available physical Page Frames (managed by the Physical Memory Manager) 34 | long AvailablePageFrames; 35 | 36 | PhysicalMemoryLayout *PhysicalMemoryLayout; 37 | } BiosInformationBlock; 38 | 39 | // Reads a single char (8 bytes) from the specified port 40 | unsigned char inb(unsigned short Port); 41 | 42 | // Reads a single short (16 bytes) from the specific port 43 | unsigned short inw(unsigned short Port); 44 | 45 | // Writes a single char (8 bytes) to the specified port 46 | void outb(unsigned short Port, unsigned char Value); 47 | 48 | // Writes a single short (16 bytes) to the specified port 49 | void outw(unsigned short Port, unsigned short Value); 50 | 51 | // Writes a single int (32 bytes) to the specified port 52 | void outl(unsigned short Port, unsigned int Value); 53 | 54 | // A simple memset implementation 55 | void *memset(void *s, int c, long n); 56 | 57 | // A simple memcpy implementation 58 | void memcpy(void *dest, void *src, int len); 59 | 60 | // Returns the length of the given string 61 | int strlen(char *string); 62 | 63 | // A simple strcpy implementation 64 | char *strcpy(char *destination, const char *source); 65 | 66 | // A simple strcmp implementation 67 | int strcmp(char *s1, char *s2); 68 | 69 | // A simple strcat implementation 70 | char *strcat(char *destination, char *source); 71 | 72 | // Returns a substring from a given string 73 | int substring(char *source, int from, int n, char *target); 74 | 75 | // Returns the position of the specific character in the given string 76 | int find(char *string, char junk); 77 | 78 | // Checks if a string starts with a given prefix 79 | int startswith(char *string, char *prefix); 80 | 81 | // Converts a string to upper case 82 | void toupper(char *s); 83 | 84 | // Converts a string to lower case 85 | void tolower(char *s); 86 | 87 | // Converts an integer value to a string value for a specific base (base 10 => decimal, base 16 => hex) 88 | void itoa(unsigned int i, unsigned base, char *buf); 89 | 90 | // Helper function for the itoa function. 91 | static void itoa_helper(unsigned int i, unsigned base, char *buf); 92 | 93 | // Converts a long value to a string value for a specific base (base 10 => decimal, base 16 => hex) 94 | void ltoa(unsigned long i, unsigned base, char *buf); 95 | 96 | // Helper function for the ltoa function. 97 | static void ltoa_helper(unsigned long i, unsigned base, char *buf); 98 | 99 | // Converts an ASCII string to its integer value 100 | int atoi(char *str); 101 | 102 | // Formats an Integer value with a leading zero. 103 | void FormatInteger(int Value, char *Buffer); 104 | 105 | // Formats a Hex string with the given number of leading zeros. 106 | void FormatHexString(char *string, int length); 107 | 108 | // Aligns the Number to the given Alignment. 109 | int AlignNumber(int Number, int Alignment); 110 | 111 | // Sets the given Bit in the provided Bitmap mask. 112 | void SetBit(unsigned long Bit, unsigned long *BitmapMask); 113 | 114 | // Clears the given Bit in the provided Bitmap mask. 115 | void ClearBit(unsigned long Bit, unsigned long *BitmapMask); 116 | 117 | // Tests if a given Bit is set in the provided Bitmap mask. 118 | int TestBit(unsigned long Bit, unsigned long *BitmapMask); 119 | 120 | // Initializes the Serial Port COM1 121 | void InitSerialPort(); 122 | 123 | // Checks if the Transmission Buffer is empty 124 | int IsTansmissionBufferEmpty(); 125 | 126 | // Writes a single character to the Serial Port 127 | void WriteCharToSerialPort(char a); 128 | 129 | // Writes a null-terminated string to the Serial Port 130 | void WriteStringToSerialPort(char *string); 131 | 132 | #endif -------------------------------------------------------------------------------- /main64/kernel/date.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "date.h" 3 | 4 | // The number of days for each month 5 | int NumberOfDaysPerMonth[12] = 6 | { 7 | 31, // January 8 | 28, // February 9 | 31, // March 10 | 30, // April 11 | 31, // Mai 12 | 30, // June 13 | 31, // July 14 | 31, // August 15 | 30, // September 16 | 31, // October 17 | 30, // November 18 | 31 // December 19 | }; 20 | 21 | // Increments the system data by 1 second. 22 | void IncrementSystemDate() 23 | { 24 | // Getting a reference to the BIOS Information Block 25 | BiosInformationBlock *bib = (BiosInformationBlock *)BIB_OFFSET; 26 | 27 | // Increment the system date by 1 second 28 | bib->Second++; 29 | 30 | // Roll over to the next minute 31 | if (bib->Second > 59) 32 | { 33 | bib->Second = 0; 34 | bib->Minute++; 35 | } 36 | 37 | // Roll over to the next hour 38 | if (bib->Minute > 59) 39 | { 40 | bib->Minute = 0; 41 | bib->Hour++; 42 | } 43 | 44 | // Roll over to the next day 45 | if (bib->Hour > 23) 46 | { 47 | bib->Hour = 0; 48 | bib->Day++; 49 | } 50 | 51 | // Roll over to the next month 52 | // We don't check here for the leap year!!! 53 | if (bib->Day > NumberOfDaysPerMonth[bib->Month - 1]) 54 | { 55 | bib->Day = 1; 56 | bib->Month++; 57 | } 58 | } 59 | 60 | // Sets the system date. 61 | void SetDate(int Year, int Month, int Day) 62 | { 63 | // Getting a reference to the BIOS Information Block 64 | BiosInformationBlock *bib = (BiosInformationBlock *)BIB_OFFSET; 65 | 66 | // Set the date 67 | bib->Year = Year; 68 | bib->Month = Month; 69 | bib->Day = Day; 70 | } 71 | 72 | // Sets the system time. 73 | void SetTime(int Hour, int Minute, int Second) 74 | { 75 | // Getting a reference to the BIOS Information Block 76 | BiosInformationBlock *bib = (BiosInformationBlock *)BIB_OFFSET; 77 | 78 | // Set the time 79 | bib->Hour = Hour; 80 | bib->Minute = Minute; 81 | bib->Second = Second; 82 | } -------------------------------------------------------------------------------- /main64/kernel/date.h: -------------------------------------------------------------------------------- 1 | #ifndef DATE_H 2 | #define DATE_H 3 | 4 | // Increments the system data by 1 second. 5 | void IncrementSystemDate(); 6 | 7 | // Sets the system date. 8 | void SetDate(int Year, int Month, int Day); 9 | 10 | // Sets the system time. 11 | void SetTime(int Hour, int Minute, int Second); 12 | 13 | #endif -------------------------------------------------------------------------------- /main64/kernel/drivers/keyboard.c: -------------------------------------------------------------------------------- 1 | #include "../common.h" 2 | #include "../isr/irq.h" 3 | #include "screen.h" 4 | #include "keyboard.h" 5 | 6 | // Stores the last received Scan Code from the keyboard. 7 | // The value "0" means, we have entered a non-printable character (like "shift") 8 | static char lastReceivedScanCode; 9 | 10 | // Stores if the shift key is pressed, or not 11 | int shiftKey; 12 | 13 | // Stores if the caps lock key is pressed, or not 14 | int capsLock; 15 | 16 | int leftCtrl; 17 | 18 | // Used to indicate the last scan code is not to be reused 19 | const char INVALID_SCANCODE = (char)0; 20 | 21 | // Initializes the keyboard 22 | void InitKeyboard() 23 | { 24 | // Registers the IRQ callback function for the hardware timer 25 | RegisterIrqHandler(33, &KeyboardCallback); 26 | 27 | // Set the internal key buffer to KEY_UNKNOWN 28 | DiscardLastKey(); 29 | 30 | capsLock = 0; 31 | } 32 | 33 | // This function runs continuosly in the Kernel, processes a key press, 34 | // and stores the entered character in the memory 35 | void KeyboardHandlerTask() 36 | { 37 | while (1 == 1) 38 | { 39 | // Wait for the next keystroke 40 | char originalInput = getchar(); 41 | 42 | // Get a pointer to the keyboard buffer 43 | char *keyboardBuffer = (char *)KEYBOARD_BUFFER; 44 | 45 | // Store the processed key in to keyboard buffer 46 | keyboardBuffer[0] = originalInput; 47 | } 48 | } 49 | 50 | // Reads data from the keyboard 51 | void scanf(char *buffer, int buffer_size) 52 | { 53 | int processKey = 1; 54 | int i = 0; 55 | 56 | while (i < buffer_size) 57 | { 58 | char key = getchar(); 59 | processKey = 1; 60 | 61 | // When we have hit the ENTER key, we have finished entering our input data 62 | if (key == KEY_RETURN) 63 | { 64 | print_char('\n'); 65 | break; 66 | } 67 | 68 | if (key == KEY_BACKSPACE) 69 | { 70 | processKey = 0; 71 | 72 | // We only process the backspace key, if we have data already in the input buffer 73 | if (i > 0) 74 | { 75 | int col; 76 | int row; 77 | 78 | // Move the cursor position one character back 79 | GetCursorPosition(&row, &col); 80 | col -= 1; 81 | SetCursorPosition(row, col); 82 | 83 | // Clear out the last printed key 84 | // This also moves the cursor one character forward, so we have to go back 85 | // again with the cursor in the next step 86 | print_char(' '); 87 | 88 | // Move the cursor position one character back again 89 | GetCursorPosition(&row, &col); 90 | col -= 1; 91 | SetCursorPosition(row, col); 92 | 93 | // Delete the last entered character from the input buffer 94 | i--; 95 | } 96 | } 97 | 98 | if (processKey == 1) 99 | { 100 | // Print out the current entered key stroke 101 | // If we have pressed a non-printable key, the character is not printed out 102 | if (key != 0) 103 | { 104 | print_char(key); 105 | } 106 | 107 | // Write the entered character into the provided buffer 108 | buffer[i] = key; 109 | i++; 110 | } 111 | } 112 | 113 | // Null-terminate the input string 114 | buffer[i] = '\0'; 115 | } 116 | 117 | // Waits for a key press, and returns it 118 | char getchar() 119 | { 120 | char key = INVALID_SCANCODE; 121 | 122 | // Wait until we get a key stroke 123 | while (key == INVALID_SCANCODE) 124 | { 125 | if (lastReceivedScanCode > INVALID_SCANCODE) 126 | { 127 | if (shiftKey || capsLock) 128 | key = ScanCodes_UpperCase_QWERTZ[lastReceivedScanCode]; 129 | else 130 | key = ScanCodes_LowerCase_QWERTZ[lastReceivedScanCode]; 131 | } 132 | else 133 | { 134 | key = INVALID_SCANCODE; 135 | } 136 | } 137 | 138 | DiscardLastKey(); 139 | 140 | // Return the received character from the keyboard 141 | return key; 142 | } 143 | 144 | // Discards the last key press 145 | static void DiscardLastKey() 146 | { 147 | lastReceivedScanCode = INVALID_SCANCODE; 148 | } 149 | 150 | // Keyboard callback function 151 | static void KeyboardCallback(int Number) 152 | { 153 | // Check if the keyboard controller output buffer is full 154 | if (ReadStatus() & KYBRD_CTRL_STATS_MASK_OUT_BUF) 155 | { 156 | // Read the scan code 157 | int code = ReadBuffer(); 158 | 159 | // Check if the current scan code is a break code 160 | if (code & 0x80) 161 | { 162 | // A break code is received from the keyboard when the key is released. 163 | // In a break code the 8th bit is set, therefore we test above against 0x80 (10000000b) 164 | 165 | // Convert the break code into the make code by clearing the 8th bit 166 | code -= 0x80; 167 | 168 | // Get the key from the scan code table 169 | int key = ScanCodes_LowerCase_QWERTZ[code]; 170 | 171 | switch (key) 172 | { 173 | case KEY_LCTRL: 174 | { 175 | leftCtrl = 0; 176 | lastReceivedScanCode = 0; 177 | break; 178 | } 179 | case KEY_LSHIFT: 180 | { 181 | // The left shift key is released 182 | shiftKey = 0; 183 | lastReceivedScanCode = 0; 184 | break; 185 | } 186 | case KEY_RSHIFT: 187 | { 188 | // The right shift key is released 189 | lastReceivedScanCode = 0; 190 | shiftKey = 0; 191 | break; 192 | } 193 | } 194 | } 195 | else 196 | { 197 | // Get the key from the scan code table 198 | int key = ScanCodes_LowerCase_QWERTZ[code]; 199 | 200 | switch (key) 201 | { 202 | case KEY_LCTRL: 203 | { 204 | leftCtrl = 1; 205 | lastReceivedScanCode = 0; 206 | break; 207 | } 208 | case KEY_CAPSLOCK: 209 | { 210 | // The caps lock key is pressed 211 | // We just toggle the flag 212 | if (capsLock == 1) 213 | capsLock = 0; 214 | else 215 | capsLock = 1; 216 | 217 | break; 218 | } 219 | case KEY_LSHIFT: 220 | { 221 | // The left shift key is pressed 222 | shiftKey = 1; 223 | lastReceivedScanCode = 0; 224 | break; 225 | } 226 | case KEY_RSHIFT: 227 | { 228 | // The right shift key is pressed 229 | lastReceivedScanCode = 0; 230 | shiftKey = 1; 231 | break; 232 | } 233 | default: 234 | { 235 | // We only buffer the Scan Code from the keyboard, if it is a printable character 236 | lastReceivedScanCode = code; 237 | break; 238 | } 239 | } 240 | } 241 | } 242 | } 243 | 244 | // Reads the keyboard status 245 | static unsigned char ReadStatus() 246 | { 247 | return inb(KYBRD_CTRL_STATS_REG); 248 | } 249 | 250 | // Reads the keyboard encoder buffer 251 | static unsigned char ReadBuffer() 252 | { 253 | return inb(KYBRD_ENC_INPUT_BUF); 254 | } -------------------------------------------------------------------------------- /main64/kernel/drivers/screen.c: -------------------------------------------------------------------------------- 1 | #include "screen.h" 2 | #include "../common.h" 3 | 4 | // Define a variable for the screen location information 5 | ScreenLocation screenLocation; 6 | 7 | // The number of rows of the video memory 8 | int NumberOfRows; 9 | 10 | // The number of columns of the video memory 11 | int NumberOfColumns; 12 | 13 | // The blank character 14 | unsigned char BLANK = 0x20; 15 | 16 | // Initializes the screen 17 | void InitializeScreen(int Cols, int Rows) 18 | { 19 | NumberOfColumns = Cols; 20 | NumberOfRows = Rows; 21 | 22 | screenLocation.Row = 1; 23 | screenLocation.Col = 1; 24 | screenLocation.Attributes = COLOR_WHITE; 25 | ClearScreen(); 26 | } 27 | 28 | // Sets the specific color 29 | int SetColor(int Color) 30 | { 31 | int currentColor = screenLocation.Attributes; 32 | screenLocation.Attributes = Color; 33 | 34 | return currentColor; 35 | } 36 | 37 | // Returns the current cursor position 38 | void GetCursorPosition(int *Row, int *Col) 39 | { 40 | *Row = screenLocation.Row; 41 | *Col = screenLocation.Col; 42 | } 43 | 44 | // Sets the current cursor position 45 | void SetCursorPosition(int Row, int Col) 46 | { 47 | screenLocation.Row = Row; 48 | screenLocation.Col = Col; 49 | MoveCursor(); 50 | } 51 | 52 | // Moves the screen cursor to the current location on the screen 53 | void MoveCursor() 54 | { 55 | // Calculate the linear offset of the cursor 56 | short cursorLocation = (screenLocation.Row - 1) * NumberOfColumns + (screenLocation.Col - 1); 57 | 58 | // Setting the cursor's high byte 59 | outb(0x3D4, 14); 60 | outb(0x3D5, cursorLocation >> 8); 61 | 62 | // Setting the cursor's low byte 63 | outb(0x3D4, 15); 64 | outb(0x3D5, cursorLocation); 65 | } 66 | 67 | // Clears the screen 68 | void ClearScreen() 69 | { 70 | char *video_memory = (char *)VIDEO_MEMORY; 71 | int row, col; 72 | 73 | for (row = 0; row < NumberOfRows; row++) 74 | { 75 | for (col = 0; col < NumberOfColumns; col++) 76 | { 77 | int offset = row * NumberOfColumns * 2 + col * 2; 78 | video_memory[offset] = BLANK; 79 | video_memory[offset + 1] = screenLocation.Attributes; 80 | } 81 | } 82 | 83 | // Reset the cursor to the beginning 84 | screenLocation.Row = 1; 85 | screenLocation.Col = 1; 86 | MoveCursor(); 87 | } 88 | 89 | // Scrolls the screen, when we have used more than 25 rows 90 | void Scroll() 91 | { 92 | unsigned char attributeByte = (COLOR_BLACK << 4) | (COLOR_WHITE & 0x0F); 93 | char *video_memory = (char *)VIDEO_MEMORY; 94 | int i; 95 | 96 | // Check if we have reached the last row of the screen. 97 | // This means we need to scroll up 98 | if (screenLocation.Row > NumberOfRows) 99 | { 100 | for (i = 0; i < NumberOfColumns * 2 * (NumberOfRows - 1); i++) 101 | { 102 | video_memory[i] = video_memory[i + (NumberOfColumns * 2)]; 103 | } 104 | 105 | // Blank the last line 106 | for (i = (NumberOfRows - 1) * NumberOfColumns * 2; i < NumberOfRows * NumberOfColumns * 2; i += 2) 107 | { 108 | video_memory[i] = BLANK; 109 | video_memory[i + 1] = attributeByte; 110 | } 111 | 112 | screenLocation.Row = NumberOfRows; 113 | } 114 | } 115 | 116 | // Prints out a null-terminated string 117 | void printf(char *string) 118 | { 119 | while (*string != '\0') 120 | { 121 | print_char(*string); 122 | string++; 123 | } 124 | } 125 | 126 | // Prints out the status line string 127 | void PrintStatusLine(char *string) 128 | { 129 | unsigned char color = (COLOR_GREEN << 4) | (COLOR_BLACK & 0x0F); 130 | char *video_memory = (char *)VIDEO_MEMORY; 131 | int colStatusLine = 1; 132 | 133 | while (*string != '\0') 134 | { 135 | int offset = (25 - 1) * NumberOfColumns * 2 + (colStatusLine - 1) * 2; 136 | video_memory[offset] = *string; 137 | video_memory[offset + 1] = color; 138 | colStatusLine++; 139 | 140 | string++; 141 | } 142 | } 143 | 144 | // Prints a single character on the screen 145 | void print_char(char character) 146 | { 147 | char *video_memory = (char *)VIDEO_MEMORY; 148 | 149 | switch(character) 150 | { 151 | case CRLF: 152 | { 153 | // New line 154 | screenLocation.Row++; 155 | screenLocation.Col = 1; 156 | 157 | break; 158 | } 159 | case TAB: 160 | { 161 | // Tab 162 | screenLocation.Col = (screenLocation.Col + 8) & ~ (8 - 1); 163 | break; 164 | } 165 | default: 166 | { 167 | int offset = (screenLocation.Row - 1) * NumberOfColumns * 2 + (screenLocation.Col - 1) * 2; 168 | video_memory[offset] = character; 169 | video_memory[offset + 1] = screenLocation.Attributes; 170 | screenLocation.Col++; 171 | 172 | break; 173 | } 174 | } 175 | 176 | Scroll(); 177 | MoveCursor(); 178 | } 179 | 180 | // Prints out an integer value 181 | void printf_int(int i, int base) 182 | { 183 | char str[32] = ""; 184 | itoa(i, base, str); 185 | printf(str); 186 | } 187 | 188 | // Prints out a long value 189 | void printf_long(unsigned long i, int base) 190 | { 191 | char str[32] = ""; 192 | ltoa(i, base, str); 193 | printf(str); 194 | } -------------------------------------------------------------------------------- /main64/kernel/drivers/screen.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREEN_H 2 | #define SCREEN_H 3 | 4 | // Video output memory address 5 | #define VIDEO_MEMORY 0xB8000 6 | 7 | #define CRLF '\n' 8 | #define TAB '\t' 9 | 10 | // Text mode color constants 11 | enum VGA_Color 12 | { 13 | COLOR_BLACK = 0, 14 | COLOR_BLUE = 1, 15 | COLOR_GREEN = 2, 16 | COLOR_CYAN = 3, 17 | COLOR_RED = 4, 18 | COLOR_MAGENTA = 5, 19 | COLOR_BROWN = 6, 20 | COLOR_LIGHT_GREY = 7, 21 | COLOR_DARK_GREY = 8, 22 | COLOR_LIGHT_BLUE = 9, 23 | COLOR_LIGHT_GREEN = 10, 24 | COLOR_LIGHT_CYAN = 11, 25 | COLOR_LIGHT_RED = 12, 26 | COLOR_LIGHT_MAGENTA = 13, 27 | COLOR_LIGHT_BROWN = 14, 28 | COLOR_WHITE = 15 29 | }; 30 | 31 | // This struct contains information about the screen 32 | typedef struct ScreenLocation 33 | { 34 | // The current row on the screen 35 | int Row; 36 | 37 | // The current column on the screen 38 | int Col; 39 | 40 | // The used attributes 41 | int Attributes; 42 | } ScreenLocation; 43 | 44 | // Initializes the screen 45 | void InitializeScreen(int Cols, int Rows); 46 | 47 | // Sets the specific color 48 | int SetColor(int Color); 49 | 50 | // Returns the current cursor position 51 | void GetCursorPosition(int *Row, int *Col); 52 | 53 | // Sets the current cursor position 54 | void SetCursorPosition(int Row, int Col); 55 | 56 | // Moves the screen cursor to the current location on the screen 57 | void MoveCursor(); 58 | 59 | // Clears the screen 60 | void ClearScreen(); 61 | 62 | // Scrolls the screen, when we have used more than 25 rows 63 | void Scroll(); 64 | 65 | // Prints out a status line string 66 | void PrintStatusLine(char *string); 67 | 68 | // Prints a null-terminated string 69 | void printf(char *string); 70 | 71 | // Prints a single character 72 | void print_char(char character); 73 | 74 | // Prints out an integer value 75 | void printf_int(int i, int base); 76 | 77 | // Prints out a long value 78 | void printf_long(unsigned long i, int base); 79 | 80 | #endif -------------------------------------------------------------------------------- /main64/kernel/drivers/timer.c: -------------------------------------------------------------------------------- 1 | #include "../common.h" 2 | #include "../isr/irq.h" 3 | #include "../date.h" 4 | #include "../kernel.h" 5 | #include "timer.h" 6 | #include "screen.h" 7 | 8 | // Initializes the hardware timer 9 | void InitTimer(int Hertz) 10 | { 11 | int divisor = 1193180 / Hertz; 12 | 13 | // Send the command byte 14 | outb(0x43, 0x36); 15 | 16 | // Divisor has to be sent byte-wise, so split here into upper/lower bytes 17 | unsigned char l = (unsigned char)(divisor & 0xFF); 18 | unsigned char h = (unsigned char)((divisor >> 8)); 19 | 20 | // Send the frequency divisor 21 | outb(0x40, l); 22 | outb(0x40, h); 23 | } -------------------------------------------------------------------------------- /main64/kernel/drivers/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_H 2 | #define TIMER_H 3 | 4 | // Initializes the hardware timer 5 | void InitTimer(int Hertz); 6 | 7 | #endif -------------------------------------------------------------------------------- /main64/kernel/io/ata.c: -------------------------------------------------------------------------------- 1 | #include "ata.h" 2 | #include "../common.h" 3 | 4 | // Reads a given number of disk sectors (512 bytes) from the starting LBA address into the target memory address. 5 | void ReadSectors(unsigned char *TargetAddress, unsigned int LBA, unsigned char SectorCount) 6 | { 7 | WaitForBSYFlag(); 8 | 9 | outb(0x1F2, SectorCount); 10 | outb(0x1F3, (unsigned char) LBA); 11 | outb(0x1F4, (unsigned char)(LBA >> 8)); 12 | outb(0x1F5, (unsigned char)(LBA >> 16)); 13 | outb(0x1F6, 0xE0 | ((LBA >> 24) & 0xF)); 14 | outb(0x1F7, 0x20); 15 | 16 | for (int j =0; j < SectorCount; j++) 17 | { 18 | WaitForBSYFlag(); 19 | WaitForDRQFlag(); 20 | 21 | for (int i = 0; i < 256; i++) 22 | { 23 | // Retrieve a single 16-byte value from the input port 24 | unsigned short readBuffer = inw(0x1F0); 25 | 26 | // Write the 2 retrieved 8-byte values to their target address 27 | TargetAddress[i] = readBuffer & 0xFF; 28 | TargetAddress++; 29 | TargetAddress[i] = (readBuffer >> 8) & 0xFF; 30 | } 31 | 32 | TargetAddress += 512; 33 | } 34 | } 35 | 36 | // Writes a given number of disk sectors (512 bytes) to the starting LBA address of the disk from the source memory address. 37 | void WriteSectors(unsigned int *SourceAddress, unsigned int LBA, unsigned char SectorCount) 38 | { 39 | WaitForBSYFlag(); 40 | 41 | outb(0x1F2, SectorCount); 42 | outb(0x1F3, (unsigned char) LBA); 43 | outb(0x1F4, (unsigned char)(LBA >> 8)); 44 | outb(0x1F5, (unsigned char)(LBA >> 16)); 45 | outb(0x1F6, 0xE0 | ((LBA >>24) & 0xF)); 46 | outb(0x1F7, 0x30); 47 | 48 | for (int j = 0; j < SectorCount; j++) 49 | { 50 | WaitForBSYFlag(); 51 | WaitForDRQFlag(); 52 | 53 | for (int i = 0; i < 256; i++) 54 | { 55 | outl(0x1F0, SourceAddress[i]); 56 | } 57 | 58 | SourceAddress += 256; 59 | } 60 | } 61 | 62 | // Waits until the BSY flag is cleared. 63 | static void WaitForBSYFlag() 64 | { 65 | while (inb(0x1F7) & STATUS_BSY); 66 | } 67 | 68 | // Waits until the DRQ flag is set. 69 | static void WaitForDRQFlag() 70 | { 71 | // while (!(inb(0x1F7) & STATUS_DRQ)); 72 | while (!(inb(0x1F7) & STATUS_RDY)); 73 | } -------------------------------------------------------------------------------- /main64/kernel/io/ata.h: -------------------------------------------------------------------------------- 1 | #ifndef ATA_H 2 | #define ATA_H 3 | 4 | #define STATUS_BSY 0x80 5 | #define STATUS_RDY 0x40 6 | #define STATUS_DRQ 0x08 7 | #define STATUS_DF 0x20 8 | #define STATUS_ERR 0x01 9 | 10 | // Reads a given number of disk sectors (512 bytes) from the starting LBA address into the target memory address. 11 | void ReadSectors(unsigned char *TargetAddress, unsigned int LBA, unsigned char SectorCount); 12 | 13 | // Writes a given number of disk sectors (512 bytes) to the starting LBA address of the disk from the source memory address. 14 | void WriteSectors(unsigned int *SourceAddress, unsigned int LBA, unsigned char SectorCount); 15 | 16 | // Waits until the BSY flag is cleared. 17 | static void WaitForBSYFlag(); 18 | 19 | // Waits until the DRQ flag is set. 20 | static void WaitForDRQFlag(); 21 | 22 | #endif -------------------------------------------------------------------------------- /main64/kernel/io/fat12.h: -------------------------------------------------------------------------------- 1 | #ifndef FAT12_H 2 | #define FAT12_H 3 | 4 | #define EOF 0x0FF0 5 | #define BYTES_PER_SECTOR 512 6 | #define FAT_COUNT 2 7 | #define SECTORS_PER_FAT 9 8 | #define RESERVED_SECTORS 1 9 | #define ROOT_DIRECTORY_ENTRIES 224 10 | #define DATA_AREA_BEGINNING 31 11 | #define FAT1_CLUSTER 1 12 | #define FAT2_CLUSTER 10 13 | #define FAT12_YEAROFFSET 1980 14 | 15 | // Represents a Root Directory Entry - 32 bytes long 16 | struct RootDirectoryEntry 17 | { 18 | unsigned char FileName[8]; 19 | unsigned char Extension[3]; 20 | unsigned char Attributes[1]; 21 | unsigned char Reserved[2]; 22 | unsigned CreationSecond: 5; 23 | unsigned CreationMinute: 6; 24 | unsigned CreationHour: 5; 25 | unsigned CreationDay: 5; 26 | unsigned CreationMonth: 4; 27 | unsigned CreationYear: 7; 28 | unsigned LastAccessDay: 5; 29 | unsigned LastAccessMonth: 4; 30 | unsigned LastAccessYear: 7; 31 | unsigned char Ignore[2]; 32 | unsigned LastWriteSecond: 5; 33 | unsigned LastWriteMinute: 6; 34 | unsigned LastWriteHour: 5; 35 | unsigned LastWriteDay: 5; 36 | unsigned LastWriteMonth: 4; 37 | unsigned LastWriteYear: 7; 38 | unsigned short FirstCluster; 39 | unsigned int FileSize; 40 | } __attribute__ ((packed)); 41 | typedef struct RootDirectoryEntry RootDirectoryEntry; 42 | 43 | // Represents a File Descriptor 44 | struct FileDescriptor 45 | { 46 | unsigned char FileName[11]; 47 | unsigned char Extension[3]; 48 | unsigned long FileSize; 49 | unsigned long CurrentFileOffset; 50 | char FileMode[2]; 51 | }; 52 | typedef struct FileDescriptor FileDescriptor; 53 | 54 | // Initializes the FAT12 system 55 | void InitFAT12(); 56 | 57 | // Opens an existing file in the FAT12 file system 58 | unsigned long OpenFile(unsigned char *FileName, unsigned char *Extension, char *FileMode); 59 | 60 | // Reads the requested data from a file into the provided buffer 61 | unsigned long ReadFile(unsigned long FileHandle, unsigned char *Buffer, unsigned long Length); 62 | 63 | // Writes the requested data from the provided buffer into a file 64 | unsigned long WriteFile(unsigned long FileHandle, unsigned char *Buffer, unsigned long Length); 65 | 66 | // Seeks to the specific position in the file 67 | int SeekFile(unsigned long FileHandle, unsigned long NewFileOffset); 68 | 69 | // Returns a flag if the file offset within the FileDescriptor has reached the end of file 70 | int EndOfFile(unsigned long FileHandle); 71 | 72 | // Closes a file in the FAT12 file system 73 | int CloseFile(unsigned long FileHandle); 74 | 75 | // Deletes an existing file in the FAT12 file system 76 | int DeleteFile(unsigned char *FileName, unsigned char *Extension); 77 | 78 | // Load the given program into memory 79 | int LoadProgram(unsigned char *Filename); 80 | 81 | // Prints the Root Directory 82 | void PrintRootDirectory(); 83 | 84 | // Finds a given Root Directory Entry by its Filename 85 | RootDirectoryEntry* FindRootDirectoryEntry(unsigned char *Filename); 86 | 87 | // Prints out the FileDescriptorList entries 88 | void PrintFileDescriptorList(); 89 | 90 | // Prints out the FAT12 chain 91 | void PrintFATChain(); 92 | 93 | // Tests some functionality of the FAT12 file system 94 | void FAT12Test(); 95 | 96 | // Creates a new file in the FAT12 file system 97 | static void CreateFile(unsigned char *FileName, unsigned char *Extension); 98 | 99 | // Allocates a new cluster to the given FAT sector 100 | static unsigned short AllocateNewClusterToFile(unsigned short CurrentFATSect); 101 | 102 | // Deallocates the FAT clusters for a file - beginning with the given first cluster 103 | static void DeallocateFATClusters(unsigned short FirstCluster); 104 | 105 | // Loads the Root Directory into memory 106 | static void LoadRootDirectory(); 107 | 108 | // Finds the next free Root Directory Entry 109 | static RootDirectoryEntry *FindNextFreeRootDirectoryEntry(); 110 | 111 | // Writes the Root Directory and the FAT12 tables from the memory back to the disk 112 | static void WriteRootDirectoryAndFAT(); 113 | 114 | // Reads the next FAT Entry from the FAT Tables 115 | static unsigned short FATRead(unsigned short Cluster); 116 | 117 | // Writes the provided value to the specific FAT12 cluster 118 | static void FATWrite(unsigned short Cluster, unsigned short Value); 119 | 120 | // Finds the next free FAT12 cluster entry 121 | static unsigned short FindNextFreeFATEntry(); 122 | 123 | // Sets the last Access Date and the last Write Date for the RootDirectoryEntry 124 | static void SetLastAccessDate(RootDirectoryEntry *Entry); 125 | 126 | // Load all Clusters for the given Root Directory Entry into memory 127 | static void LoadProgramIntoMemory(RootDirectoryEntry *Entry); 128 | 129 | // Calculates a Hash Value for the given file name 130 | static unsigned long HashFileName(unsigned char *FileName); 131 | 132 | #endif -------------------------------------------------------------------------------- /main64/kernel/isr/idt.c: -------------------------------------------------------------------------------- 1 | #include "idt.h" 2 | #include "irq.h" 3 | #include "../common.h" 4 | #include "../multitasking/multitasking.h" 5 | #include "../syscalls/syscall.h" 6 | #include "../drivers/screen.h" 7 | #include "../memory/virtual-memory.h" 8 | 9 | // The 256 possible Interrupt Gates are stored from 0xFFFF800000060000 to 0xFFFF800000060FFF (4096 Bytes long - each Entry is 16 Bytes) 10 | IdtEntry *idtEntries = (IdtEntry *)IDT_START_OFFSET; 11 | 12 | // The pointer that points to the Interrupt Gates 13 | IdtPointer idtPointer; 14 | 15 | // Initializes the IDT table 16 | void InitIdt() 17 | { 18 | idtPointer.Limit = sizeof(IdtEntry) * IDT_ENTRIES - 1; 19 | idtPointer.Base = (unsigned long)idtEntries; 20 | memset(idtEntries, 0, sizeof(IdtEntry) * IDT_ENTRIES); 21 | 22 | // Setup the 32 Exception handlers - as described in Volume 3A: 6.15 23 | IdtSetGate(EXCEPTION_DIVIDE, (unsigned long)Isr0, IDT_TRAP_GATE); // Divide Error Exception 24 | IdtSetGate(EXCEPTION_DEBUG, (unsigned long)Isr1, IDT_TRAP_GATE); // Debug Exception 25 | IdtSetGate(EXCEPTION_NON_MASKABLE_INTERRUPT, (unsigned long)Isr2, IDT_TRAP_GATE); // Non-Maskable Interrupt 26 | IdtSetGate(EXCEPTION_BREAKPOINT, (unsigned long)Isr3, IDT_TRAP_GATE); // Breakpoint Exception 27 | IdtSetGate(EXCEPTION_OVERFLOW, (unsigned long)Isr4, IDT_TRAP_GATE); // Overflow Exception 28 | IdtSetGate(EXCEPTION_BOUND_RANGE, (unsigned long)Isr5, IDT_TRAP_GATE); // Bound Range Exceeded Exception 29 | IdtSetGate(EXCEPTION_INVALID_OPCODE, (unsigned long)Isr6, IDT_TRAP_GATE); // Invalid Opcode Exception 30 | IdtSetGate(EXCEPTION_DEVICE_NOT_AVAILABLE, (unsigned long)Isr7, IDT_TRAP_GATE); // Device Not Available Exception 31 | IdtSetGate(EXCEPTION_DOUBLE_FAULT, (unsigned long)Isr8, IDT_INTERRUPT_GATE); // Double Fault Exception 32 | IdtSetGate(EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN, (unsigned long)Isr9, IDT_TRAP_GATE); // Coprocessor Segment Overrun 33 | IdtSetGate(EXCEPTION_INVALID_TSS, (unsigned long)Isr10, IDT_INTERRUPT_GATE); // Invalid TSS Exception 34 | IdtSetGate(EXCEPTION_SEGMENT_NOT_PRESENT, (unsigned long)Isr11, IDT_INTERRUPT_GATE); // Segment Not Present 35 | IdtSetGate(EXCEPTION_STACK_FAULT, (unsigned long)Isr12, IDT_INTERRUPT_GATE); // Stack Fault Exception 36 | IdtSetGate(EXCEPTION_GENERAL_PROTECTION, (unsigned long)Isr13, IDT_INTERRUPT_GATE); // General Protection Exception 37 | IdtSetGate(EXCEPTION_PAGE_FAULT, (unsigned long)Isr14, IDT_INTERRUPT_GATE); // Page Fault Exception 38 | IdtSetGate(EXCEPTION_UNASSGIGNED, (unsigned long)Isr15, IDT_TRAP_GATE); // Unassigned 39 | IdtSetGate(EXCEPTION_X87_FPU, (unsigned long)Isr16, IDT_TRAP_GATE); // x87 FPU Floating Point Error 40 | IdtSetGate(EXCEPTION_ALIGNMENT_CHECK, (unsigned long)Isr17, IDT_TRAP_GATE); // Alignment Check Exception 41 | IdtSetGate(EXCEPTION_MACHINE_CHECK, (unsigned long)Isr18, IDT_TRAP_GATE); // Machine Check Exception 42 | IdtSetGate(EXCEPTION_SIMD_FLOATING_POINT, (unsigned long)Isr19, IDT_TRAP_GATE); // SIMD Floating Point Exception 43 | IdtSetGate(EXCEPTION_VIRTUALIZATION, (unsigned long)Isr20, IDT_TRAP_GATE); // Virtualization Exception 44 | IdtSetGate(EXCEPTION_CONTROL_PROTECTION, (unsigned long)Isr21, IDT_TRAP_GATE); // Control Protection Exception 45 | IdtSetGate(EXCEPTION_RESERVED_22, (unsigned long)Isr22, IDT_TRAP_GATE); // Reserved 46 | IdtSetGate(EXCEPTION_RESERVED_23, (unsigned long)Isr23, IDT_TRAP_GATE); // Reserved 47 | IdtSetGate(EXCEPTION_RESERVED_24, (unsigned long)Isr24, IDT_TRAP_GATE); // Reserved 48 | IdtSetGate(EXCEPTION_RESERVED_25, (unsigned long)Isr25, IDT_TRAP_GATE); // Reserved 49 | IdtSetGate(EXCEPTION_RESERVED_26, (unsigned long)Isr26, IDT_TRAP_GATE); // Reserved 50 | IdtSetGate(EXCEPTION_RESERVED_27, (unsigned long)Isr27, IDT_TRAP_GATE); // Reserved 51 | IdtSetGate(EXCEPTION_RESERVED_28, (unsigned long)Isr28, IDT_TRAP_GATE); // Reserved 52 | IdtSetGate(EXCEPTION_RESERVED_29, (unsigned long)Isr29, IDT_TRAP_GATE); // Reserved 53 | IdtSetGate(EXCEPTION_RESERVED_30, (unsigned long)Isr30, IDT_TRAP_GATE); // Reserved 54 | IdtSetGate(EXCEPTION_RESERVED_31, (unsigned long)Isr31, IDT_TRAP_GATE); // Reserved 55 | 56 | // Setup the 16 IRQ handlers 57 | IdtSetGate(32, (unsigned long)Irq0, IDT_INTERRUPT_GATE); // Timer 58 | IdtSetGate(33, (unsigned long)Irq1, IDT_INTERRUPT_GATE); // Keyboard 59 | IdtSetGate(34, (unsigned long)Irq2, IDT_INTERRUPT_GATE); // Cascade for 8259A Slave Controller 60 | IdtSetGate(35, (unsigned long)Irq3, IDT_INTERRUPT_GATE); // Serial Port 2 61 | IdtSetGate(36, (unsigned long)Irq4, IDT_INTERRUPT_GATE); // Serial Port 1 62 | IdtSetGate(37, (unsigned long)Irq5, IDT_INTERRUPT_GATE); // AT systems: Parallel Port 2. PS/2 systems: Reserved 63 | IdtSetGate(38, (unsigned long)Irq6, IDT_INTERRUPT_GATE); // Floppy Drive 64 | IdtSetGate(39, (unsigned long)Irq7, IDT_INTERRUPT_GATE); // Parallel Port 1 65 | IdtSetGate(40, (unsigned long)Irq8, IDT_INTERRUPT_GATE); // CMOS Real Time Clock 66 | IdtSetGate(41, (unsigned long)Irq9, IDT_INTERRUPT_GATE); // CGA Vertical Retrace 67 | IdtSetGate(42, (unsigned long)Irq10, IDT_INTERRUPT_GATE); // Reserved 68 | IdtSetGate(43, (unsigned long)Irq11, IDT_INTERRUPT_GATE); // Reserved 69 | IdtSetGate(44, (unsigned long)Irq12, IDT_INTERRUPT_GATE); // AT systems: Reserved. PS/2: Auxiliary Device 70 | IdtSetGate(45, (unsigned long)Irq13, IDT_INTERRUPT_GATE); // FPU 71 | IdtSetGate(46, (unsigned long)Irq14, IDT_INTERRUPT_GATE); // Hard Disk Controller 72 | IdtSetGate(47, (unsigned long)Irq15, IDT_INTERRUPT_GATE); // Reserved 73 | 74 | // The INT 0x80 can be raised from Ring 3 75 | IdtSetGate(128, (unsigned long)SysCallHandlerAsm, IDT_INTERRUPT_GATE); 76 | idtEntries[128].DPL = 3; 77 | 78 | // Loads the IDT table into the processor register (Assembler function) 79 | IdtFlush((unsigned long)&idtPointer); 80 | } 81 | 82 | // Installs the corresponding ISR routine in the IDT table 83 | void IdtSetGate(unsigned char Entry, unsigned long BaseAddress, unsigned char Type) 84 | { 85 | idtEntries[Entry].OffsetLow = (unsigned short)BaseAddress & 0xFFFF; 86 | idtEntries[Entry].Selector = 0x8; 87 | idtEntries[Entry].InterruptStackTable = 0; 88 | idtEntries[Entry].Reserved1 = 0; 89 | idtEntries[Entry].Type = Type; 90 | idtEntries[Entry].Reserved2 = 0; 91 | idtEntries[Entry].DPL = 0; 92 | idtEntries[Entry].Present = 1; 93 | idtEntries[Entry].OffsetMiddle = (unsigned short)((BaseAddress >> 16) & 0xFFFF); 94 | idtEntries[Entry].OffsetHigh = (unsigned int)((BaseAddress >> 32) & 0xFFFFFFFF); 95 | idtEntries[Entry].Reserved3 = 0; 96 | } 97 | 98 | // Our generic ISR handler, which is called from the assembly code. 99 | void IsrHandler(int InterruptNumber, unsigned long cr2, RegisterState *Registers) 100 | { 101 | if (InterruptNumber == EXCEPTION_PAGE_FAULT) 102 | { 103 | // Handle the Page Fault 104 | HandlePageFault(cr2); 105 | } 106 | else 107 | { 108 | // Every other exception just stops the system 109 | 110 | // Display the occured exception 111 | DisplayException(InterruptNumber, Registers); 112 | 113 | // Halt the system 114 | while (1 == 1) {} 115 | } 116 | } 117 | 118 | // Installs the IRQ0 interrupt handler that performs the Context Switching between the various tasks 119 | void InitTimerForContextSwitching() 120 | { 121 | IdtSetGate(32, (unsigned long)Irq0_ContextSwitching, IDT_INTERRUPT_GATE); 122 | 123 | // Loads the IDT table into the processor register (Assembler function) 124 | IdtFlush((unsigned long)&idtPointer); 125 | } 126 | 127 | // Displays the state of the general purpose registers when the exception has occured. 128 | void DisplayException(int Number, RegisterState *Registers) 129 | { 130 | // Set the Blue Screen color 131 | unsigned int color = (COLOR_BLUE << 4) | (COLOR_WHITE & 0x0F); 132 | SetColor(color); 133 | ClearScreen(); 134 | 135 | printf("A fatal error has occured!\n"); 136 | printf("ISR: 0x"); 137 | printf_int(Number, 16); 138 | printf("\n"); 139 | 140 | // Error Code 141 | printf("Error Code: "); 142 | printf_int(Registers->ErrorCode, 10); 143 | printf("\n"); 144 | 145 | // RIP register 146 | printf("RIP: 0x"); 147 | printf_long(Registers->RIP, 16); 148 | printf("\n"); 149 | 150 | // RDI register 151 | printf("RDI: 0x"); 152 | printf_long(Registers->RDI, 16); 153 | printf("\n"); 154 | 155 | // RSI register 156 | printf("RSI: 0x"); 157 | printf_long(Registers->RSI, 16); 158 | printf("\n"); 159 | 160 | // RBP register 161 | printf("RBP: 0x"); 162 | printf_long(Registers->RBP, 16); 163 | printf("\n"); 164 | 165 | // RSP register 166 | printf("RSP: 0x"); 167 | printf_long(Registers->RSP, 16); 168 | printf("\n"); 169 | 170 | // RAX register 171 | printf("RAX: 0x"); 172 | printf_long(Registers->RAX, 16); 173 | printf("\n"); 174 | 175 | // RBX register 176 | printf("RBX: 0x"); 177 | printf_long(Registers->RBX, 16); 178 | printf("\n"); 179 | 180 | // RCX register 181 | printf("RCX: 0x"); 182 | printf_long(Registers->RCX, 16); 183 | printf("\n"); 184 | 185 | // RDX register 186 | printf("RDX: 0x"); 187 | printf_long(Registers->RDX, 16); 188 | printf("\n"); 189 | 190 | // R8 register 191 | printf("R8: 0x"); 192 | printf_long(Registers->R8, 16); 193 | printf("\n"); 194 | 195 | // R9 register 196 | printf("R9: 0x"); 197 | printf_long(Registers->R9, 16); 198 | printf("\n"); 199 | 200 | // R10 register 201 | printf("R10: 0x"); 202 | printf_long(Registers->R10, 16); 203 | printf("\n"); 204 | 205 | // R11 register 206 | printf("R11: 0x"); 207 | printf_long(Registers->R11, 16); 208 | printf("\n"); 209 | 210 | // R12 register 211 | printf("R12: 0x"); 212 | printf_long(Registers->R12, 16); 213 | printf("\n"); 214 | 215 | // R13 register 216 | printf("R13: 0x"); 217 | printf_long(Registers->R13, 16); 218 | printf("\n"); 219 | 220 | // R14 register 221 | printf("R14: 0x"); 222 | printf_long(Registers->R14, 16); 223 | printf("\n"); 224 | 225 | // R15 register 226 | printf("R15: 0x"); 227 | printf_long(Registers->R15, 16); 228 | printf("\n"); 229 | 230 | // SS register 231 | printf("SS: 0x"); 232 | printf_long(Registers->SS, 16); 233 | 234 | // CS register 235 | printf(", CS: 0x"); 236 | printf_long(Registers->CS, 16); 237 | 238 | // DS register 239 | printf(", DS: 0x"); 240 | printf_long(Registers->DS, 16); 241 | 242 | // ES register 243 | printf(", ES: 0x"); 244 | printf_long(Registers->ES, 16); 245 | 246 | // FS register 247 | printf(", FS: 0x"); 248 | printf_long(Registers->FS, 16); 249 | 250 | // GS register 251 | printf(", GS: 0x"); 252 | printf_long(Registers->GS, 16); 253 | printf("\n"); 254 | 255 | // CR3 register 256 | printf("CR3: 0x"); 257 | printf_long(Registers->CR3, 16); 258 | printf("\n"); 259 | } -------------------------------------------------------------------------------- /main64/kernel/isr/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef IDT_H 2 | #define IDT_H 3 | 4 | // Virtual address where the IDT table is stored 5 | #define IDT_START_OFFSET 0xFFFF800000060000 6 | 7 | // Number of IDT entries 8 | #define IDT_ENTRIES 256 9 | 10 | // Constant for an Interrupt Gate 11 | #define IDT_INTERRUPT_GATE 0xE 12 | 13 | // Constant for a Trap Gate 14 | #define IDT_TRAP_GATE 0xF 15 | 16 | // The various CPU exceptions 17 | #define EXCEPTION_DIVIDE 0 18 | #define EXCEPTION_DEBUG 1 19 | #define EXCEPTION_NON_MASKABLE_INTERRUPT 2 20 | #define EXCEPTION_BREAKPOINT 3 21 | #define EXCEPTION_OVERFLOW 4 22 | #define EXCEPTION_BOUND_RANGE 5 23 | #define EXCEPTION_INVALID_OPCODE 6 24 | #define EXCEPTION_DEVICE_NOT_AVAILABLE 7 25 | #define EXCEPTION_DOUBLE_FAULT 8 26 | #define EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN 9 27 | #define EXCEPTION_INVALID_TSS 10 28 | #define EXCEPTION_SEGMENT_NOT_PRESENT 11 29 | #define EXCEPTION_STACK_FAULT 12 30 | #define EXCEPTION_GENERAL_PROTECTION 13 31 | #define EXCEPTION_PAGE_FAULT 14 32 | #define EXCEPTION_UNASSGIGNED 15 33 | #define EXCEPTION_X87_FPU 16 34 | #define EXCEPTION_ALIGNMENT_CHECK 17 35 | #define EXCEPTION_MACHINE_CHECK 18 36 | #define EXCEPTION_SIMD_FLOATING_POINT 19 37 | #define EXCEPTION_VIRTUALIZATION 20 38 | #define EXCEPTION_CONTROL_PROTECTION 21 39 | #define EXCEPTION_RESERVED_22 22 40 | #define EXCEPTION_RESERVED_23 23 41 | #define EXCEPTION_RESERVED_24 24 42 | #define EXCEPTION_RESERVED_25 25 43 | #define EXCEPTION_RESERVED_26 26 44 | #define EXCEPTION_RESERVED_27 27 45 | #define EXCEPTION_RESERVED_28 28 46 | #define EXCEPTION_RESERVED_29 29 47 | #define EXCEPTION_RESERVED_30 30 48 | #define EXCEPTION_RESERVED_31 31 49 | 50 | // Represents an Interrupt Gate - 128 Bit long 51 | // As described in Volume 3A: 6.14.1 52 | struct IdtEntry 53 | { 54 | unsigned short OffsetLow; // 16 Bit 55 | unsigned short Selector; // 16 Bit 56 | unsigned InterruptStackTable : 3; // 3 Bit 57 | unsigned Reserved1 : 5; // 5 Bit 58 | unsigned Type : 4; // 4 Bit 59 | unsigned Reserved2 : 1; // 1 Bit 60 | unsigned DPL : 2; // 2 Bit 61 | unsigned Present : 1; // 1 Bit 62 | unsigned short OffsetMiddle; // 16 Bit 63 | unsigned int OffsetHigh; // 32 Bit 64 | unsigned int Reserved3; // 32 Bit 65 | } __attribute__ ((packed)); 66 | typedef struct IdtEntry IdtEntry; 67 | 68 | // Represents the state of the registers when an exception has occured. 69 | typedef struct RegisterState 70 | { 71 | unsigned long RIP; 72 | unsigned long ErrorCode; 73 | 74 | // General Purpose Registers 75 | unsigned long RAX; 76 | unsigned long RBX; 77 | unsigned long RCX; 78 | unsigned long RDX; 79 | unsigned long RSI; 80 | unsigned long RDI; 81 | unsigned long RBP; 82 | unsigned long RSP; 83 | unsigned long R8; 84 | unsigned long R9; 85 | unsigned long R10; 86 | unsigned long R11; 87 | unsigned long R12; 88 | unsigned long R13; 89 | unsigned long R14; 90 | unsigned long R15; 91 | 92 | // Segment Registers 93 | unsigned long SS; 94 | unsigned long CS; 95 | unsigned long DS; 96 | unsigned long ES; 97 | unsigned long FS; 98 | unsigned long GS; 99 | 100 | // Control Registers 101 | unsigned long CR3; 102 | } RegisterState; 103 | 104 | // Represents the pointer to the interrupt gates 105 | struct IdtPointer 106 | { 107 | unsigned short Limit; 108 | unsigned long Base; 109 | } __attribute((packed)); 110 | typedef struct IdtPointer IdtPointer; 111 | 112 | // Initializes the IDT table for the ISR routines. 113 | void InitIdt(); 114 | 115 | // Installs the corresponding ISR routine in the IDT table 116 | void IdtSetGate(unsigned char Entry, unsigned long BaseAddress, unsigned char Type); 117 | 118 | // Our generic ISR handler, which is called from the assembly code. 119 | void IsrHandler(int InterruptNumber, unsigned long cr2, RegisterState *Registers); 120 | 121 | // Displays the state of the general purpose registers when the exception has occured. 122 | void DisplayException(int Number, RegisterState *Registers); 123 | 124 | // Installs the IRQ0 interrupt handler that performs the Context Switching between the various tasks 125 | void InitTimerForContextSwitching(); 126 | 127 | // Loads the IDT table into the processor register (implemented in Assembler) 128 | extern void IdtFlush(unsigned long); 129 | 130 | // Disables the hardware interrupts 131 | extern void DisableInterrupts(); 132 | 133 | // Enables the hardware interrupts 134 | extern void EnableInterrupts(); 135 | 136 | // The 32 ISR routines (implemented in Assembler) 137 | extern void Isr0(); // Divide Error Exception 138 | extern void Isr1(); // Debug Exception 139 | extern void Isr2(); // Non-Maskable Interrupt 140 | extern void Isr3(); // Breakpoint Exception 141 | extern void Isr4(); // Overflow Exception 142 | extern void Isr5(); // Bound Range Exceeded Exception 143 | extern void Isr6(); // Invalid Opcode Exception 144 | extern void Isr7(); // Device Not Available Exception 145 | extern void Isr8(); // Double Fault Exception 146 | extern void Isr9(); // Coprocessor Segment Overrun 147 | extern void Isr10(); // Invalid TSS Exception 148 | extern void Isr11(); // Segment Not Present 149 | extern void Isr12(); // Stack Fault Exception 150 | extern void Isr13(); // General Protection Exception 151 | extern void Isr14(); // Page Fault Exception 152 | extern void Isr15(); // Unassigned! 153 | extern void Isr16(); // x87 FPU Floating Point Error 154 | extern void Isr17(); // Alignment Check Exception 155 | extern void Isr18(); // Machine Check Exception 156 | extern void Isr19(); // SIMD Floating Point Exception 157 | extern void Isr20(); // Virtualization Exception 158 | extern void Isr21(); // Control Protection Exception 159 | extern void Isr22(); // Reserved! 160 | extern void Isr23(); // Reserved! 161 | extern void Isr24(); // Reserved! 162 | extern void Isr25(); // Reserved! 163 | extern void Isr26(); // Reserved! 164 | extern void Isr27(); // Reserved! 165 | extern void Isr28(); // Reserved! 166 | extern void Isr29(); // Reserved! 167 | extern void Isr30(); // Reserved! 168 | extern void Isr31(); // Reserved! 169 | 170 | #endif -------------------------------------------------------------------------------- /main64/kernel/isr/irq.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | [EXTERN IrqHandler] 3 | [EXTERN MoveToNextTask] 4 | 5 | %MACRO IRQ 2 6 | GLOBAL Irq%1 7 | Irq%1: 8 | ; Disable interrupts 9 | CLI 10 | 11 | ; Save the General Purpose Registers on the Stack 12 | PUSH RDI 13 | PUSH RSI 14 | PUSH RBP 15 | PUSH RSP 16 | PUSH RAX 17 | PUSH RBX 18 | PUSH RCX 19 | PUSH RDX 20 | PUSH R8 21 | PUSH R9 22 | PUSH R10 23 | PUSH R11 24 | PUSH R12 25 | PUSH R13 26 | PUSH R14 27 | PUSH R15 28 | 29 | ; Call the ISR handler that is implemented in C 30 | MOV RDI, %2 31 | CALL IrqHandler 32 | 33 | ; Restore the General Purpose Registers from the Stack 34 | POP R15 35 | POP R14 36 | POP R13 37 | POP R12 38 | POP R11 39 | POP R10 40 | POP R9 41 | POP R8 42 | POP RDX 43 | POP RCX 44 | POP RBX 45 | POP RAX 46 | POP RSP 47 | POP RBP 48 | POP RSI 49 | POP RDI 50 | 51 | ; Enable Interrupts 52 | STI 53 | 54 | ; Return 55 | IRETQ 56 | %ENDMACRO 57 | 58 | IRQ 0, 32 ; Timer 59 | IRQ 1, 33 ; Keyboard 60 | IRQ 2, 34 ; Cascade for 8259A Slave Controller 61 | IRQ 3, 35 ; Serial Port 2 62 | IRQ 4, 36 ; Serial Port 1 63 | IRQ 5, 37 ; AT systems: Parallel Port 2. PS/2 systems: Reserved 64 | IRQ 6, 38 ; Floppy Drive 65 | IRQ 7, 39 ; Parallel Port 1 66 | IRQ 8, 40 ; CMOS Real Time Clock 67 | IRQ 9, 41 ; CGA Vertical Retrace 68 | IRQ 10, 42 ; Reserved 69 | IRQ 11, 43 ; Reserved 70 | IRQ 12, 44 ; AT systems: Reserved. PS/2: Auxiliary Device 71 | IRQ 13, 45 ; FPU 72 | IRQ 14, 36 ; Hard Disk Controller 73 | IRQ 15, 47 ; Reserved -------------------------------------------------------------------------------- /main64/kernel/isr/irq.c: -------------------------------------------------------------------------------- 1 | #include "irq.h" 2 | #include "idt.h" 3 | #include "pic.h" 4 | #include "../common.h" 5 | 6 | // Defines an array for our various IRQ handlers 7 | IRQ_HANDLER InterruptHandlers[IRQ_ENTRIES]; 8 | 9 | // Registers a IRQ callback function 10 | void RegisterIrqHandler(int n, IRQ_HANDLER Handler) 11 | { 12 | InterruptHandlers[n] = Handler; 13 | } 14 | 15 | // Common IRQ handler that is called as soon as an IRQ is raised 16 | void IrqHandler(int InterruptNumber) 17 | { 18 | // Signal that we have handled the received interrupt 19 | if (InterruptNumber >= 40) 20 | { 21 | // Send reset signal to slave 22 | outb(I86_PIC2_REG_COMMAND, I86_PIC_OCW2_MASK_EOI); 23 | } 24 | 25 | // Send reset signal to master 26 | outb(I86_PIC1_REG_COMMAND, I86_PIC_OCW2_MASK_EOI); 27 | 28 | // Call the IRQ callback function, if one is registered 29 | if (InterruptHandlers[InterruptNumber] != 0) 30 | { 31 | IRQ_HANDLER handler = InterruptHandlers[InterruptNumber]; 32 | handler(InterruptNumber); 33 | } 34 | } -------------------------------------------------------------------------------- /main64/kernel/isr/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef IRQ_H 2 | #define IRQ_H 3 | 4 | // Number of IDT entries 5 | #define IRQ_ENTRIES 256 6 | 7 | // Callback function pointer for handling the various IRQs 8 | typedef void (*IRQ_HANDLER)(int Number); 9 | 10 | // Registers a IRQ callback function 11 | void RegisterIrqHandler(int n, IRQ_HANDLER Handler); 12 | 13 | // IRQ handler that is called as soon as an IRQ is raised 14 | void IrqHandler(int InterruptNumber); 15 | 16 | // Our 15 IRQ routines (implemented in assembly code) 17 | extern void Irq0(); // Timer 18 | extern void Irq1(); // Keyboard 19 | extern void Irq2(); // Cascade for 8259A Slave Controller 20 | extern void Irq3(); // Serial Port 2 21 | extern void Irq4(); // Serial Port 1 22 | extern void Irq5(); // AT systems: Parallel Port 2. PS/2 systems: Reserved 23 | extern void Irq6(); // Floppy Drive 24 | extern void Irq7(); // Parallel Port 1 25 | extern void Irq8(); // CMOS Real Time Clock 26 | extern void Irq9(); // CGA Vertical Retrace 27 | extern void Irq10(); // Reserved 28 | extern void Irq11(); // Reserved 29 | extern void Irq12(); // AT systems: Reserved. PS/2: Auxiliary Device 30 | extern void Irq13(); // FPU 31 | extern void Irq14(); // Hard Disk Controller 32 | extern void Irq15(); // Reserved 33 | 34 | #endif -------------------------------------------------------------------------------- /main64/kernel/isr/pic.c: -------------------------------------------------------------------------------- 1 | #include "pic.h" 2 | #include "../common.h" 3 | 4 | // This code is based on http://www.brokenthorn.com/Resources/OSDevPic.html 5 | 6 | // Initializes the PIC, and remaps the IRQs 7 | void InitPic(unsigned char base0, unsigned char base1) 8 | { 9 | unsigned char icw = 0; 10 | 11 | // Begin initialization of PIC 12 | icw = (icw & ~I86_PIC_ICW1_MASK_INIT) | I86_PIC_ICW1_INIT_YES; 13 | icw = (icw & ~I86_PIC_ICW1_MASK_IC4) | I86_PIC_ICW1_IC4_EXPECT; 14 | 15 | PicSendCommand(icw, 0); 16 | PicSendCommand(icw, 1); 17 | 18 | // Send initialization control word 2. This is the base addresses of the irq's 19 | PicSendData(base0, 0); 20 | PicSendData(base1, 1); 21 | 22 | // Send initialization control word 3. This is the connection between master and slave. 23 | // ICW3 for master PIC is the IR that connects to secondary pic in binary format 24 | // ICW3 for secondary PIC is the IR that connects to master pic in decimal format 25 | PicSendData(0x04, 0); 26 | PicSendData(0x02, 1); 27 | 28 | // Send Initialization control word 4. 29 | // Enables i86 mode. 30 | icw = (icw & ~I86_PIC_ICW4_MASK_UPM) | I86_PIC_ICW4_UPM_86MODE; 31 | PicSendData(icw, 0); 32 | PicSendData(icw, 1); 33 | } 34 | 35 | // Sends a command to the PICs 36 | static void PicSendCommand(unsigned char cmd, unsigned char picNum) 37 | { 38 | if (picNum > 1) 39 | return; 40 | 41 | unsigned char reg = (picNum == 1) ? I86_PIC2_REG_COMMAND : I86_PIC1_REG_COMMAND; 42 | outb(reg, cmd); 43 | } 44 | 45 | // Sends data to PICs 46 | static void PicSendData(unsigned char data, unsigned char picNum) 47 | { 48 | if (picNum > 1) 49 | return; 50 | 51 | unsigned char reg = (picNum == 1) ? I86_PIC2_REG_DATA : I86_PIC1_REG_DATA; 52 | outb(reg, data); 53 | } 54 | 55 | // Reads data from PICs 56 | static unsigned char PicReadData(unsigned char picNum) 57 | { 58 | if (picNum > 1) 59 | return 0; 60 | 61 | unsigned char reg = (picNum == 1) ? I86_PIC2_REG_DATA : I86_PIC1_REG_DATA; 62 | return inb(reg); 63 | } -------------------------------------------------------------------------------- /main64/kernel/isr/pic.h: -------------------------------------------------------------------------------- 1 | #ifndef PIC_H 2 | #define PIC_H 3 | 4 | // This code is based on http://www.brokenthorn.com/Resources/OSDevPic.html 5 | 6 | //----------------------------------------------- 7 | // Devices connected to the PICs. May be useful 8 | // when enabling and disabling irq's 9 | //----------------------------------------------- 10 | 11 | // The following devices use PIC 1 to generate interrupts 12 | #define I86_PIC_IRQ_TIMER 0 13 | #define I86_PIC_IRQ_KEYBOARD 1 14 | #define I86_PIC_IRQ_SERIAL2 3 15 | #define I86_PIC_IRQ_SERIAL1 4 16 | #define I86_PIC_IRQ_PARALLEL2 5 17 | #define I86_PIC_IRQ_DISKETTE 6 18 | #define I86_PIC_IRQ_PARALLEL1 7 19 | 20 | // The following devices use PIC 2 to generate interrupts 21 | #define I86_PIC_IRQ_CMOSTIMER 0 22 | #define I86_PIC_IRQ_CGARETRACE 1 23 | #define I86_PIC_IRQ_AUXILIARY 4 24 | #define I86_PIC_IRQ_FPU 5 25 | #define I86_PIC_IRQ_HDC 6 26 | 27 | //----------------------------------------------- 28 | // Command words are used to control the devices 29 | //----------------------------------------------- 30 | 31 | // Command Word 2 bit masks. Use when sending commands 32 | #define I86_PIC_OCW2_MASK_L1 1 // 00000001 33 | #define I86_PIC_OCW2_MASK_L2 2 // 00000010 34 | #define I86_PIC_OCW2_MASK_L3 4 // 00000100 35 | #define I86_PIC_OCW2_MASK_EOI 0x20 // 00100000 36 | #define I86_PIC_OCW2_MASK_SL 0x40 // 01000000 37 | #define I86_PIC_OCW2_MASK_ROTATE 0x80 // 10000000 38 | 39 | // Command Word 3 bit masks. Use when sending commands 40 | #define I86_PIC_OCW3_MASK_RIS 1 // 00000001 41 | #define I86_PIC_OCW3_MASK_RIR 2 // 00000010 42 | #define I86_PIC_OCW3_MASK_MODE 4 // 00000100 43 | #define I86_PIC_OCW3_MASK_SMM 0x20 // 00100000 44 | #define I86_PIC_OCW3_MASK_ESMM 0x40 // 01000000 45 | #define I86_PIC_OCW3_MASK_D7 0x80 // 10000000 46 | 47 | //----------------------------------------------- 48 | // PIC Controller Registers 49 | //----------------------------------------------- 50 | 51 | // PIC 1 register port addresses 52 | #define I86_PIC1_REG_COMMAND 0x20 53 | #define I86_PIC1_REG_STATUS 0x20 54 | #define I86_PIC1_REG_DATA 0x21 55 | #define I86_PIC1_REG_IMR 0x21 56 | 57 | // PIC 2 register port addresses 58 | #define I86_PIC2_REG_COMMAND 0xA0 59 | #define I86_PIC2_REG_STATUS 0xA0 60 | #define I86_PIC2_REG_DATA 0xA1 61 | #define I86_PIC2_REG_IMR 0xA1 62 | 63 | //----------------------------------------------- 64 | // Initialization Command Bit Masks 65 | //----------------------------------------------- 66 | 67 | // Initialization Control Word 1 bit masks 68 | #define I86_PIC_ICW1_MASK_IC4 0x1 // 00000001 69 | #define I86_PIC_ICW1_MASK_SNGL 0x2 // 00000010 70 | #define I86_PIC_ICW1_MASK_ADI 0x4 // 00000100 71 | #define I86_PIC_ICW1_MASK_LTIM 0x8 // 00001000 72 | #define I86_PIC_ICW1_MASK_INIT 0x10 // 00010000 73 | 74 | // Initialization Control Words 2 and 3 do not require bit masks 75 | 76 | // Initialization Control Word 4 bit masks 77 | #define I86_PIC_ICW4_MASK_UPM 0x1 // 00000001 78 | #define I86_PIC_ICW4_MASK_AEOI 0x2 // 00000010 79 | #define I86_PIC_ICW4_MASK_MS 0x4 // 00000100 80 | #define I86_PIC_ICW4_MASK_BUF 0x8 // 00001000 81 | #define I86_PIC_ICW4_MASK_SFNM 0x10 // 00010000 82 | 83 | //----------------------------------------------- 84 | // Initialization Command 1 control bits 85 | //----------------------------------------------- 86 | 87 | #define I86_PIC_ICW1_IC4_EXPECT 1 // 1 88 | #define I86_PIC_ICW1_IC4_NO 0 // 0 89 | #define I86_PIC_ICW1_SNGL_YES 2 // 10 90 | #define I86_PIC_ICW1_SNGL_NO 0 // 00 91 | #define I86_PIC_ICW1_ADI_CALLINTERVAL4 4 // 100 92 | #define I86_PIC_ICW1_ADI_CALLINTERVAL8 0 // 000 93 | #define I86_PIC_ICW1_LTIM_LEVELTRIGGERED 8 // 1000 94 | #define I86_PIC_ICW1_LTIM_EDGETRIGGERED 0 // 0000 95 | #define I86_PIC_ICW1_INIT_YES 0x10 // 10000 96 | #define I86_PIC_ICW1_INIT_NO 0 // 00000 97 | 98 | //----------------------------------------------- 99 | // Initialization Command 4 control bits 100 | //----------------------------------------------- 101 | 102 | #define I86_PIC_ICW4_UPM_86MODE 1 // 1 103 | #define I86_PIC_ICW4_UPM_MCSMODE 0 // 0 104 | #define I86_PIC_ICW4_AEOI_AUTOEOI 2 // 10 105 | #define I86_PIC_ICW4_AEOI_NOAUTOEOI 0 // 0 106 | #define I86_PIC_ICW4_MS_BUFFERMASTER 4 // 100 107 | #define I86_PIC_ICW4_MS_BUFFERSLAVE 0 // 0 108 | #define I86_PIC_ICW4_BUF_MODEYES 8 // 1000 109 | #define I86_PIC_ICW4_BUF_MODENO 0 // 0 110 | #define I86_PIC_ICW4_SFNM_NESTEDMODE 0x10 // 10000 111 | #define I86_PIC_ICW4_SFNM_NOTNESTED 0 // a binary 2 112 | 113 | // Initializes the PIC, and remaps the IRQs 114 | void InitPic(unsigned char base0, unsigned char base1); 115 | 116 | // Sends a command to the PICs 117 | static void PicSendCommand(unsigned char cmd, unsigned char picNum); 118 | 119 | // Sends data to PICs 120 | static void PicSendData(unsigned char data, unsigned char picNum); 121 | 122 | // Reads data from PICs 123 | static unsigned char PicReadData(unsigned char picNum); 124 | 125 | #endif -------------------------------------------------------------------------------- /main64/kernel/kernel.c: -------------------------------------------------------------------------------- 1 | #include "drivers/screen.h" 2 | #include "drivers/keyboard.h" 3 | #include "drivers/timer.h" 4 | #include "memory/physical-memory.h" 5 | #include "memory/virtual-memory.h" 6 | #include "memory/heap.h" 7 | #include "multitasking/multitasking.h" 8 | #include "multitasking/gdt.h" 9 | #include "isr/pic.h" 10 | #include "isr/idt.h" 11 | #include "io/fat12.h" 12 | #include "kernel.h" 13 | #include "common.h" 14 | #include "date.h" 15 | 16 | // The main entry of our Kernel 17 | void KernelMain(int KernelSize) 18 | { 19 | // Initialize the Kernel 20 | InitKernel(KernelSize); 21 | 22 | /* // Print out a welcome message 23 | SetColor(COLOR_LIGHT_BLUE); 24 | printf("Executing the x64 KAOS Kernel at the virtual address 0x"); 25 | printf_long((unsigned long)&KernelMain, 16); 26 | printf("...\n"); 27 | printf("===============================================================================\n\n"); 28 | SetColor(COLOR_WHITE); */ 29 | 30 | // Halt the system 31 | while (1 == 1) {} 32 | } 33 | 34 | // Initializes the whole Kernel 35 | void InitKernel(int KernelSize) 36 | { 37 | // Initialize and clear the screen 38 | InitializeScreen(80, 24); 39 | 40 | // Initializes the Serial Port 41 | InitSerialPort(); 42 | 43 | // Disable the hardware interrupts 44 | DisableInterrupts(); 45 | 46 | // Initialize the physical Memory Manager 47 | InitPhysicalMemoryManager(KernelSize); 48 | 49 | // Initialize the virtual Memory Manager 50 | InitVirtualMemoryManager(0); 51 | 52 | // Initializes the PIC, and remap the IRQ handlers. 53 | // The 1st PIC handles the hardware interrupts 32 - 39 (input value 0x20). 54 | // The 2nd PIC handles the hardware interrupts 40 - 47 (input value 0x28). 55 | InitPic(0x20, 0x28); 56 | 57 | // Initialize the ISR & IRQ routines 58 | InitIdt(); 59 | 60 | // Initialize the keyboard 61 | InitKeyboard(); 62 | 63 | // Initialize the timer to fire every 4ms 64 | InitTimer(250); 65 | 66 | // Enable the hardware interrupts again 67 | EnableInterrupts(); 68 | 69 | // Initialize the Heap. 70 | // It generates Page Faults, therefore the interrupts must be already re-enabled. 71 | InitHeap(); 72 | 73 | // Initializes the GDT and TSS structures 74 | InitGdt(); 75 | 76 | // Initializes the FAT12 file system 77 | InitFAT12(); 78 | 79 | // Create the initial OS tasks 80 | CreateInitialTasks(); 81 | 82 | // Refresh the status line 83 | RefreshStatusLine(); 84 | 85 | // Register the Context Switching IRQ Handler when the Timer fires 86 | InitTimerForContextSwitching(); 87 | } 88 | 89 | // Causes a Divide by Zero Exception 90 | void DivideByZeroException() 91 | { 92 | // This causes a Divide by Zero Exception - which calls the ISR0 routine 93 | int a = 5; 94 | int b = 0; 95 | int c = a / b; 96 | } 97 | 98 | // Tests the functionality of the keyboard 99 | void KeyboardTest() 100 | { 101 | char input[100] = ""; 102 | 103 | printf("Please enter your name: "); 104 | scanf(input, 98); 105 | 106 | printf("Your name is "); 107 | printf(input); 108 | printf("\n"); 109 | } -------------------------------------------------------------------------------- /main64/kernel/kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_H 2 | #define KERNEL_H 3 | 4 | // The main entry of our Kernel 5 | void KernelMain(int KernelSize); 6 | 7 | // Initializes the whole Kernel 8 | void InitKernel(int KernelSize); 9 | 10 | // Causes a Divide by Zero Exception 11 | void DivideByZeroException(); 12 | 13 | // Tests the functionality of the keyboard 14 | void KeyboardTest(); 15 | 16 | #endif -------------------------------------------------------------------------------- /main64/kernel/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(KernelMain) 2 | 3 | SECTIONS 4 | { 5 | . = 0xFFFF800000100000; 6 | .text : AT(ADDR(.text) - 0xFFFF800000000000) 7 | { 8 | *(.text .text.*) 9 | *(.data .data.*) 10 | *(.rodata .rodata.*) 11 | . = ALIGN(4K); 12 | } 13 | 14 | .bss : AT(ADDR(.bss) - 0xFFFF800000000000) 15 | { 16 | *(.bss .bss.*) 17 | } 18 | 19 | .eh_frame : AT(ADDR(.eh_frame) - 0xFFFF800000000000) 20 | { 21 | *(.eh_frame .eh_frame.*) 22 | } 23 | } -------------------------------------------------------------------------------- /main64/kernel/list.c: -------------------------------------------------------------------------------- 1 | #include "drivers/screen.h" 2 | #include "memory/heap.h" 3 | #include "list.h" 4 | 5 | // Creates a new Double Linked List 6 | List *NewList() 7 | { 8 | // Allocate a new List structure on the Heap 9 | List *list = malloc(sizeof(List)); 10 | list->Count = 0; 11 | list->RootEntry = 0x0; 12 | 13 | return list; 14 | } 15 | 16 | // Adds a new entry to the given Double Linked List 17 | void AddEntryToList(List *List, void *Payload, unsigned long Key) 18 | { 19 | ListEntry *newEntry = NewListEntry(Payload, Key); 20 | 21 | if (!List->RootEntry) 22 | { 23 | // Add the first, initial entry to the List 24 | List->RootEntry = newEntry; 25 | } 26 | else 27 | { 28 | ListEntry *currentEntry = List->RootEntry; 29 | 30 | // Move to the end of the List 31 | while (currentEntry->Next) 32 | currentEntry = currentEntry->Next; 33 | 34 | // Add the new entry to the end of the List 35 | currentEntry->Next = newEntry; 36 | newEntry->Previous = currentEntry; 37 | } 38 | 39 | // Increment the number of List entries 40 | List->Count++; 41 | } 42 | 43 | // Returns an entry from the given Double Linked List 44 | ListEntry *GetEntryFromList(List *List, unsigned long Key) 45 | { 46 | ListEntry *currentEntry = List->RootEntry; 47 | int currentIndex; 48 | 49 | while (currentEntry != 0x0) 50 | { 51 | // Check if we have found the requested entry in the Double Linked List 52 | if (currentEntry->Key == Key) 53 | return currentEntry; 54 | 55 | // Move to the next entry in the Double Linked List 56 | currentEntry = currentEntry->Next; 57 | } 58 | 59 | // The List entry was not found 60 | return (void *)0x0; 61 | } 62 | 63 | // Removes a Node from the given Double Linked List 64 | void RemoveEntryFromList(List *List, ListEntry *Entry) 65 | { 66 | ListEntry *nextEntry = 0x0; 67 | ListEntry *previousEntry = 0x0; 68 | 69 | if (Entry->Previous == 0x0) 70 | { 71 | // When we remove the first list entry, we just set the new root node to the 2nd list entry 72 | List->RootEntry = Entry->Next; 73 | List->RootEntry->Previous = 0x0; 74 | } 75 | else 76 | { 77 | // Remove the ListNode from the Double Linked List 78 | previousEntry = Entry->Previous; 79 | nextEntry = Entry->Next; 80 | previousEntry->Next = nextEntry; 81 | nextEntry->Previous = previousEntry; 82 | } 83 | 84 | // Decrement the number of List entries 85 | List->Count--; 86 | 87 | // Release the memory of the ListNode structure on the Heap 88 | free(Entry); 89 | } 90 | 91 | // This function prints out the content of the Double Linked List 92 | void PrintList(List *List) 93 | { 94 | ListEntry *currentEntry = List->RootEntry; 95 | 96 | printf("Number of List entries: "); 97 | printf_int(List->Count, 10); 98 | printf("\n\n"); 99 | 100 | // Call the custom print function for the Double Linked List 101 | List->PrintFunctionPtr(); 102 | } 103 | 104 | // Creates a new ListEntry structure 105 | static ListEntry *NewListEntry(void *Payload, unsigned long Key) 106 | { 107 | // Allocate a new ListNode structure on the Heap 108 | ListEntry *entry = malloc(sizeof(ListEntry)); 109 | entry->Previous = 0x0; 110 | entry->Next = 0x0; 111 | entry->Payload = Payload; 112 | entry->Key = Key; 113 | 114 | return entry; 115 | } -------------------------------------------------------------------------------- /main64/kernel/list.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H 2 | #define LIST_H 3 | 4 | // This structure defines a single entry in a Double Linked List. 5 | typedef struct ListEntry 6 | { 7 | void *Payload; // The actual data of the List entry 8 | unsigned long Key; // The unique key of the List entry 9 | struct ListEntry *Next; // Pointer to the next List entry 10 | struct ListEntry *Previous; // Pointer to the previous List entry 11 | } ListEntry; 12 | 13 | // Defines a simple Doube Linked List 14 | typedef struct List 15 | { 16 | int Count; 17 | ListEntry *RootEntry; 18 | void (*PrintFunctionPtr)(void); 19 | } List; 20 | 21 | // Creates a new Double Linked List 22 | List *NewList(); 23 | 24 | // Adds a new entry to the given Double Linked List 25 | void AddEntryToList(List *List, void *Payload, unsigned long Key); 26 | 27 | // Returns an entry from the given Double Linked List 28 | ListEntry *GetEntryFromList(List *List, unsigned long Key); 29 | 30 | // Removes an entry from the given Double Linked List 31 | void RemoveEntryFromList(List *List, ListEntry *Node); 32 | 33 | // This function prints out the content of the Double Linked List 34 | void PrintList(List *List); 35 | 36 | // Creates a new ListEntry structure 37 | static ListEntry *NewListEntry(void *Payload, unsigned long Key); 38 | 39 | #endif -------------------------------------------------------------------------------- /main64/kernel/makefile: -------------------------------------------------------------------------------- 1 | # Automatically generate lists of sources using wildcards. 2 | C_SOURCES = $(wildcard *.c drivers/*.c isr/*.c memory/*.c multitasking/*.c syscalls/*.c io/*.c) 3 | HEADERS = $(wildcard *.h drivers/*.h isr/*.h memory/*.h multitasking/*.h syscalls/*.h io/*.h) 4 | 5 | # Convert the *.c filenames to *.o to give a list of object files to build 6 | OBJ = ${C_SOURCES:.c=.o} 7 | 8 | # Builds the final floppy image from which the OS can be booted. 9 | kaos64.img : bootsector.bin kernel.bin 10 | fat_imgen -c -s ../boot/bootsector.bin -f ../kaos64.img 11 | fat_imgen -m -f ../kaos64.img -i ../kaosldr_16/kldr16.bin 12 | fat_imgen -m -f ../kaos64.img -i ../kaosldr_64/kldr64.bin 13 | fat_imgen -m -f ../kaos64.img -i ../kernel/kernel.bin 14 | fat_imgen -m -f ../kaos64.img -i ../programs/program1/prog1.bin 15 | fat_imgen -m -f ../kaos64.img -i ../programs/program2/prog2.bin 16 | fat_imgen -m -f ../kaos64.img -i ../programs/shell/shell.bin 17 | fat_imgen -m -f ../kaos64.img -i ../BigFile.txt 18 | fat_imgen -m -f ../kaos64.img -i ../SFile.txt 19 | x86_64-elf-objdump -M intel -S --disassemble kernel.o > kernel.generated 20 | x86_64-elf-objdump -M intel -S --disassemble drivers/screen.o > drivers/screen.generated 21 | x86_64-elf-objdump -M intel -S --disassemble multitasking/contextswitching.o > multitasking/contextswitching.generated 22 | x86_64-elf-objdump -M intel -S --disassemble multitasking/multitasking.o > multitasking/multitasking.generated 23 | 24 | # Builds the boot sector 25 | bootsector.bin: ../boot/bootsector.asm 26 | nasm -fbin ../boot/bootsector.asm -o ../boot/bootsector.bin 27 | 28 | # Builds the ISR handlers written in Assembler 29 | isr/idt_asm.o : isr/idt.asm 30 | nasm -felf64 isr/idt.asm -o isr/idt_asm.o 31 | 32 | # Builds the IRQ handlers written in Assembler 33 | isr/irq_asm.o : isr/irq.asm 34 | nasm -felf64 isr/irq.asm -o isr/irq_asm.o 35 | 36 | # Builds the GDT functions written in Assembler 37 | multitasking/gdt_asm.o : multitasking/gdt.asm 38 | nasm -felf64 multitasking/gdt.asm -o multitasking/gdt_asm.o 39 | 40 | # Builds the Task Switching functionality written in Assembler 41 | multitasking/contextswitching.o : multitasking/contextswitching.asm 42 | nasm -felf64 multitasking/contextswitching.asm -o multitasking/contextswitching.o 43 | 44 | # Builds the SysCall functionality written in Assembler 45 | syscalls/syscall_asm.o : syscalls/syscall.asm 46 | nasm -felf64 syscalls/syscall.asm -o syscalls/syscall_asm.o 47 | 48 | # Compiles the C kernel 49 | %.o : %.c ${HEADERS} 50 | x86_64-elf-gcc -ffreestanding -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -c $< -o $@ 51 | 52 | # Links the C kernel 53 | # The file "kernel.o" is specified explicitly, so that it is the first part of the file "kernel.bin" 54 | kernel.bin: kernel.o isr/idt_asm.o isr/irq_asm.o multitasking/contextswitching.o multitasking/gdt_asm.o syscalls/syscall_asm.o ${OBJ} 55 | x86_64-elf-ld -o $@ -Tlink.ld $^ --oformat binary -z max-page-size=0x1000 -Map kernel.map 56 | 57 | # Clean up 58 | clean: 59 | rm -f ../boot/bootsector.bin 60 | rm -f ../kaos64.img 61 | rm -f *.o *.map *.bin 62 | rm -f drivers/*.o 63 | rm -f isr/*.o 64 | rm -f memory/*.o 65 | rm -f multitasking/*.o 66 | rm -f syscalls/*.o 67 | rm -f io/*.o 68 | rm -f *.generated 69 | -------------------------------------------------------------------------------- /main64/kernel/memory/heap.h: -------------------------------------------------------------------------------- 1 | #ifndef HEAP_H 2 | #define HEAP_H 3 | 4 | #define HEADER_SIZE 4 5 | 6 | typedef struct HeapBlock 7 | { 8 | // Header: 4 bytes 9 | int InUse : 1; 10 | int Size : 31; 11 | 12 | // Payload 13 | unsigned char Payload[0]; 14 | } HeapBlock; 15 | 16 | // Initializes the Heap Manager. 17 | int InitHeap(); 18 | 19 | // Returns if the Heap Manager is fully initialized. 20 | int IsHeapInitialized(); 21 | 22 | // Dumps out the status of each Heap Block 23 | void DumpHeap(); 24 | 25 | // Allocates the specific amount of memory on the Heap 26 | void *malloc(int Size); 27 | 28 | // Frees up a Heap Block 29 | void free(void *ptr); 30 | 31 | // Tests the Heap Manager with simple malloc()/free() calls. 32 | void TestHeapManager(int DebugOutput); 33 | 34 | // Tests the Heap Manaager across Page boundaries. 35 | void TestHeapManagerAcrossPageBoundaries(int DebugOutput); 36 | 37 | // Tests the Heap Manager with huge allocation requests. 38 | void TestHeapManagerWithHugeAllocations(int DebugOutput); 39 | 40 | // Finds a free block of the requested size on the Heap 41 | static HeapBlock *Find(int Size); 42 | 43 | // Returns the next Heap Block 44 | static HeapBlock *NextHeapBlock(HeapBlock *Block); 45 | 46 | // Returns the last Heap Block 47 | static HeapBlock *GetLastHeapBlock(); 48 | 49 | // Allocates a Heap Block at the beginning of "*Block" with a size of "Size". 50 | // Splits the remaining available Heap Space and marks it as a free Heap Block 51 | static void Allocate(HeapBlock *Block, int Size); 52 | 53 | // Merges 2 free blocks into one larger free block 54 | static int Merge(); 55 | 56 | // Dumps out the status of a Heap Block 57 | static void PrintHeapBlock(HeapBlock *Block); 58 | 59 | #endif -------------------------------------------------------------------------------- /main64/kernel/memory/physical-memory.h: -------------------------------------------------------------------------------- 1 | #ifndef PHYSICAL_MEMORY_H 2 | #define PHYSICAL_MEMORY_H 3 | 4 | // The offset where the Memory Map is stored 5 | #define MEMORYMAP_OFFSET 0x1200 6 | 7 | #define PAGE_SIZE 4096 8 | #define BITS_PER_BYTE 8 9 | #define MARK_1MB 0x100000 10 | 11 | #define INDEX_FROM_BIT(a) (a / ( 8 * 4 * 2)) 12 | #define OFFSET_FROM_BIT(a) (a % ( 8 * 4 * 2)) 13 | 14 | // Describes a Memory Map Entry that we have obtained from the BIOS. 15 | typedef struct BiosMemoryRegion 16 | { 17 | unsigned long Start; // Physical Start Address 18 | unsigned long Size; // Length in Bytes 19 | int Type; // Type - see MemoryRegionType below 20 | int Reserved; // Reserved 21 | } BiosMemoryRegion; 22 | 23 | // Describes a single Memory Region that is managed by the Physical Memory Manager. 24 | typedef struct PhysicalMemoryRegionDescriptor 25 | { 26 | unsigned long PhysicalMemoryStartAddress; // Physical memory address, where the memory region starts 27 | unsigned long AvailablePageFrames; // The number of physical Page Frames that are available 28 | unsigned long BitmapMaskStartAddress; // Physical memory address, where the bitmap mask is stored 29 | unsigned long BitmapMaskSize; // The size of the bitmap mask in bytes 30 | unsigned long FreePageFrames; // The number of free (unallocated) Page Frames 31 | } PhysicalMemoryRegionDescriptor; 32 | 33 | // Describes the whole memory layout that is managed by the 34 | // Physical Memory Manager. 35 | typedef struct PhysicalMemoryLayout 36 | { 37 | // The number of managed memory regions. 38 | unsigned int MemoryRegionCount; 39 | 40 | // We have to make sure that we pad all previous structure members to multiple 41 | // of 8 bytes, otherwise we get an unaligned pointer for the following array. 42 | // Therefore, we add here 4 additional bytes, so that the array "Regions" starts 43 | // at a multiple of 8 bytes. 44 | unsigned int padding; 45 | 46 | // The PhysicalMemoryRegionDescriptor array is at the end of this struct, because 47 | // it has a dynamic size based on the number of memory regions. 48 | PhysicalMemoryRegionDescriptor MemoryRegions[]; 49 | } PhysicalMemoryLayout; 50 | 51 | // Describes a physical Page Frame 52 | typedef struct PageFrame 53 | { 54 | // The physical Page Frame Number 55 | unsigned long PageFrameNumber; 56 | 57 | // The Memory Region index in which the Page Frame was allocated. 58 | // With this information we can perform a lookup into the array PhysicalMemoryLayout->MemoryRegions[] 59 | // to release a Page Frame at a later point in time. 60 | unsigned int MemoryRegionIndex; 61 | } PageFrame; 62 | 63 | // This double-linked list entry represents a Page Frame that is currently tracked by the Kernel. 64 | typedef struct TrackedPageFrameListEntry 65 | { 66 | struct TrackedPageFrameListEntry *Previous; // Pointer to the previous list entry 67 | struct TrackedPageFrameListEntry *Next; // Pointer to the next list entry 68 | PageFrame *PageFrame; // A reference to the tracked Page Frame 69 | } TrackedPageFrameListEntry; 70 | 71 | // Initializes the physical Memory Manager. 72 | void InitPhysicalMemoryManager(int KernelSize); 73 | 74 | // Allocates the first free Page Frame and returns the Page Frame number. 75 | unsigned long AllocatePageFrame(); 76 | 77 | // Releases a physical Page Frame. 78 | void ReleasePageFrame(unsigned long PageFrameNumber); 79 | 80 | // This function adds the Page Frame to the TrackedPageFrameList 81 | static void AddPageFrameToTrackedList(unsigned long PageFrameNumber, int MemoryRegionIndex); 82 | 83 | // This function prints out the currently tracked Page Frames. 84 | void PrintTrackedPageFrameList(); 85 | 86 | // Prints out the memory map that we have obtained from the BIOS 87 | void PrintMemoryMap(); 88 | 89 | // Returns the number of used physical Page Frames by the Kernel and the Physical Memory Manager itself 90 | static int GetUsedPageFrames(PhysicalMemoryLayout *MemoryLayout); 91 | 92 | // Tests the Bitmap mask functionality 93 | void TestBitmapMask(); 94 | 95 | // Tests the Physical Memory Manager by allocating Page Frames in the various 96 | // available memory regions... 97 | void TestPhysicalMemoryManager(); 98 | 99 | // Tests the Page Frame Tracking 100 | void TestPageFrameTracking(); 101 | 102 | #endif -------------------------------------------------------------------------------- /main64/kernel/memory/virtual-memory.h: -------------------------------------------------------------------------------- 1 | #ifndef VIRTUAL_MEMORY_H 2 | #define VIRTUAL_MEMORY_H 3 | 4 | #define SMALL_PAGE_SIZE 4096 5 | #define PT_ENTRIES 512 6 | 7 | // A temporary virtual address to which physical page frames can be mapped to 8 | #define TEMPORARY_VIRTUAL_PAGE 0xFFFF80000DEAD000 9 | 10 | // ========================================================================== 11 | // The following macros are used to access the various Page Table structures 12 | // through the recursive Page Table Mapping in the 511th entry of the PML4. 13 | // 14 | // VA == Virtual Address 15 | // PML4 == Page Map Level 4 16 | // PDP == Page Directory Pointer Table 17 | // PD == Page Directory Table 18 | // PT == Page Table 19 | // ========================================================================== 20 | 21 | // 0xFFFFFFFFFFFFF000 22 | // Sign Extension PML4 PDP PD PT Offset 23 | // 1111111111111111 111111111 111111111 111111111 111111111 000000000000 24 | // 511 dec 511 dec 511 dec 511 dec 25 | // => PML4 => PML4 => PML4 => PML4 ==>>> PML4 as a result 26 | #define PML4_TABLE ((unsigned long *)(0xFFFFFFFFFFFFF000)) 27 | 28 | // 0xFFFFFFFFFFE00000 29 | // Sign Extension PML4 PDP PD PT (VA!) Offset 30 | // 111111111111111 1111111111 111111111 111111111 000000000 000000000000 31 | // 511 dec 511 dec 511 dec 0 dec 32 | // => PML4 => PML4 => PML4 => PDP ==>>> PDP as a result 33 | // 34 | // The correct PDP index entry is taken from the provided virtual memory address 35 | // and is added to the base virtual memory address 0xFFFFFFFFFFE00000: 36 | // 0x00001FF000 = 111111111 000000000000 37 | // PT Offset 38 | #define PDP_TABLE(VirtualAddress) ((unsigned long *)(0xFFFFFFFFFFE00000 + ((((unsigned long)(VirtualAddress)) >> 27) & 0x00001FF000))) 39 | 40 | // 0xFFFFFFFFC0000000 41 | // Sign Extension PML4 PDP PD (VA!) PT (VA!) Offset 42 | // 1111111111111111 111111111 111111111 000000000 000000000 000000000000 43 | // 511 dec 511 dec 0 dec 0 dec 44 | // => PML4 => PML4 => PDP => PD ==>>> PD as a result 45 | // 46 | // The correct PDP and PD index entries are taken from the provided virtual memory address 47 | // and are added to the base virtual memory address 0xFFFFFFFFC0000000: 48 | // 0x003FFFF000 = 111111111 111111111 000000000000 49 | // PD PT Offset 50 | #define PD_TABLE(VirtualAddress) ((unsigned long *)(0xFFFFFFFFC0000000 + ((((unsigned long)(VirtualAddress)) >> 18) & 0x003FFFF000))) 51 | 52 | // 0xFFFFFF8000000000 53 | // Sign Extension PML4 PDP (VA!) PD (VA!) PT (VA!) Offset 54 | // 1111111111111111 111111111 000000000 000000000 000000000 000000000000 55 | // 511 dec 0 dec 0 dec 0 dec 56 | // => PML4 => PDP => PD => PT ==>>> PT as a result 57 | // 58 | // The correct PDP, PD, and PT index entries are taken from the provided virtual memory address 59 | // and are added to the base virtual memory address 0xFFFFFF8000000000: 60 | // 0x7FFFFFF000 = 111111111 111111111 111111111 000000000000 61 | // PDP PD PT Offset 62 | #define PT_TABLE(VirtualAddress) ((unsigned long *)(0xFFFFFF8000000000 + ((((unsigned long)(VirtualAddress)) >> 9) & 0x7FFFFFF000))) 63 | 64 | // ============================================================================== 65 | // The following macros are used to index into the various Page Table structures 66 | // through the given virtual memory address. 67 | // ============================================================================== 68 | 69 | // Macros to index into the various Page Tables 70 | #define PML4_INDEX(VirtualAddress) ((((unsigned long)(VirtualAddress)) >> 39) & PT_ENTRIES - 1) 71 | #define PDP_INDEX(VirtualAddress) ((((unsigned long)(VirtualAddress)) >> 30) & PT_ENTRIES - 1) 72 | #define PD_INDEX(VirtualAddress) ((((unsigned long)(VirtualAddress)) >> 21) & PT_ENTRIES - 1) 73 | #define PT_INDEX(VirtualAddress) ((((unsigned long)(VirtualAddress)) >> 12) & PT_ENTRIES - 1) 74 | 75 | // Represents a 64-bit long Page Map Level 4 Entry 76 | struct PML4Entry 77 | { 78 | unsigned Present : 1; // P 79 | unsigned ReadWrite : 1; // R/W 80 | unsigned User : 1; // U/S 81 | unsigned WriteThrough : 1; // PWT 82 | unsigned CacheDisable : 1; // PCD 83 | unsigned Accessed : 1; // A 84 | unsigned Ignored1 : 1; // IGN 85 | unsigned PageSize : 1; 86 | unsigned Ignored2 : 4; 87 | unsigned long Frame : 36; 88 | unsigned short Reserved; 89 | } __attribute__ ((packed)); 90 | typedef struct PML4Entry PML4Entry; 91 | 92 | // Represents a 64-bit long Page Directory Pointer Entry 93 | struct PDPEntry 94 | { 95 | unsigned Present : 1; // P 96 | unsigned ReadWrite : 1; // R/W 97 | unsigned User : 1; // U/S 98 | unsigned WriteThrough : 1; // PWT 99 | unsigned CacheDisable : 1; // PCD 100 | unsigned Accessed : 1; // A 101 | unsigned Ignored1 : 1; // IGN 102 | unsigned PageSize : 1; 103 | unsigned Ignored2 : 4; 104 | unsigned long Frame : 36; 105 | unsigned short Reserved; 106 | } __attribute__ ((packed)); 107 | typedef struct PDPEntry PDPEntry; 108 | 109 | // Represents a 64-bit long Page Directory Entry 110 | struct PDEntry 111 | { 112 | unsigned Present : 1; // P 113 | unsigned ReadWrite : 1; // R/W 114 | unsigned User : 1; // U/S 115 | unsigned WriteThrough : 1; // PWT 116 | unsigned CacheDisable : 1; // PCD 117 | unsigned Accessed : 1; // A 118 | unsigned Ignored1 : 1; // IGN 119 | unsigned PageSize : 1; 120 | unsigned Ignored2 : 4; 121 | unsigned long Frame : 36; 122 | unsigned short Reserved; 123 | } __attribute__ ((packed)); 124 | typedef struct PDEntry PDEntry; 125 | 126 | // Represents a 64-bit long Page Table Entry 127 | struct PTEntry 128 | { 129 | unsigned Present : 1; // P 130 | unsigned ReadWrite: 1; // R/W 131 | unsigned User : 1; // U/S 132 | unsigned WriteThrough : 1; // PWT 133 | unsigned CacheDisable : 1; // PCD 134 | unsigned Accessed : 1; // A 135 | unsigned Dirty : 1; // D 136 | unsigned PageSize : 1; // PS 137 | unsigned Global : 1; // G 138 | unsigned Available : 3; // AVL 139 | unsigned long Frame : 36; 140 | unsigned short Reserved; // 16 Bits 141 | } __attribute__ ((packed)); 142 | typedef struct PTEntry PTEntry; 143 | 144 | // Defines the Page Map Level 4 Table 145 | typedef struct PageMapLevel4Table 146 | { 147 | PML4Entry Entries[512]; 148 | } PageMapLevel4Table; 149 | 150 | // Defines the Page Directory Pointer Table 151 | typedef struct PageDirectoryPointerTable 152 | { 153 | PDPEntry Entries[512]; 154 | } PageDirectoryPointerTable; 155 | 156 | // Defines the Page Directory Table 157 | typedef struct PageDirectoryTable 158 | { 159 | PDEntry Entries[512]; 160 | } PageDirectoryTable; 161 | 162 | // Defines the Page Table 163 | typedef struct PageTable 164 | { 165 | PTEntry Entries[512]; 166 | } PageTable; 167 | 168 | // Initializes the Paging Data Structures. 169 | void InitVirtualMemoryManager(int DebugOutput); 170 | 171 | // Returns the physical address of the PML4 table 172 | unsigned long GetPML4Address(); 173 | 174 | // Switches the PML4 Page Table Offset in the CR3 Register. 175 | void SwitchPageDirectory(PageMapLevel4Table *PML4); 176 | 177 | // Handles a Page Fault 178 | void HandlePageFault(unsigned long VirtualAddress); 179 | 180 | // Maps a Virtual Memory Address to a Physical Memory Address 181 | void MapVirtualAddressToPhysicalAddress(unsigned long VirtualAddress, unsigned long PhysicalAddress); 182 | 183 | // Unmaps the given Virtual Memory Address 184 | void UnmapVirtualAddress(unsigned long VirtualAddress); 185 | 186 | // Clones the PML4 table of the Kernel Mode and returns the physical address of the PML4 table clone 187 | unsigned long ClonePML4Table(); 188 | 189 | // Tests the Virtual Memory Manager. 190 | void TestVirtualMemoryManager(); 191 | 192 | // Prints out some debug information about a Page Fault. 193 | static void PageFaultDebugPrint(unsigned long PageTableIndex, char *PageTableName, unsigned long PhysicalFrame); 194 | 195 | #endif -------------------------------------------------------------------------------- /main64/kernel/multitasking/contextswitching.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | [GLOBAL Irq0_ContextSwitching] 3 | [GLOBAL GetTaskState] 4 | [EXTERN MoveToNextTask] 5 | 6 | ; ======================================================================= 7 | ; The following constants defines the offsets into the C structure "Task" 8 | ; ======================================================================= 9 | 10 | ; Instruction Pointer and Flags Registers 11 | %DEFINE TaskState_RIP 0 12 | %DEFINE TaskState_RFLAGS 8 13 | 14 | ; General Purpose Registers 15 | %DEFINE TaskState_RAX 16 16 | %DEFINE TaskState_RBX 24 17 | %DEFINE TaskState_RCX 32 18 | %DEFINE TaskState_RDX 40 19 | %DEFINE TaskState_RSI 48 20 | %DEFINE TaskState_RDI 56 21 | %DEFINE TaskState_RBP 64 22 | %DEFINE TaskState_RSP 72 23 | %DEFINE TaskState_R8 80 24 | %DEFINE TaskState_R9 88 25 | %DEFINE TaskState_R10 96 26 | %DEFINE TaskState_R11 104 27 | %DEFINE TaskState_R12 112 28 | %DEFINE TaskState_R13 120 29 | %DEFINE TaskState_R14 128 30 | %DEFINE TaskState_R15 136 31 | 32 | ; Segment Registers 33 | %DEFINE TaskState_SS 144 34 | %DEFINE TaskState_CS 152 35 | %DEFINE TaskState_DS 160 36 | %DEFINE TaskState_ES 168 37 | %DEFINE TaskState_FS 176 38 | %DEFINE TaskState_GS 184 39 | 40 | ; Control Registers 41 | %DEFINE TaskState_CR3 192 42 | 43 | ; ============================================================================ 44 | ; The following constants defines the offsets into the IRQ Stack Frame Layout 45 | ; IRQ STACK FRAME LAYOUT (based on the current RSP): 46 | ; ============================================================================ 47 | ; Return SS: +32 48 | ; Return RSP: +24 49 | ; Return RFLAGS: +16 50 | ; Return CS: +8 51 | ; Return RIP: +0 52 | ; 53 | %DEFINE StackFrame_RIP 0 54 | %DEFINE StackFrame_CS 8 55 | %DEFINE StackFrame_RFLAGS 16 56 | %DEFINE StackFrame_RSP 24 57 | %DEFINE StackFrame_SS 32 58 | 59 | ; This function is called as soon as the Timer Interrupt is raised 60 | ; 61 | ; NOTE: We don't need to disable/enable the interrupts explicitly, because the IRQ0 is an Interrupt Gate, 62 | ; where the interrupts are disabled/enabled automatically by the CPU! 63 | Irq0_ContextSwitching: 64 | ; Save RDI on the Stack, so that we can store it later in the Task structure 65 | PUSH RDI 66 | 67 | ; The first initial code execution path (entry point of KERNEL.BIN) that was started by KLDR64.BIN, 68 | ; has no Task structure assigned in register R15. 69 | ; Therefore we only save the current Task State if we have a Task structure assigned in R15. 70 | MOV RDI, R15 71 | CMP RDI, 0x0 72 | JE NoTaskStateSaveNecessary 73 | 74 | ; Save the current general purpose registers 75 | MOV [RDI + TaskState_RAX], RAX 76 | MOV [RDI + TaskState_RBX], RBX 77 | MOV [RDI + TaskState_RCX], RCX 78 | MOV [RDI + TaskState_RDX], RDX 79 | MOV [RDI + TaskState_RSI], RSI 80 | MOV [RDI + TaskState_RBP], RBP 81 | MOV [RDI + TaskState_R8], R8 82 | MOV [RDI + TaskState_R9], R9 83 | MOV [RDI + TaskState_R10], R10 84 | MOV [RDI + TaskState_R11], R11 85 | MOV [RDI + TaskState_R12], R12 86 | MOV [RDI + TaskState_R13], R13 87 | MOV [RDI + TaskState_R14], R14 88 | MOV [RDI + TaskState_R15], R15 89 | 90 | ; Save RDI 91 | POP RAX ; Pop the initial content of RDI off the Stack 92 | MOV [RDI + TaskState_RDI], RAX 93 | 94 | ; Save the Segment Registers 95 | MOV [RDI + TaskState_DS], DS 96 | MOV [RDI + TaskState_ES], ES 97 | MOV [RDI + TaskState_FS], FS 98 | MOV [RDI + TaskState_GS], GS 99 | 100 | ; Save the Control Registers 101 | MOV RAX, CR3 102 | MOV [RDI + TaskState_CR3], RAX 103 | 104 | ; IRQ STACK FRAME LAYOUT (based on the current RSP) 105 | ; ================================================== 106 | ; Return SS: +32 107 | ; Return RSP: +24 108 | ; Return RFLAGS: +16 109 | ; Return CS: +8 110 | ; Return RIP: +0 111 | 112 | ; Save the current register RIP from the Stack 113 | MOV RAX, [RSP + StackFrame_RIP] 114 | MOV [RDI + TaskState_RIP], RAX 115 | 116 | ; Save the current register CS from the Stack 117 | MOV RAX, [RSP + StackFrame_CS] 118 | MOV [RDI + TaskState_CS], RAX 119 | 120 | ; Save the current register RFLAGS from the Stack 121 | MOV RAX, [RSP + StackFrame_RFLAGS] 122 | MOV [RDI + TaskState_RFLAGS], RAX 123 | 124 | ; Save the current register RSP from the Stack 125 | MOV RAX, [RSP + StackFrame_RSP] 126 | MOV [RDI + TaskState_RSP], RAX 127 | 128 | ; Save the current register SS from the Stack 129 | MOV RAX, [RSP + StackFrame_SS] 130 | MOV [RDI + TaskState_SS], RAX 131 | 132 | JMP Continue 133 | 134 | NoTaskStateSaveNecessary: 135 | ; Pop the initial content of RDI off the Stack 136 | POP RAX 137 | 138 | Continue: 139 | ; Move to the next Task to be executed 140 | CALL MoveToNextTask 141 | 142 | ; Store the pointer to the current Task in the register RDI. 143 | ; It was returned in the register RAX from the previous function call. 144 | MOV RDI, RAX 145 | 146 | ; Restore the general purpose registers of the next Task to be executed 147 | MOV RBX, [RDI + TaskState_RBX] 148 | MOV RCX, [RDI + TaskState_RCX] 149 | MOV RDX, [RDI + TaskState_RDX] 150 | MOV RSI, [RDI + TaskState_RSI] 151 | MOV RBP, [RDI + TaskState_RBP] 152 | MOV R8, [RDI + TaskState_R8] 153 | MOV R9, [RDI + TaskState_R9] 154 | MOV R10, [RDI + TaskState_R10] 155 | MOV R11, [RDI + TaskState_R11] 156 | MOV R12, [RDI + TaskState_R12] 157 | MOV R13, [RDI + TaskState_R13] 158 | MOV R14, [RDI + TaskState_R14] 159 | MOV R15, [RDI + TaskState_R15] 160 | 161 | ; Restore the Control Registers 162 | MOV RAX, [RDI + TaskState_CR3] 163 | MOV CR3, RAX 164 | 165 | ; IRQ STACK FRAME LAYOUT (based on the current RSP) 166 | ; ================================================== 167 | ; Return SS: +32 168 | ; Return RSP: +24 169 | ; Return RFLAGS: +16 170 | ; Return CS: +8 171 | ; Return RIP: +0 172 | 173 | ; Restore the register RIP of the next Task onto the stack 174 | MOV RAX, [RDI + TaskState_RIP] 175 | MOV [RSP + StackFrame_RIP], RAX 176 | 177 | ; Restore the register CS of the next Task onto the stack 178 | MOV RAX, [RDI + TaskState_CS] 179 | MOV [RSP + StackFrame_CS], RAX 180 | 181 | ; Restore the register RFLAGS of the next Task onto the stack 182 | MOV RAX, [RDI + TaskState_RFLAGS] 183 | MOV [RSP + StackFrame_RFLAGS], RAX 184 | 185 | ; Restore the register RSP of the next Task onto the stack 186 | MOV RAX, [RDI + TaskState_RSP] 187 | MOV [RSP + StackFrame_RSP], RAX 188 | 189 | ; Restore the register SS of the next Task onto the stack 190 | MOV RAX, [RDI + TaskState_SS] 191 | MOV [RSP + StackFrame_SS], RAX 192 | 193 | ; Restore the register RAX register of the next Task 194 | MOV RAX, [RDI + TaskState_RAX] 195 | 196 | ; Restore the remaining Segment Registers 197 | MOV DS, [RDI + TaskState_DS] 198 | MOV ES, [RDI + TaskState_ES] 199 | MOV FS, [RDI + TaskState_FS] 200 | MOV GS, [RDI + TaskState_GS] 201 | 202 | ; Send the reset signal to the master PIC... 203 | PUSH RAX 204 | MOV AL, 0x20 205 | OUT 0x20, AL 206 | POP RAX 207 | 208 | ; Return from the Interrupt Handler 209 | ; Because we have patched the Stack Frame of the Interrupt Handler, we continue with the execution of 210 | ; the next Task - based on the restored register RIP on the Stack... 211 | IRETQ 212 | 213 | ; This function returns a pointer to the Task structure of the current executing Task 214 | GetTaskState: 215 | MOV RAX, R15 216 | RET -------------------------------------------------------------------------------- /main64/kernel/multitasking/gdt.asm: -------------------------------------------------------------------------------- 1 | [GLOBAL GdtFlush] 2 | 3 | ; Loads the GDT table 4 | GdtFlush: 5 | CLI 6 | 7 | ; The first function parameter is provided in the RDI register on the x64 architecture 8 | ; RDI points to the variable gdtPointer (defined in the C code) 9 | LGDT [RDI] 10 | 11 | ; Load the TSS 12 | MOV AX, 0x2B ; This is the 6th entry from the GDT with the requested RPL of 3 13 | LTR AX 14 | 15 | STI 16 | RET -------------------------------------------------------------------------------- /main64/kernel/multitasking/gdt.c: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include "../common.h" 3 | #include "../memory/heap.h" 4 | 5 | // The needed GDT and TSS structures 6 | GdtPointer gdtPointer; 7 | GdtEntry *gdtEntries = (GdtEntry *)GDT_START_OFFSET; 8 | TssEntry *tssEntry = (TssEntry *)TSS_START_OFFSET; 9 | 10 | // Installs the various need GDT entries 11 | void InitGdt() 12 | { 13 | // Initialize the GDT 14 | gdtPointer.Limit = sizeof(GdtEntry) * (GDT_ENTRIES + 1); 15 | gdtPointer.Base = (unsigned long)gdtEntries; 16 | memset(gdtEntries, 0, sizeof(GdtEntry) * (GDT_ENTRIES + 1)); 17 | 18 | // Initialize the TSS 19 | memset(tssEntry, 0, sizeof(tssEntry)); 20 | 21 | // The NULL Descriptor 22 | GdtSetGate(0, 0, 0, 0, 0); 23 | 24 | // The Code Segment Descriptor for Ring 0 25 | GdtSetGate(1, 0, 0, GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, GDT_FLAG_64_BIT); 26 | 27 | // The Data Segment Descriptor for Ring 0 28 | GdtSetGate(2, 0, 0, GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, 0); 29 | 30 | // The Code Segment Descriptor for Ring 3 31 | GdtSetGate(3, 0, 0, GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT, GDT_FLAG_64_BIT); 32 | 33 | // The Data Segment Descriptor for Ring 3 34 | GdtSetGate(4, 0, 0, GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT, 0); 35 | 36 | // The TSS Entry 37 | GdtSetGate(5, (unsigned long)tssEntry, sizeof(TssEntry), 0x89, 0x40); 38 | 39 | // Install the new GDT 40 | GdtFlush((unsigned long)&gdtPointer); 41 | } 42 | 43 | // Returns the TSS entry 44 | TssEntry *GetTss() 45 | { 46 | return tssEntry; 47 | } 48 | 49 | // Sets the GDT entry 50 | void GdtSetGate(unsigned char Num, unsigned long Base, unsigned long Limit, unsigned char Access, unsigned char Granularity) 51 | { 52 | gdtEntries[Num].BaseLow = Base & 0xFFFF; 53 | gdtEntries[Num].BaseMiddle = ((Base >> 16) & 0xFF); 54 | gdtEntries[Num].BaseHigh = ((Base >> 24) & 0xFF); 55 | gdtEntries[Num].LimitLow = Limit & 0xFFFF; 56 | gdtEntries[Num].Granularity = ((Limit >> 16) & 0x0F); 57 | gdtEntries[Num].Granularity |= (Granularity & 0xF0); 58 | gdtEntries[Num].Access = Access; 59 | } -------------------------------------------------------------------------------- /main64/kernel/multitasking/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef GDT_H 2 | #define GDT_H 3 | 4 | // Virtual address where the GDT and TSS tables are stored 5 | #define GDT_START_OFFSET 0xFFFF800000061000 6 | #define TSS_START_OFFSET 0xFFFF800000062000 7 | 8 | // The number of entries in the GDT 9 | #define GDT_ENTRIES 6 10 | 11 | // The various GDT flags 12 | #define GDT_FLAG_DATASEG 0x02 13 | #define GDT_FLAG_CODESEG 0x0a 14 | #define GDT_FLAG_TSS 0x09 15 | #define GDT_FLAG_TSS_BUSY 0x02 16 | #define GDT_FLAG_SEGMENT 0x10 17 | #define GDT_FLAG_RING0 0x00 18 | #define GDT_FLAG_RING1 0x20 19 | #define GDT_FLAG_RING2 0x40 20 | #define GDT_FLAG_RING3 0x60 21 | #define GDT_FLAG_PRESENT 0x80 22 | #define GDT_FLAG_ACCESSED 0x01 23 | #define GDT_FLAG_4K_GRAN 0x80 24 | #define GDT_FLAG_16_BIT 0x00 25 | #define GDT_FLAG_32_BIT 0x40 26 | #define GDT_FLAG_64_BIT 0x20 27 | 28 | // The various Segment Selectors for the GDT 29 | #define GDT_KERNEL_CODE_SEGMENT 0x8 30 | #define GDT_KERNEL_DATA_SEGMENT 0x10 31 | #define GDT_USER_CODE_SEGMENT 0x18 32 | #define GDT_USER_DATA_SEGMENT 0x20 33 | 34 | // The various used RPL levels 35 | #define RPL_RING0 0x0 36 | #define RPL_RING3 0x3 37 | 38 | // This structure describes a GDT entry 39 | typedef struct 40 | { 41 | unsigned short LimitLow; // 16 Bits 42 | unsigned short BaseLow; // 16 Bits 43 | unsigned char BaseMiddle; // 8 Bits 44 | unsigned char Access; // 8 Bits 45 | unsigned char Granularity; // 8 Bits 46 | unsigned char BaseHigh; // 8 Bits 47 | } __attribute__ ((packed)) GdtEntry; 48 | 49 | // This structure describes the GDT pointer 50 | typedef struct 51 | { 52 | unsigned short Limit; 53 | unsigned long Base; 54 | } __attribute__ ((packed)) GdtPointer; 55 | 56 | typedef struct 57 | { 58 | int reserved1; 59 | long rsp0; 60 | long rsp1; 61 | long rsp2; 62 | long reserved2; 63 | long ist1; 64 | long ist2; 65 | long ist3; 66 | long ist4; 67 | long ist5; 68 | long ist6; 69 | long ist7; 70 | long reserved3; 71 | int reserved4; 72 | } __attribute__ ((packed)) TssEntry; 73 | 74 | // Initializes the GDT 75 | void InitGdt(); 76 | 77 | // Returns the TSS Entry 78 | TssEntry *GetTss(); 79 | 80 | // Sets the GDT Entry 81 | void GdtSetGate(unsigned char Num, unsigned long Base, unsigned long Limit, unsigned char Access, unsigned char Granularity); 82 | 83 | // Loads the GDT table into the processor register (implemented in Assembler) 84 | extern void GdtFlush(unsigned long); 85 | 86 | #endif -------------------------------------------------------------------------------- /main64/kernel/multitasking/multitasking.h: -------------------------------------------------------------------------------- 1 | #ifndef TASK_H 2 | #define TASK_H 3 | 4 | // The various Task states 5 | #define TASK_STATUS_CREATED 0x0 6 | #define TASK_STATUS_RUNNABLE 0x1 7 | #define TASK_STATUS_RUNNING 0x2 8 | #define TASK_STATUS_WAITING 0x3 9 | 10 | #define EXECUTABLE_BASE_ADDRESS 0x0000700000000000 11 | #define EXECUTABLE_USERMODE_STACK 0x00007FFFF0000000 12 | #define EXECUTABLE_KERNELMODE_STACK 0xFFFF800001400000 13 | 14 | #define USERMODE_PROGRAMM_TO_EXECUTE 0xFFFF800000300000 15 | 16 | // Represents the state of a Task 17 | typedef struct Task 18 | { 19 | // Instruction Pointer and Flags Registers 20 | unsigned long RIP; // Offset +0 21 | unsigned long RFLAGS; // Offset +8 22 | 23 | // General Purpose Registers 24 | unsigned long RAX; // Offset +16 25 | unsigned long RBX; // Offset +24 26 | unsigned long RCX; // Offset +32 27 | unsigned long RDX; // Offset +40 28 | unsigned long RSI; // Offset +48 29 | unsigned long RDI; // Offset +56 30 | unsigned long RBP; // Offset +64 31 | unsigned long RSP; // Offset +72 32 | unsigned long R8; // Offset +80 33 | unsigned long R9; // Offset +88 34 | unsigned long R10; // Offset +96 35 | unsigned long R11; // Offset +104 36 | unsigned long R12; // Offset +112 37 | unsigned long R13; // Offset +120 38 | unsigned long R14; // Offset +128 39 | unsigned long R15; // Offset +136 40 | 41 | // Segment Registers 42 | unsigned long SS; // Offset +144 43 | unsigned long CS; // Offset +152 44 | unsigned long DS; // Offset +160 45 | unsigned long ES; // Offset +168 46 | unsigned long FS; // Offset +176 47 | unsigned long GS; // Offset +184 48 | 49 | // Control Registers 50 | unsigned long CR3; // Offset +192 51 | 52 | // The ID of the running Task 53 | unsigned long PID; 54 | 55 | // The used Kernel Mode Stack 56 | unsigned long KernelModeStack; 57 | 58 | // The used User Mode Stack 59 | unsigned long UserModeStack; 60 | 61 | // The number of context switches of the running Task 62 | unsigned long ContextSwitches; 63 | 64 | // The status of the Task: 65 | // 0: CREATED 66 | // 1: RUNNABLE 67 | // 2: RUNNING 68 | // 3: WAITING 69 | int Status; 70 | } Task; 71 | 72 | // The Context Switching routine implemented in Assembler 73 | extern void Irq0_ContextSwitching(); 74 | 75 | // The GetTaskState function implemented in Assembler 76 | extern Task *GetTaskState(); 77 | 78 | // Creates a new Kernel Task 79 | Task* CreateKernelModeTask(void *TaskCode, unsigned long PID, unsigned long KernelModeStack); 80 | 81 | // Creates a new User Mode Task 82 | Task* ExecuteUserModeProgram(unsigned char *FileName, unsigned long PID); 83 | 84 | // Loads the given program into a new User Mode Virtual Address Space 85 | static int LoadProgramIntoUserModeVirtualAddressSpace(unsigned char *FileName, unsigned long UserModePML4Table); 86 | 87 | // Creates all initial OS tasks 88 | void CreateInitialTasks(); 89 | 90 | // Moves the current Task from the head of the TaskList to the tail of the TaskList 91 | Task* MoveToNextTask(); 92 | 93 | // Terminates the Kernel Mode Task with the given PID 94 | void TerminateTask(unsigned long PID); 95 | 96 | // Refreshs the status line 97 | void RefreshStatusLine(); 98 | 99 | // Prints out the TaskList entries 100 | void PrintTaskList(); 101 | 102 | // This function continuously checks if there is a new User Mode program to be started 103 | void StartUserModeTask(); 104 | 105 | // Prints out the status as text 106 | static void PrintStatus(int Status); 107 | 108 | void Dummy1(); 109 | void Dummy2(); 110 | void Dummy3(); 111 | void Dummy4(); 112 | 113 | #endif -------------------------------------------------------------------------------- /main64/kernel/multitasking/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef SPINLOCK_H 2 | #define SPINLOCK_H 3 | 4 | // Declares a Spinlock 5 | #define DECLARE_SPINLOCK(name) volatile int name ## Locked 6 | 7 | // Acquires a Spinlock 8 | #define AcquireSpinlock(name) \ 9 | while (!__sync_bool_compare_and_swap(& name ## Locked, 0, 1)); \ 10 | __sync_synchronize(); 11 | 12 | // Releases a Spinlock 13 | #define ReleaseSpinlock(name) \ 14 | __sync_synchronize(); \ 15 | name ## Locked = 0; 16 | 17 | #endif -------------------------------------------------------------------------------- /main64/kernel/syscalls/syscall.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | [GLOBAL SysCallHandlerAsm] 3 | [EXTERN SysCallHandlerC] 4 | 5 | ; Virtual address where the SysCallRegisters structure will be stored 6 | SYSCALLREGISTERS_OFFSET EQU 0xFFFF800000064000 7 | 8 | SysCallHandlerAsm: 9 | CLI 10 | 11 | ; Save the General Purpose registers on the Stack 12 | PUSH RBX 13 | PUSH RAX 14 | PUSH RCX 15 | PUSH RDX 16 | PUSH RSI 17 | PUSH RDI 18 | PUSH RBP 19 | PUSH RSP 20 | PUSH R8 21 | PUSH R9 22 | PUSH R10 23 | PUSH R11 24 | PUSH R12 25 | PUSH R13 26 | PUSH R14 27 | PUSH R15 28 | 29 | ; Store the RDI Number 30 | MOV RAX, SYSCALLREGISTERS_OFFSET 31 | MOV [RAX], RDI 32 | 33 | ; Store the RSI register 34 | ADD RAX, 0x8 35 | MOV [RAX], RSI 36 | 37 | ; Store the RDX register 38 | ADD RAX, 0x8 39 | MOV [RAX], RDX 40 | 41 | ; Store the RCX register 42 | ADD RAX, 0x8 43 | MOV [RAX], RCX 44 | 45 | ; Store the R8 register 46 | ADD RAX, 0x8 47 | MOV [RAX], R8 48 | 49 | ; Store the R9 register 50 | ADD RAX, 0x8 51 | MOV [RAX], R9 52 | 53 | ; Call the ISR handler that is implemented in C 54 | MOV RDI, SYSCALLREGISTERS_OFFSET 55 | CALL SysCallHandlerC 56 | 57 | ; Restore the General Purpose registers from the Stack 58 | POP R15 59 | POP R14 60 | POP R13 61 | POP R12 62 | POP R11 63 | POP R10 64 | POP R9 65 | POP R8 66 | POP RSP 67 | POP RBP 68 | POP RDI 69 | POP RSI 70 | POP RDX 71 | POP RCX 72 | 73 | ; We don't restore the RAX register, because it contains the result of the SysCall (from the function call to "SysCallHandlerC"). 74 | ; So we just pop the old RAX value into RBX and then pop the old RBX value into RBX 75 | POP RBX ; Original RAX value 76 | POP RBX 77 | 78 | STI 79 | IRETQ -------------------------------------------------------------------------------- /main64/kernel/syscalls/syscall.c: -------------------------------------------------------------------------------- 1 | #include "../multitasking/multitasking.h" 2 | #include "../drivers/screen.h" 3 | #include "../drivers/keyboard.h" 4 | #include "../io/fat12.h" 5 | #include "../common.h" 6 | #include "syscall.h" 7 | 8 | // Implements the SysCall Handler 9 | // 10 | // CAUTION! 11 | // When the function "SysCallHandlerC" is executed, Interrupts are disabled (performed in the 12 | // Assembler code). 13 | // Therefore, it is *safe* to call other functions in the Kernel (like "GetTaskState"), 14 | // because a Context Switch can't happen, because of the disabled Timer Interrupt. 15 | // But we can't call functions that are causing Page Fault, because of the disabled interrupts 16 | // we can't handle Page Faults. 17 | unsigned long SysCallHandlerC(SysCallRegisters *Registers) 18 | { 19 | // The SysCall Number is stored in the register RDI 20 | int sysCallNumber = Registers->RDI; 21 | 22 | // printf 23 | if (sysCallNumber == SYSCALL_PRINTF) 24 | { 25 | printf((char *)Registers->RSI); 26 | 27 | return 1; 28 | } 29 | // GetPID 30 | else if (sysCallNumber == SYSCALL_GETPID) 31 | { 32 | Task *state = (Task *)GetTaskState(); 33 | return state->PID; 34 | } 35 | // TerminateProcess 36 | else if (sysCallNumber == SYSCALL_TERMINATE_PROCESS) 37 | { 38 | Task *state = (Task *)GetTaskState(); 39 | TerminateTask(state->PID); 40 | 41 | return 1; 42 | } 43 | // getchar 44 | else if (sysCallNumber == SYSCALL_GETCHAR) 45 | { 46 | char returnValue; 47 | 48 | // Get a pointer to the keyboard buffer 49 | char *keyboardBuffer = (char *)KEYBOARD_BUFFER; 50 | 51 | // Copy the entered character into the variable that is returned 52 | memcpy(&returnValue, keyboardBuffer, 1); 53 | 54 | // Clear the keyboard buffer 55 | keyboardBuffer[0] = 0; 56 | 57 | // Return the entered character 58 | return returnValue; 59 | } 60 | // GetCursor 61 | else if (sysCallNumber == SYSCALL_GETCURSOR) 62 | { 63 | int *Row = (int *)Registers->RSI; 64 | int *Col = (int *)Registers->RDX; 65 | GetCursorPosition(Row, Col); 66 | 67 | return 1; 68 | } 69 | // SetCursor 70 | else if (sysCallNumber == SYSCALL_SETCURSOR) 71 | { 72 | int *row = (int *)Registers->RSI; 73 | int *col = (int *)Registers->RDX; 74 | SetCursorPosition(*row, *col); 75 | 76 | return 1; 77 | } 78 | // ExecuteUserProcess 79 | else if (sysCallNumber == SYSCALL_EXECUTE) 80 | { 81 | // We can't start directly here in the SysCall handler the requested User Mode program, because interrupts are 82 | // currently disabled, and therefore we can't load the new program into memory. 83 | // Loading the program into memory would generate Page Faults that we can't handle, because of the disabled interrupts. 84 | // 85 | // Therefore, we store the User Mode program that we want to start, at the memory location "USERMODE_PROGRAMM_TO_EXECUTE". 86 | // The Kernel Mode Task "StartUserModeTask()" continuously checks this memory location if there is a new User Mode program 87 | // to be started. 88 | // If yes, the program is started, and the memory location is finally cleared. 89 | 90 | // Find the Root Directory Entry for the given program name 91 | RootDirectoryEntry *entry = FindRootDirectoryEntry((char *)Registers->RSI); 92 | 93 | if (entry != 0) 94 | { 95 | // The given program name was found, so we copy the program name to the memory locattion "USERMODE_PROGRAMM_TO_EXECUTE" 96 | char *fileName = (char *)USERMODE_PROGRAMM_TO_EXECUTE; 97 | strcpy(fileName, (char *)Registers->RSI); 98 | return 1; 99 | } 100 | else 101 | return 0; 102 | } 103 | // PrintRootDirectory 104 | else if (sysCallNumber == SYSCALL_PRINTROOTDIRECTORY) 105 | { 106 | PrintRootDirectory(); 107 | 108 | return 1; 109 | } 110 | // ClearScreen 111 | else if (sysCallNumber == SYSCALL_CLEARSCREEN) 112 | { 113 | ClearScreen(); 114 | 115 | return 1; 116 | } 117 | // DeleteFile 118 | else if (sysCallNumber == SYSCALL_DELETEFILE) 119 | { 120 | unsigned char *fileName = (unsigned char *)Registers->RSI; 121 | unsigned char *extension = (unsigned char *)Registers->RDX; 122 | 123 | return DeleteFile(fileName, extension); 124 | } 125 | // OpenFile 126 | else if(sysCallNumber == SYSCALL_OPENFILE) 127 | { 128 | unsigned char *fileName = (unsigned char *)Registers->RSI; 129 | unsigned char *extension = (unsigned char *)Registers->RDX; 130 | char *fileMode = (unsigned char *)Registers->RCX; 131 | 132 | return OpenFile(fileName, extension, fileMode); 133 | } 134 | // CloseFile 135 | else if(sysCallNumber == SYSCALL_CLOSEFILE) 136 | { 137 | unsigned long fileHandle = (unsigned long)Registers->RSI; 138 | 139 | return CloseFile(fileHandle); 140 | } 141 | // ReadFile 142 | else if(sysCallNumber == SYSCALL_READFILE) 143 | { 144 | unsigned long fileHandle = (unsigned long)Registers->RSI; 145 | unsigned char *buffer = (unsigned char *)Registers->RDX; 146 | int length = (int)Registers->RCX; 147 | 148 | return ReadFile(fileHandle, buffer, length); 149 | } 150 | // WriteFile 151 | else if (sysCallNumber == SYSCALL_WRITEFILE) 152 | { 153 | unsigned long fileHandle = (unsigned long)Registers->RSI; 154 | unsigned char *buffer = (unsigned char *)Registers->RDX; 155 | unsigned long length = (int)Registers->RCX; 156 | 157 | return WriteFile(fileHandle, buffer, length);; 158 | } 159 | // EndOfFile 160 | else if(sysCallNumber == SYSCALL_ENDOFFILE) 161 | { 162 | unsigned long fileHandle = (unsigned long)Registers->RSI; 163 | 164 | return EndOfFile(fileHandle); 165 | } 166 | // SeekFile 167 | else if (sysCallNumber == SYSCALL_SEEKFILE) 168 | { 169 | unsigned long fileHandle = (unsigned long)Registers->RSI; 170 | unsigned long fileOffset = (unsigned long)Registers->RDX; 171 | 172 | return SeekFile(fileHandle, fileOffset); 173 | } 174 | 175 | return 0; 176 | } -------------------------------------------------------------------------------- /main64/kernel/syscalls/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSCALL_H 2 | #define SYSCALL_H 3 | 4 | // Defines the various available SysCalls 5 | #define SYSCALL_PRINTF 1 6 | #define SYSCALL_GETPID 2 7 | #define SYSCALL_TERMINATE_PROCESS 3 8 | #define SYSCALL_GETCHAR 4 9 | #define SYSCALL_GETCURSOR 5 10 | #define SYSCALL_SETCURSOR 6 11 | #define SYSCALL_EXECUTE 7 12 | #define SYSCALL_PRINTROOTDIRECTORY 8 13 | #define SYSCALL_CLEARSCREEN 9 14 | #define SYSCALL_OPENFILE 10 15 | #define SYSCALL_READFILE 11 16 | #define SYSCALL_WRITEFILE 12 17 | #define SYSCALL_SEEKFILE 13 18 | #define SYSCALL_ENDOFFILE 14 19 | #define SYSCALL_CLOSEFILE 15 20 | #define SYSCALL_DELETEFILE 16 21 | 22 | typedef struct SysCallRegisters 23 | { 24 | // Parameter values 25 | unsigned long RDI; 26 | unsigned long RSI; 27 | unsigned long RDX; 28 | unsigned long RCX; 29 | unsigned long R8; 30 | unsigned long R9; 31 | } SysCallRegisters; 32 | 33 | // Implements the SysCall Handler 34 | unsigned long SysCallHandlerC(SysCallRegisters *Registers); 35 | 36 | // The SysCall Handler written in Assembler 37 | extern void SysCallHandlerAsm(); 38 | 39 | #endif -------------------------------------------------------------------------------- /main64/libc/libc.c: -------------------------------------------------------------------------------- 1 | #include "syscall.h" 2 | #include "libc.h" 3 | 4 | char tbuf[64]; 5 | char tbuf_long[64]; 6 | char bchars[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 7 | 8 | // Prints out a null-terminated string 9 | void printf(unsigned char *string) 10 | { 11 | SYSCALL1(SYSCALL_PRINTF, string); 12 | } 13 | 14 | // Returns the PID of the current executing process 15 | long GetPID() 16 | { 17 | return SYSCALL0(SYSCALL_GETPID); 18 | } 19 | 20 | // Terminates the current executing process 21 | void TerminateProcess() 22 | { 23 | SYSCALL0(SYSCALL_TERMINATE_PROCESS); 24 | while (1 == 1) {} 25 | } 26 | 27 | // Returns the entered character 28 | char getchar() 29 | { 30 | long enteredCharacter = SYSCALL0(SYSCALL_GETCHAR); 31 | 32 | return (char)enteredCharacter; 33 | } 34 | 35 | // Returns the current cursor position 36 | void GetCursorPosition(int *Row, int *Col) 37 | { 38 | SYSCALL2(SYSCALL_GETCURSOR, Row, Col); 39 | } 40 | 41 | // Sets the current cursor position 42 | void SetCursorPosition(int *Row, int *Col) 43 | { 44 | SYSCALL2(SYSCALL_SETCURSOR, Row, Col); 45 | } 46 | 47 | // Reads a string with the given size from the keyboard, and returns it 48 | void scanf(char *buffer, int buffer_size) 49 | { 50 | int processKey = 1; 51 | int i = 0; 52 | 53 | while (i < buffer_size) 54 | { 55 | char key = 0; 56 | 57 | while (key == 0) 58 | key = getchar(); 59 | 60 | processKey = 1; 61 | 62 | // When we have hit the ENTER key, we have finished entering our input data 63 | if (key == KEY_RETURN) 64 | { 65 | printf("\n"); 66 | break; 67 | } 68 | 69 | if (key == KEY_BACKSPACE) 70 | { 71 | processKey = 0; 72 | 73 | // We only process the backspace key, if we have data already in the input buffer 74 | if (i > 0) 75 | { 76 | int col; 77 | int row; 78 | 79 | // Move the cursor position one character back 80 | GetCursorPosition(&row, &col); 81 | col -= 1; 82 | SetCursorPosition(&row, &col); 83 | 84 | // Clear out the last printed key 85 | // This also moves the cursor one character forward, so we have to go back 86 | // again with the cursor in the next step 87 | printf(" "); 88 | 89 | // Move the cursor position one character back again 90 | GetCursorPosition(&row, &col); 91 | col -= 1; 92 | SetCursorPosition(&row, &col); 93 | 94 | // Delete the last entered character from the input buffer 95 | i--; 96 | } 97 | } 98 | 99 | if (processKey == 1) 100 | { 101 | // Print out the current entered key stroke 102 | // If we have pressed a non-printable key, the character is not printed out 103 | if (key != 0) 104 | { 105 | char str[2] = {key}; 106 | printf(str); 107 | } 108 | 109 | // Write the entered character into the provided buffer 110 | buffer[i] = key; 111 | i++; 112 | } 113 | } 114 | 115 | // Null-terminate the input string 116 | buffer[i] = '\0'; 117 | } 118 | 119 | // Prints out an integer value 120 | void printf_int(int i, int base) 121 | { 122 | char str[32] = ""; 123 | itoa(i, base, str); 124 | printf(str); 125 | } 126 | 127 | // Prints out a long value 128 | void printf_long(unsigned long i, int base) 129 | { 130 | char str[32] = ""; 131 | ltoa(i, base, str); 132 | printf(str); 133 | } 134 | 135 | // Converts an integer value to a string value for a specific base (base 10 => decimal, base 16 => hex) 136 | void itoa(unsigned int i, unsigned base, char *buf) 137 | { 138 | if (base > 16) return; 139 | 140 | if (i < 0) 141 | { 142 | *buf++ = '-'; 143 | i *= -1; 144 | } 145 | 146 | itoa_helper(i, base, buf); 147 | } 148 | 149 | // Converts a long value to a string value for a specific base (base 10 => decimal, base 16 => hex) 150 | void ltoa(unsigned long i, unsigned base, char *buf) 151 | { 152 | if (base > 16) return; 153 | 154 | if (i < 0) 155 | { 156 | *buf++ = '-'; 157 | i *= -1; 158 | } 159 | 160 | ltoa_helper(i, base, buf); 161 | } 162 | 163 | // Helper function for the itoa function. 164 | void itoa_helper(unsigned int i, unsigned base, char *buf) 165 | { 166 | int pos = 0; 167 | int opos = 0; 168 | int top = 0; 169 | 170 | if (i == 0 || base > 16) 171 | { 172 | buf[0] = '0'; 173 | buf[1] = '\0'; 174 | return; 175 | } 176 | 177 | while (i != 0) 178 | { 179 | tbuf[pos] = bchars[i % base]; 180 | pos++; 181 | i /= base; 182 | } 183 | 184 | top = pos--; 185 | 186 | for (opos = 0; opos < top; pos--,opos++) 187 | { 188 | buf[opos] = tbuf[pos]; 189 | } 190 | 191 | buf[opos] = 0; 192 | } 193 | 194 | // Helper function for the ltoa function. 195 | static void ltoa_helper(unsigned long i, unsigned base, char *buf) 196 | { 197 | int pos = 0; 198 | int opos = 0; 199 | int top = 0; 200 | 201 | if (i == 0 || base > 16) 202 | { 203 | buf[0] = '0'; 204 | buf[1] = '\0'; 205 | return; 206 | } 207 | 208 | while (i != 0) 209 | { 210 | tbuf[pos] = bchars[i % base]; 211 | pos++; 212 | i /= base; 213 | } 214 | 215 | top = pos--; 216 | 217 | for (opos = 0; opos < top; pos--,opos++) 218 | { 219 | buf[opos] = tbuf[pos]; 220 | } 221 | 222 | buf[opos] = 0; 223 | } 224 | 225 | // Checks if a string starts with a given prefix 226 | int StartsWith(char *string, char *prefix) 227 | { 228 | while (*prefix) 229 | { 230 | if (*prefix++ != *string++) 231 | return 0; 232 | } 233 | 234 | return 1; 235 | } 236 | 237 | // Executes the given User Mode program 238 | int ExecuteUserModeProgram(unsigned char *FileName) 239 | { 240 | return SYSCALL1(SYSCALL_EXECUTE, FileName); 241 | } 242 | 243 | // Prints out the root directory of the FAT12 partition 244 | int PrintRootDirectory() 245 | { 246 | return SYSCALL0(SYSCALL_PRINTROOTDIRECTORY); 247 | } 248 | 249 | // Clears the screen 250 | int ClearScreen() 251 | { 252 | return SYSCALL0(SYSCALL_CLEARSCREEN); 253 | } 254 | 255 | // Deletes the file in the FAT12 file system 256 | int DeleteFile(unsigned char *FileName, unsigned char *Extension) 257 | { 258 | return SYSCALL2(SYSCALL_DELETEFILE, FileName, Extension); 259 | } 260 | 261 | // Opens the requested file in the FAT12 file system 262 | unsigned long OpenFile(unsigned char *FileName, unsigned char *Extension, const char *FileMode) 263 | { 264 | return SYSCALL3(SYSCALL_OPENFILE, FileName, Extension, (void *)FileMode); 265 | } 266 | 267 | // Closes thef ile in the FAT12 file system 268 | int CloseFile(unsigned long FileHandle) 269 | { 270 | return SYSCALL1(SYSCALL_CLOSEFILE, (void *)FileHandle); 271 | } 272 | 273 | // Reads the requested data from a file into the provided buffer 274 | unsigned long ReadFile(unsigned long FileHandle, unsigned char *Buffer, unsigned long Length) 275 | { 276 | return SYSCALL3(SYSCALL_READFILE, (void *)FileHandle, Buffer, (void *)Length); 277 | } 278 | 279 | // Writes the requested data from the provided buffer into a file 280 | unsigned long WriteFile(unsigned long FileHandle, unsigned char *Buffer, unsigned long Length) 281 | { 282 | return SYSCALL3(SYSCALL_WRITEFILE, (void *)FileHandle, Buffer, (void *)Length); 283 | } 284 | 285 | // Seeks to the specific position in the file 286 | int SeekFile(unsigned long FileHandle, unsigned long NewFileOffset) 287 | { 288 | return SYSCALL2(SYSCALL_SEEKFILE, (void *)FileHandle, (void *)NewFileOffset); 289 | } 290 | 291 | // Returns a flag if the file offset within the FileDescriptor has reached the end of file 292 | int EndOfFile(unsigned long FileHandle) 293 | { 294 | return SYSCALL1(SYSCALL_ENDOFFILE, (void *)FileHandle); 295 | } -------------------------------------------------------------------------------- /main64/libc/libc.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBC_H 2 | #define LIBC_H 3 | 4 | #define KEY_RETURN '\r' 5 | #define KEY_BACKSPACE '\b' 6 | 7 | // Prints out a null-terminated string 8 | void printf(unsigned char *string); 9 | 10 | // Returns the PID of the current executing process 11 | long GetPID(); 12 | 13 | // Terminates the current executing process 14 | void TerminateProcess(); 15 | 16 | // Returns the entered character 17 | char getchar(); 18 | 19 | // Reads a string with the given size from the keyboard, and returns it 20 | void scanf(char *buffer, int buffer_size); 21 | 22 | // Returns the current cursor position 23 | void GetCursorPosition(int *Row, int *Col); 24 | 25 | // Sets the current cursor position 26 | void SetCursorPosition(int *Row, int *Col); 27 | 28 | // Executes the given User Mode program 29 | int ExecuteUserModeProgram(unsigned char *FileName); 30 | 31 | // Prints out the root directory of the FAT12 partition 32 | int PrintRootDirectory(); 33 | 34 | // Clears the screen 35 | int ClearScreen(); 36 | 37 | // Deletes the file in the FAT12 file system 38 | int DeleteFile(unsigned char *FileName, unsigned char *Extension); 39 | 40 | // Opens the requested file in the FAT12 file system 41 | unsigned long OpenFile(unsigned char *FileName, unsigned char *Extension, const char *FileMode); 42 | 43 | // Closes thef ile in the FAT12 file system 44 | int CloseFile(unsigned long FileHandle); 45 | 46 | // Reads the requested data from a file into the provided buffer 47 | unsigned long ReadFile(unsigned long FileHandle, unsigned char *Buffer, unsigned long Length); 48 | 49 | // Writes the requested data from the provided buffer into a file 50 | unsigned long WriteFile(unsigned long FileHandle, unsigned char *Buffer, unsigned long Length); 51 | 52 | // Seeks to the specific position in the file 53 | int SeekFile(unsigned long FileHandle, unsigned long NewFileOffset); 54 | 55 | // Returns a flag if the file offset within the FileDescriptor has reached the end of file 56 | int EndOfFile(unsigned long FileHandle); 57 | 58 | // Prints out an integer value 59 | void printf_int(int i, int base); 60 | 61 | // Prints out a long value 62 | void printf_long(unsigned long i, int base); 63 | 64 | // Converts an integer value to a string value for a specific base (base 10 => decimal, base 16 => hex) 65 | void itoa(unsigned int i, unsigned base, char *buf); 66 | 67 | // Converts a long value to a string value for a specific base (base 10 => decimal, base 16 => hex) 68 | void ltoa(unsigned long i, unsigned base, char *buf); 69 | 70 | // Helper function for the itoa function. 71 | static void itoa_helper(unsigned int i, unsigned base, char *buf); 72 | 73 | // Helper function for the ltoa function. 74 | static void ltoa_helper(unsigned long i, unsigned base, char *buf); 75 | 76 | // Checks if a string starts with a given prefix 77 | int StartsWith(char *string, char *prefix); 78 | 79 | #endif -------------------------------------------------------------------------------- /main64/libc/syscall.asm: -------------------------------------------------------------------------------- 1 | [BITS 64] 2 | [GLOBAL SYSCALLASM0] 3 | [GLOBAL SYSCALLASM1] 4 | [GLOBAL SYSCALLASM2] 5 | [GLOBAL SYSCALLASM3] 6 | 7 | ; Raises a SysCall 8 | SYSCALLASM0: 9 | INT 0x80 10 | RET 11 | 12 | ; Raises a SysCall 13 | SYSCALLASM1: 14 | INT 0x80 15 | RET 16 | 17 | ; Raises a SysCall 18 | SYSCALLASM2: 19 | INT 0x80 20 | RET 21 | 22 | ; Raises a SysCall 23 | SYSCALLASM3: 24 | INT 0x80 25 | RET -------------------------------------------------------------------------------- /main64/libc/syscall.c: -------------------------------------------------------------------------------- 1 | #include "syscall.h" 2 | 3 | // Raises a SysCall with no parameters 4 | long SYSCALL0(int SysCallNumber) 5 | { 6 | return SYSCALLASM0(SysCallNumber); 7 | } 8 | 9 | // Raises a SysCall with 1 parameter 10 | long SYSCALL1(int SysCallNumber, void *Parameter1) 11 | { 12 | return SYSCALLASM1(SysCallNumber, Parameter1); 13 | } 14 | 15 | // Raises a Syscall with 2 parameters 16 | long SYSCALL2(int SysCallNumber, void *Parameter1, void *Parameter2) 17 | { 18 | return SYSCALLASM2(SysCallNumber, Parameter1, Parameter2); 19 | } 20 | 21 | // Raises a Syscall with 3 parameters 22 | long SYSCALL3(int SysCallNumber, void *Parameter1, void *Parameter2, void *Parameter3) 23 | { 24 | return SYSCALLASM3(SysCallNumber, Parameter1, Parameter2, Parameter3); 25 | } -------------------------------------------------------------------------------- /main64/libc/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSCALL_H 2 | #define SYSCALL_H 3 | 4 | // Defines the various available SysCalls 5 | #define SYSCALL_PRINTF 1 6 | #define SYSCALL_GETPID 2 7 | #define SYSCALL_TERMINATE_PROCESS 3 8 | #define SYSCALL_GETCHAR 4 9 | #define SYSCALL_GETCURSOR 5 10 | #define SYSCALL_SETCURSOR 6 11 | #define SYSCALL_EXECUTE 7 12 | #define SYSCALL_PRINTROOTDIRECTORY 8 13 | #define SYSCALL_CLEARSCREEN 9 14 | #define SYSCALL_OPENFILE 10 15 | #define SYSCALL_READFILE 11 16 | #define SYSCALL_WRITEFILE 12 17 | #define SYSCALL_SEEKFILE 13 18 | #define SYSCALL_ENDOFFILE 14 19 | #define SYSCALL_CLOSEFILE 15 20 | #define SYSCALL_DELETEFILE 16 21 | 22 | // Raises a SysCall with no parameters 23 | long SYSCALL0(int SysCallNumber); 24 | extern long SYSCALLASM0(); 25 | 26 | // Raises a SysCall with 1 parameter 27 | long SYSCALL1(int SysCallNumber, void *Parameter1); 28 | extern long SYSCALLASM1(); 29 | 30 | // Raises a Syscall with 2 parameters 31 | long SYSCALL2(int SysCallNumber, void *Parameter1, void *Parameter2); 32 | extern long SYSCALLASM2(); 33 | 34 | // Raises a Syscall with 3 parameters 35 | long SYSCALL3(int SysCallNumber, void *Parameter1, void *Parameter2, void *Parameter3); 36 | extern long SYSCALLASM3(); 37 | 38 | #endif -------------------------------------------------------------------------------- /main64/programs/program1/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(ProgramMain) 2 | 3 | SECTIONS 4 | { 5 | . = 0x0000700000000000; 6 | .text : AT(ADDR(.text)) 7 | { 8 | *(.text .text.*) 9 | *(.rodata .rodata.*) 10 | . = ALIGN(4K); 11 | } 12 | 13 | .data : AT(ADDR(.data)) 14 | { 15 | *(.data .data.*) 16 | } 17 | 18 | .bss : AT(ADDR(.bss)) 19 | { 20 | *(.bss .bss.*) 21 | } 22 | } -------------------------------------------------------------------------------- /main64/programs/program1/makefile: -------------------------------------------------------------------------------- 1 | # Automatically generate lists of sources using wildcards. 2 | C_SOURCES = $(wildcard *.c ../../libc/*.c) 3 | HEADERS = $(wildcard *.h ../../libc/*.h) 4 | 5 | # Convert the *.c filenames to *.o to give a list of object files to build 6 | OBJ = ${C_SOURCES:.c=.o} 7 | 8 | # Links the C program 9 | prog1.bin: program.o ../../libc/syscall_asm.o ${OBJ} 10 | x86_64-elf-ld -o $@ -Tlink.ld $^ --oformat binary -z max-page-size=0x1000 -Map prog1.map 11 | x86_64-elf-objdump -M intel -S --disassemble program.o > program.generated 12 | 13 | # Compiles the C program 14 | %.o : %.c ${HEADERS} 15 | x86_64-elf-gcc -ffreestanding -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -c $< -o $@ 16 | 17 | # Builds the SYSCALL functionality written in Assembler 18 | ../../libc/syscall_asm.o : ../../libc/syscall.asm 19 | nasm -felf64 ../../libc/syscall.asm -o ../../libc/syscall_asm.o 20 | 21 | # Clean up 22 | clean: 23 | rm -f *.bin *.o *.generated ../../libc/*.o common/*.o ../../libc/*.generated -------------------------------------------------------------------------------- /main64/programs/program1/program.c: -------------------------------------------------------------------------------- 1 | #include "../../libc/syscall.h" 2 | #include "../../libc/libc.h" 3 | #include "program.h" 4 | 5 | // The main entry point for the User Mode program 6 | void ProgramMain() 7 | { 8 | // This function call will trigger a GP fault, because the 9 | // code runs in Ring 3 (User Mode) 10 | // outb(0x3D4, 14); 11 | 12 | long pid = GetPID(); 13 | 14 | char input[100] = ""; 15 | 16 | printf("Please enter your name: "); 17 | scanf(input, 98); 18 | 19 | printf("Your name is "); 20 | printf(input); 21 | printf("\n"); 22 | 23 | TerminateProcess(); 24 | 25 | /* while (1 == 1) 26 | { 27 | printf("Hello World from User Mode Program #1 with PID "); 28 | printf_long(pid, 10); 29 | printf("\n"); 30 | } */ 31 | } 32 | 33 | // The x64 out assembly instructions are only allowed in Ring 0 code. 34 | // Therefore, this instruction will cause a GP fault, because the code 35 | // runs in Ring 3 (User Mode) 36 | void outb(unsigned short Port, unsigned char Value) 37 | { 38 | asm volatile ("outb %1, %0" : : "dN" (Port), "a" (Value)); 39 | } -------------------------------------------------------------------------------- /main64/programs/program1/program.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAM_H 2 | #define PROGRAM_H 3 | 4 | // The main entry point for the User Mode program. 5 | void ProgramMain(); 6 | 7 | // This function triggers a GP fault, because the out instruction is not allowed in Ring 3 codee. 8 | void outb(unsigned short Port, unsigned char Value); 9 | 10 | #endif -------------------------------------------------------------------------------- /main64/programs/program2/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(main) 2 | 3 | SECTIONS 4 | { 5 | . = 0x0000700000000000; 6 | .text : AT(ADDR(.text)) 7 | { 8 | *(.text .text.*) 9 | *(.rodata .rodata.*) 10 | . = ALIGN(4K); 11 | } 12 | 13 | .data : AT(ADDR(.data)) 14 | { 15 | *(.data .data.*) 16 | } 17 | 18 | .bss : AT(ADDR(.bss)) 19 | { 20 | *(.bss .bss.*) 21 | } 22 | } -------------------------------------------------------------------------------- /main64/programs/program2/makefile: -------------------------------------------------------------------------------- 1 | # Automatically generate lists of sources using wildcards. 2 | C_SOURCES = $(wildcard *.c ../../libc/*.c) 3 | HEADERS = $(wildcard *.h ../../libc/*.h) 4 | 5 | # Convert the *.c filenames to *.o to give a list of object files to build 6 | OBJ = ${C_SOURCES:.c=.o} 7 | 8 | # Links the C program 9 | prog2.bin: program.o ../../libc/syscall_asm.o ${OBJ} 10 | x86_64-elf-ld -o $@ -Tlink.ld $^ --oformat binary -z max-page-size=0x1000 -Map prog2.map 11 | x86_64-elf-objdump -M intel -S --disassemble program.o > program.generated 12 | 13 | # Compiles the C program 14 | %.o : %.c ${HEADERS} 15 | x86_64-elf-gcc -ffreestanding -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -c $< -o $@ 16 | 17 | # Builds the SYSCALL functionality written in Assembler 18 | ../../libc/syscall_asm.o : ../../libc/syscall.asm 19 | nasm -felf64 ../../libc/syscall.asm -o ../../libc/syscall_asm.o 20 | 21 | # Clean up 22 | clean: 23 | rm -f *.bin *.o *.generated ../../libc/*.o common/*.o ../../libc/*.generated -------------------------------------------------------------------------------- /main64/programs/program2/program.c: -------------------------------------------------------------------------------- 1 | #include "../../libc/syscall.h" 2 | #include "../../libc/libc.h" 3 | #include "program.h" 4 | 5 | // The main entry point for the User Mode program 6 | void ProgramMain() 7 | { 8 | // This function call will trigger a GP fault, because the 9 | // code runs in Ring 3 (User Mode) 10 | // outb(0x3D4, 14); 11 | 12 | for (int i = 0; i < 100; i++) 13 | { 14 | printf("Hello World from User Mode Program #2...\n"); 15 | } 16 | 17 | // Terminate the current running process 18 | TerminateProcess(); 19 | } 20 | 21 | // The x64 out assembly instructions are only allowed in Ring 0 code. 22 | // Therefore, this instruction will cause a GP fault, because the code 23 | // runs in Ring 3 (User Mode) 24 | void outb(unsigned short Port, unsigned char Value) 25 | { 26 | asm volatile ("outb %1, %0" : : "dN" (Port), "a" (Value)); 27 | } -------------------------------------------------------------------------------- /main64/programs/program2/program.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAM_H 2 | #define PROGRAM_H 3 | 4 | // The main entry point for the User Mode program. 5 | void ProgramMain(); 6 | 7 | // This function triggers a GP fault, because the out instruction is not allowed in Ring 3 codee. 8 | void outb(unsigned short Port, unsigned char Value); 9 | 10 | #endif -------------------------------------------------------------------------------- /main64/programs/shell/link.ld: -------------------------------------------------------------------------------- 1 | ENTRY(ShellMain) 2 | 3 | SECTIONS 4 | { 5 | . = 0x0000700000000000; 6 | .text : AT(ADDR(.text)) 7 | { 8 | *(.text .text.*) 9 | *(.rodata .rodata.*) 10 | . = ALIGN(4K); 11 | } 12 | 13 | .data : AT(ADDR(.data)) 14 | { 15 | *(.data .data.*) 16 | } 17 | 18 | .bss : AT(ADDR(.bss)) 19 | { 20 | *(.bss .bss.*) 21 | } 22 | } -------------------------------------------------------------------------------- /main64/programs/shell/makefile: -------------------------------------------------------------------------------- 1 | # Automatically generate lists of sources using wildcards. 2 | C_SOURCES = $(wildcard *.c ../../libc/*.c) 3 | HEADERS = $(wildcard *.h ../../libc/*.h) 4 | 5 | # Convert the *.c filenames to *.o to give a list of object files to build 6 | OBJ = ${C_SOURCES:.c=.o} 7 | 8 | # Links the C program 9 | shell.bin: shell.o ../../libc/syscall_asm.o ${OBJ} 10 | x86_64-elf-ld -o $@ -Tlink.ld $^ --oformat binary -z max-page-size=0x1000 -Map shell.map 11 | x86_64-elf-objdump -M intel -S --disassemble shell.o > shell.generated 12 | 13 | # Compiles the C program 14 | %.o : %.c ${HEADERS} 15 | x86_64-elf-gcc -ffreestanding -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -c $< -o $@ 16 | 17 | # Builds the SYSCALL functionality written in Assembler 18 | ../../libc/syscall_asm.o : ../../libc/syscall.asm 19 | nasm -felf64 ../../libc/syscall.asm -o ../../libc/syscall_asm.o 20 | 21 | # Clean up 22 | clean: 23 | rm -f *.bin *.o *.generated ../../libc/*.o common/*.o ../../libc/*.generated -------------------------------------------------------------------------------- /main64/programs/shell/shell.c: -------------------------------------------------------------------------------- 1 | #include "../../libc/syscall.h" 2 | #include "../../libc/libc.h" 3 | #include "shell.h" 4 | 5 | // The available Shell commands 6 | char *commands[] = 7 | { 8 | "cls", 9 | "dir", 10 | "mkfile", 11 | "type", 12 | "del", 13 | "open", 14 | "copy" 15 | }; 16 | 17 | int (*command_functions[]) (char *param) = 18 | { 19 | &shell_cls, 20 | &shell_dir, 21 | &shell_mkfile, 22 | &shell_type, 23 | &shell_del, 24 | &shell_open, 25 | &shell_copy 26 | }; 27 | 28 | // The main entry point for the User Mode program 29 | void ShellMain() 30 | { 31 | int i; 32 | 33 | while (1 == 1) 34 | { 35 | char input[100] = ""; 36 | int commandFound = 0; 37 | printf("C:\\>"); 38 | scanf(input, 98); 39 | 40 | for (i = 0; i < COMMAND_COUNT; i++) 41 | { 42 | // Execute the specified command 43 | if (StartsWith(input, commands[i]) == 1) 44 | { 45 | (*command_functions[i])((char *)&input); 46 | commandFound = 1; 47 | } 48 | } 49 | 50 | if (commandFound == 0) 51 | { 52 | // Execute the requested User Mode program... 53 | if (ExecuteUserModeProgram(input) == 0) 54 | { 55 | printf("'"); 56 | printf(input); 57 | printf("' is not recognized as an internal or external command,\n"); 58 | printf("operable program or batch file.\n\n"); 59 | } 60 | } 61 | } 62 | } 63 | 64 | // Prints out the Root Directory of the FAT12 partition 65 | int shell_dir(char *param) 66 | { 67 | PrintRootDirectory(); 68 | 69 | return 1; 70 | } 71 | 72 | // Clears the screen 73 | int shell_cls(char *param) 74 | { 75 | ClearScreen(); 76 | 77 | return 1; 78 | } 79 | 80 | // Creates a new file 81 | int shell_mkfile(char *param) 82 | { 83 | char fileName[10] = ""; 84 | char extension[5] = ""; 85 | char content[512] = ""; 86 | 87 | printf("Please enter the name of the new file: "); 88 | scanf(fileName, 8); 89 | printf("Please enter the extension of the new file: "); 90 | scanf(extension, 3); 91 | printf("Please enter the inital content of the new file: "); 92 | scanf(content, 510); 93 | 94 | unsigned long fileHandle = OpenFile(fileName, extension, "w"); 95 | WriteFile(fileHandle, content, sizeof(content)); 96 | CloseFile(fileHandle); 97 | 98 | ClearScreen(); 99 | printf("The file was created successfully.\n"); 100 | } 101 | 102 | // Prints out an existing file 103 | int shell_type(char *param) 104 | { 105 | char fileName[10] = ""; 106 | char extension[5] = ""; 107 | 108 | printf("Please enter the name of the file to be printed out: "); 109 | scanf(fileName, 8); 110 | printf("Please enter the extension of the file to be printed out: "); 111 | scanf(extension, 3); 112 | 113 | unsigned char buffer[510] = ""; 114 | unsigned long fileHandle = OpenFile(fileName, extension, "r"); 115 | 116 | while (!EndOfFile(fileHandle)) 117 | { 118 | ReadFile(fileHandle, (unsigned char *)&buffer, 500); 119 | printf((unsigned char *)&buffer); 120 | } 121 | 122 | printf("\n"); 123 | 124 | CloseFile(fileHandle); 125 | } 126 | 127 | // Deletes an existing file 128 | int shell_del(char *param) 129 | { 130 | char fileName[10] = ""; 131 | char extension[5] = ""; 132 | 133 | printf("Please enter the name of the file to be deleted: "); 134 | scanf(fileName, 8); 135 | printf("Please enter the extension of the file to be deleted: "); 136 | scanf(extension, 3); 137 | 138 | DeleteFile(fileName, extension); 139 | printf("The file was deleted successfully.\n"); 140 | } 141 | 142 | int shell_open(char *param) 143 | { 144 | unsigned long fileHandle1 = OpenFile("PROG1 ", "BIN", "r"); 145 | unsigned long fileHandle2 = OpenFile("TEST ", "BIN", "r"); 146 | 147 | printf_long(fileHandle1, 10); 148 | printf("\n"); 149 | printf_long(fileHandle2, 10); 150 | printf("\n"); 151 | 152 | if (fileHandle1 == 0) 153 | printf("PROG1.BIN was not found.\n"); 154 | 155 | if (fileHandle2 == 0) 156 | printf("TEST.BIN was not found.\n"); 157 | 158 | CloseFile(fileHandle1); 159 | CloseFile(fileHandle2); 160 | } 161 | 162 | int shell_copy(char *param) 163 | { 164 | unsigned char buffer[512] = ""; 165 | 166 | // Open both files 167 | unsigned long fileHandleSource = OpenFile("BIGFILE ", "TXT", "r"); 168 | unsigned long fileHandleTarget = OpenFile("TARGET ", "TXT", "w"); 169 | 170 | // Check if the source file was opened 171 | if (fileHandleSource == 0) 172 | printf("The source file could not be opened.\n"); 173 | 174 | // Check if the target file was opened 175 | if (fileHandleSource == 0) 176 | printf("The target file could not be opened or created.\n"); 177 | 178 | if ((fileHandleSource != 0) && (fileHandleTarget != 0)) 179 | { 180 | // Copy the source file to the target file 181 | while (!EndOfFile(fileHandleSource)) 182 | { 183 | ReadFile(fileHandleSource, (unsigned char *)&buffer, 512); 184 | WriteFile(fileHandleTarget, (unsigned char *)&buffer, 512); 185 | } 186 | 187 | // Close both file handles 188 | CloseFile(fileHandleSource); 189 | CloseFile(fileHandleTarget); 190 | 191 | printf("File copied.\n"); 192 | } 193 | } -------------------------------------------------------------------------------- /main64/programs/shell/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAM_H 2 | #define PROGRAM_H 3 | 4 | // The number of available commands 5 | #define COMMAND_COUNT 7 6 | 7 | // The main entry point for the User Mode program. 8 | void ShellMain(); 9 | 10 | int shell_cls(char *param); 11 | int shell_dir(char *param); 12 | int shell_mkfile(char *param); 13 | int shell_type(char *param); 14 | int shell_del(char *param); 15 | int shell_open(char *param); 16 | int shell_copy(char *param); 17 | 18 | #endif --------------------------------------------------------------------------------