Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d89a1c4071 | ||
|
|
becfc2bc3b | ||
|
|
9d665c9648 | ||
|
|
6f3c23e088 | ||
|
|
ef2de556e3 | ||
|
|
40561a6537 | ||
|
|
8093880eaa | ||
|
|
64ccec0866 | ||
|
|
bf0228d3ac | ||
|
|
5e4e6d2db8 | ||
|
|
fa879acd8a | ||
|
|
e14e5db15a | ||
|
|
d90682c40e | ||
|
|
a9a4b89c85 | ||
|
|
841e72b431 | ||
|
|
2fa918bc87 | ||
|
|
df7187ca75 | ||
|
|
8826a7d873 | ||
|
|
b0668b1fd7 | ||
|
|
cacc042a5c | ||
|
|
247558669e | ||
|
|
f55723c227 | ||
|
|
acbcc54e51 | ||
|
|
d2034cd68b | ||
|
|
b59af22897 | ||
|
|
4d05e0d620 | ||
|
|
3b39a0a1f4 | ||
|
|
f1f45fbeb6 | ||
|
|
6f5c05e0d9 | ||
|
|
a4b036dfbd | ||
|
|
a316367236 | ||
|
|
93f5feff85 | ||
|
|
7c80cc8af9 | ||
|
|
88debf5085 | ||
|
|
449873f55d | ||
|
|
adcfdc8231 | ||
|
|
deafe2439b | ||
|
|
b1e4ef8ad2 | ||
|
|
cde6bb4522 | ||
|
|
9992f84fdb | ||
|
|
8e51ab357e | ||
|
|
942b4fa88e | ||
|
|
2893e75ad1 | ||
|
|
0646536f35 | ||
|
|
75d120efcd | ||
|
|
d10e00835c | ||
|
|
fbd4fa6089 | ||
|
|
a915ac15a1 | ||
|
|
a03bb42790 | ||
|
|
0146613ce7 | ||
|
|
b3ee5f5dc9 | ||
|
|
f4f7a37554 | ||
|
|
7089ddd052 | ||
|
|
a029218acd | ||
|
|
6d0c9ac62b | ||
|
|
f1a9f84f24 | ||
|
|
f8eb658c33 | ||
|
|
52a92a5358 | ||
|
|
98d3d346c2 | ||
|
|
1ebed970c8 | ||
|
|
6ce5264b43 | ||
|
|
a2a7ab52a1 | ||
|
|
ca001598fc | ||
|
|
2f562758ad | ||
|
|
cd705589de | ||
|
|
7e551dbfae | ||
|
|
7b65e4ed01 | ||
|
|
ef88100c1f | ||
|
|
6e162fc365 | ||
|
|
e17b428bcc | ||
|
|
8ad4efb3d0 | ||
|
|
3612f223b6 | ||
|
|
5ca49cefd0 | ||
|
|
00b131fa72 | ||
|
|
51024e1d06 | ||
|
|
c47e29f9ed | ||
|
|
e5d3b460b3 | ||
|
|
f3b30bbb9a | ||
|
|
3524fdc760 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,8 +1,7 @@
|
|||||||
*.o
|
*.o
|
||||||
bochslog.txt
|
|
||||||
build/
|
build/
|
||||||
kernel.elf
|
kernel.elf
|
||||||
os.iso
|
|
||||||
blankos.iso
|
blankos.iso
|
||||||
real/
|
iso/
|
||||||
i386-elf-7.5.0-Linux-x86_64/
|
i386-elf-7.5.0-Linux-x86_64/
|
||||||
|
i386-elf-7.5.0-Linux-x86_64.tar.xz
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
# Blank OS Developer's Manual
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
### System description
|
|
||||||
|
|
||||||
Blank OS runs on a monolithic kernel booted by a 3rd party bootloader; GRUB (whose executable is named `stage2_eltorito`). The kernel is compiled in ELF format. The target processor architecture is 32-bit x86. Blank OS is BIOS-independent which means it does not use Real mode BIOS functions as its routines. It rather uses in and out port communication to communicate with hardware directly (such as the keyboard) and it uses specific memory locations (for example the framebuffer to manage the screen in text mode).
|
|
||||||
|
|
||||||
### Code structure
|
|
||||||
|
|
||||||
The source code is available in folder `src`. You will find subfolders corresponding to appropriate system parts, such as the kernel, the C library (including drivers) and programs.
|
|
||||||
|
|
||||||
## Making programs for the OS
|
|
||||||
|
|
||||||
### Programming
|
|
||||||
|
|
||||||
Basically you can use the kernel C library functions available in `src/libc/` and make programs out of those functions. Then you can set up the shell for your program to be launchable.
|
|
||||||
|
|
||||||
More on that soon.
|
|
||||||
|
|
||||||
### Compiling and linking
|
|
||||||
|
|
||||||
The linking process should be taken care by the appropriate Linker script `link.ld` and the Makefile instructions and targets.
|
|
||||||
98
README.md
98
README.md
@@ -1,94 +1,50 @@
|
|||||||

|

|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> The project is currently paused, after months of work around the subject. I've had enough for now, and I'll surely come back in some time to implement the more advanced stuff I had planned. For now, enjoy the latest alpha version.
|
||||||
|
> This is a hobbyist operating system, and it comes without any warranty whatsoever! See the license for more info. Feedback and contributions are highly appreciated.
|
||||||
|
|
||||||
# BlankOS
|
# BlankOS
|
||||||
|
|
||||||
Rewritten monolithic version of Blank OS for the x86 processor architecture. The OS relies on an old, legacy version of GRUB as the bootloader (eltorito). This *should* be GRUB 2 compatible. Emulation was tested on Bochs and QEMU using Arch Linux 6.9.7-arch1-1, and on real hardware too.
|
Rewritten megalithic, ring 0, lower-half, singletasking kernel for the x86 processor architecture (using 32-bit protected mode), with GRUB 2 as bootloader. Emulation was tested on QEMU using Arch Linux 6.9.7-arch1-1, and on real hardware (UEFI and BIOS).
|
||||||
The long-term goal of this OS is to be capable of running user programs and having its own complete kernel C library so that users can write their own C programs and expand the system!
|
The long-term goal of this OS is to be capable of running user programs and having its own complete kernel C library so that users can write their own C programs and expand the system!
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Serial port driver (output & debug)
|
|
||||||
- Framebuffer driver (output)
|
|
||||||
- PS/2 Keyboard and PIC driver (input)
|
|
||||||
- PIT (system clock/timer) driver
|
|
||||||
- Working IDT, GDT, ISRs, and IRQs
|
|
||||||
- Kernel panicking (exception handling)
|
|
||||||
- A kernel-space shell
|
|
||||||
- Cool color output!!
|
|
||||||
- Some small working kernel-space programs!!
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Download the latest BlankOS ISO image from the "Releases" tab, and emulate it directly using the QEMU emulator:
|
Download the latest BlankOS disk image from the "Releases" tab, and start it using the QEMU emulator:
|
||||||
|
|
||||||
```
|
```
|
||||||
qemu-system-i386 blankOS-i386-0.3.45.iso
|
qemu-system-i386 blankOS-i386-0.3.55.iso
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, burn the image on a USB stick and use it on a machine (see section "Real Hardware").
|
> [!NOTE]
|
||||||
|
> Know that the latest release is not always up-to-date with the source code. To get the most up-to-date version, instead build from source as shown below.
|
||||||
|
|
||||||
## Building from source
|
## Building from source
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
For Debian-based distros:
|
|
||||||
```
|
|
||||||
sudo apt install gcc nasm make bochs
|
|
||||||
```
|
|
||||||
|
|
||||||
Then change `display-library` to `sdl2` in the `bochsrc.txt` file.
|
|
||||||
|
|
||||||
For Arch-based distros:
|
|
||||||
```
|
|
||||||
sudo pacman -S nasm gcc make
|
|
||||||
git clone https://aur.archlinux.org/bochs.git
|
|
||||||
```
|
|
||||||
|
|
||||||
Then follow [these](https://bbs.archlinux.org/viewtopic.php?id=178479) instructions to compile Bochs with X support. Alternatively you can use Bochs with SDL but you'll have to change the `bochsrc.txt` file accordingly.
|
|
||||||
|
|
||||||
### Cross Compiler
|
|
||||||
|
|
||||||
A cross-compiler is needed to build the system. More info on why [here](https://wiki.osdev.org/GCC_Cross-Compiler). In order for the build to work, you will need to download the i386-elf toolchain from [here](https://newos.org/toolchains/i386-elf-7.5.0-Linux-x86_64.tar.xz) and extract the root folder into the BlankOS root folder, or build it by youself if you're not lazy like me.
|
|
||||||
|
|
||||||
Why didn't I use one sooner? Can't tell. Maybe I was too lazy. This is actually problematic because I wasn't able to use some libraries and I had to put in a bunch of weird compilation flags. It's better like this.
|
|
||||||
|
|
||||||
To clone and build, do:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/xamidev/blankos
|
git clone https://github.com/xamidev/blankos
|
||||||
|
make toolchain
|
||||||
make
|
make
|
||||||
make run
|
make run
|
||||||
```
|
```
|
||||||
|
|
||||||
This will start a new Bochs debugger instance. To proceed with the kernel execution, you will have to type `c` in the shell spawning Bochs. Serial output will be saved under the `com1.out` file, this way you can debug the kernel by viewing its log messages. To quit, type `q`.
|
The `toolchain` target will download the appropriate cross-compiling tools, and the `run` target will make a disk image for emulation or real hardware testing. *Some operations require root access. Always audit the code yourself before running anything as root!*
|
||||||
You can try out QEMU too.
|
|
||||||
|
|
||||||
## Running on real hardware
|
## Running on real hardware
|
||||||
|
|
||||||
To run the OS on real hardware, you'll first need to have a BIOS-compatible computer. Some of the new laptops with graphical "BIOSes" only support UEFI now. So make sure to get a computer that can boot into BIOS mode, **not UEFI mode**. Then, switch the boot mode to "Legacy" in your BIOS utility.
|
The OS is now both UEFI and BIOS compatible! Burn your image file onto a USB stick:
|
||||||
|
|
||||||
Then, use the Makefile target `real` to build a "real"-capable ISO disk image. The image will have GRUB2 installed on it, using the `grub-mkrescue` utility (make sure to install it before) which is dependent on `xorriso` (install it too).
|
|
||||||
|
|
||||||
Once the ISO file is generated, you can write it on a disk using this command:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo dd bs=4M if=blankos.iso of=/dev/sdX status=progress oflag=sync
|
sudo dd bs=4M if=blankos.iso of=/dev/sdX status=progress oflag=sync
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace `sdX` with your USB drive name (you can find it by doing `sudo fdisk -l`).
|
Replace `sdX` with your USB drive name (you can find it by doing `sudo fdisk -l`).
|
||||||
Tada! You now have a working BlankOS USB stick. Go ahead and try it out!
|
Tada! You now have a working BlankOS USB stick. Go ahead and try it out!
|
||||||
|
(*Might not work properly on monitors that aren't Full HD*)
|
||||||
|
|
||||||
## Post-install
|
## Documentation
|
||||||
|
|
||||||
Two documents are available to help you understand the project better. One is the User's Manual, labelled `USERS.md`, and the other one is the Developer's Manual, labelled `DEVELOPERS.md`. They are full of useful resources around Blank OS. You'll learn how to use the system and how to contribute to it.
|
Two other documents are available to help you understand the project better. One is the User's Manual, labelled [USERS.md](docs/USERS.md), and the other one is the Developer's Manual, labelled [DEVELOPERS.md](docs/DEVELOPERS.md). They are full of useful resources: you'll learn how to use the system and how to contribute to it. *(The docs might not always be up-to-date)*
|
||||||
|
|
||||||
### Next Steps?
|
|
||||||
|
|
||||||
Next steps for this project will be:
|
|
||||||
|
|
||||||
- User programs
|
|
||||||
- Completing the kernel libc
|
|
||||||
- Filesystem support
|
|
||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
|
||||||
@@ -98,7 +54,25 @@ Next steps for this project will be:
|
|||||||
- a great book named *Operating Systems: From 0 to 1*, by Tu, Do Hoang
|
- a great book named *Operating Systems: From 0 to 1*, by Tu, Do Hoang
|
||||||
- the Intel [64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html)
|
- the Intel [64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html)
|
||||||
- [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/index.php)
|
- [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/index.php)
|
||||||
|
- Ralf Brown's Interrupt List
|
||||||
|
- the [little book about OS development](https://littleosbook.github.io/) by Erik Helin and Adam Renberg
|
||||||
|
|
||||||
### ⚠️ Disclaimer
|
### Features / Roadmap
|
||||||
|
|
||||||
This is a hobbyist operating system kernel and it comes without any warranty whatsoever! It isn't capable of anything really. Feedback and contributions are highly appreciated!
|
- [X] Booting with GRUB
|
||||||
|
- [X] Common basic structures (IDT, GDT, ISRs, IRQs)
|
||||||
|
- [X] Common drivers (framebuffer, keyboard, serial, timer, RTC, ATA PIO)
|
||||||
|
- [X] Kernel-space utilities (shell, simple programs)
|
||||||
|
- [ ] Filesystem (FAT32 or VFS ramdisk)
|
||||||
|
- [ ] Changing the default VGA font
|
||||||
|
- [X] Dynamic memory allocator (get memmap from GRUB?)
|
||||||
|
- [ ] Paging/Page Frame Allocation
|
||||||
|
- [ ] TCP/IP Network stack
|
||||||
|
- [ ] Getting to Ring-3 (userspace)
|
||||||
|
- [ ] Multitasking (via round robin scheduling)
|
||||||
|
- [ ] Advanced/other drivers (video, SB16, RTC, Ethernet)
|
||||||
|
- [X] UEFI support
|
||||||
|
- [ ] ELF parsing
|
||||||
|
- [ ] System calls
|
||||||
|
- [ ] GUI
|
||||||
|
- [ ] POSIX and ANSI specification compatibility
|
||||||
|
|||||||
52
USERS.md
52
USERS.md
@@ -1,52 +0,0 @@
|
|||||||
# Blank OS User's Manual
|
|
||||||
|
|
||||||
## Getting started
|
|
||||||
|
|
||||||
### Installation and emulation/execution
|
|
||||||
|
|
||||||
Please refer to the relevant sections in the project `README.md` available in the root folder.
|
|
||||||
|
|
||||||
### First steps
|
|
||||||
|
|
||||||
Once you have launched the OS for the first time, you should first see the welcome banner with the system version. Then, the kernel shell will spawn and you will be able to execute commands.
|
|
||||||
|
|
||||||
To get the list of available commands on the system, type `help`.
|
|
||||||
|
|
||||||
### Commands
|
|
||||||
|
|
||||||
#### `help`
|
|
||||||
|
|
||||||
Shows all of the available commands, which are explained here.
|
|
||||||
|
|
||||||
#### `panic`
|
|
||||||
|
|
||||||
Triggers a kernel panic by trying to divide four by zero.
|
|
||||||
|
|
||||||
#### `words`
|
|
||||||
|
|
||||||
Prints ten random words using an arbitrary dictionary that you can expand in `src/programs/words.c`.
|
|
||||||
|
|
||||||
#### `primes`
|
|
||||||
|
|
||||||
Computes prime numbers up to `PRIMES_MAX`, defined in `src/programs/primes.c`.
|
|
||||||
|
|
||||||
#### `rainbow`
|
|
||||||
|
|
||||||
Asks for text and then outputs it with different vibrant colors.
|
|
||||||
|
|
||||||
#### `clear`
|
|
||||||
|
|
||||||
Clears the screen by scrolling (screen height) times.
|
|
||||||
|
|
||||||
#### `math`
|
|
||||||
|
|
||||||
**This program is not working!**
|
|
||||||
The lexer and parser should be okay, but I can't figure out the `%f` floating point format specifier in the freestanding printf implementation; it triggers weird exceptions that I don't understand. So no math interpreter for now.
|
|
||||||
|
|
||||||
#### `bf`
|
|
||||||
|
|
||||||
A brainfuck interpreter with every instruction and default tape size (30k cells).
|
|
||||||
|
|
||||||
#### `uptime`
|
|
||||||
|
|
||||||
Gets system uptime from the timer in ticks. Ticks are incremented at a rate of 18.222Hz (18.222 ticks per second).
|
|
||||||
10
bochsrc.txt
10
bochsrc.txt
@@ -1,10 +0,0 @@
|
|||||||
megs: 32
|
|
||||||
display_library: x
|
|
||||||
romimage: file=/usr/share/bochs/BIOS-bochs-legacy
|
|
||||||
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
|
|
||||||
ata0-master: type=cdrom, path=os.iso, status=inserted
|
|
||||||
boot: cdrom
|
|
||||||
log: bochslog.txt
|
|
||||||
clock: sync=realtime, time0=local
|
|
||||||
cpu: count=1, ips=1000000
|
|
||||||
com1: enabled=1, mode=file, dev=com1.out
|
|
||||||
5
debug.sh
Executable file
5
debug.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
qemu-system-i386 -s -S -drive file=blankos.iso,format=raw &
|
||||||
|
sleep 1
|
||||||
|
gdb -x gdbinit
|
||||||
139
docs/DEVELOPERS.md
Normal file
139
docs/DEVELOPERS.md
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
# Blank OS Developer's Manual
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- Getting Started
|
||||||
|
- Debugging the kernel
|
||||||
|
- Emulated booting in UEFI mode
|
||||||
|
- Writing programs for BlankOS
|
||||||
|
- Changing the TTY font
|
||||||
|
- Changing the initial ramdisk content
|
||||||
|
- Changing the framebuffer resolution
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### System description
|
||||||
|
|
||||||
|
Blank OS is a megalithic kernel booted by a 3rd party bootloader, GRUB2, using the Multiboot2 specification. The kernel is compiled in ELF format. The target processor architecture is 32-bit x86. Blank OS is BIOS-independent which means it does not use Real mode BIOS functions as its routines. It rather uses in and out port communication to communicate with hardware directly (such as the keyboard) and it uses specific memory locations (for example the framebuffer to manage the screen in text mode). A linear framebuffer is requested in 1920x1080x32 mode via Multiboot and GRUB. It cannot run on other screen resolutions for now. The keyboard layout is QWERTY.
|
||||||
|
|
||||||
|
### Code structure
|
||||||
|
|
||||||
|
The source code is available in folder `src`. You will find subfolders corresponding to appropriate system parts, such as the kernel, the C library (including drivers) and "programs", which are really just functions embedded in the kernel.
|
||||||
|
|
||||||
|
### System calls
|
||||||
|
|
||||||
|
No system calls are available, as the OS runs in kernel-space.
|
||||||
|
|
||||||
|
## Debugging the kernel (QEMU w/ GDB)
|
||||||
|
|
||||||
|
```
|
||||||
|
make debug
|
||||||
|
```
|
||||||
|
|
||||||
|
## Emulated booting in UEFI mode (QEMU w/ OVMF)
|
||||||
|
|
||||||
|
Install the OVMF firmware package by doing `sudo pacman -S ovmf` or the equivalent for your distro. Then, you can emulate the OS as if it was ran using an UEFI machine:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo qemu-system-i386 -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/ia32/OVMF_CODE.fd -drive if=pflash,format=raw,file=/usr/share/OVMF/ia32/OVMF_VARS.fd -drive file=blankos.iso,format=raw -m 4098
|
||||||
|
```
|
||||||
|
|
||||||
|
## Writing programs for BlankOS
|
||||||
|
|
||||||
|
Be warned, these are not actual programs in the sense you'd expect. These are indeed functions that are called from the shell, and embedded in the kernel ELF binary. Real programs apart from the kernel are not yet a thing here, but might be one day.
|
||||||
|
|
||||||
|
### Step 1 - Making the program and the entry point
|
||||||
|
|
||||||
|
To make a program for the OS, first create the appropriate C source file and header file in the `src/programs` subfolder. Name it appropriately, for example `myprogram.c`.
|
||||||
|
|
||||||
|
In this file, you will put the functions your program will use. The entry point for the program should be a void function named `program_<PROGRAM_NAME>`. The entry point can either take no arguments, or use the classic argc/argv structure.
|
||||||
|
|
||||||
|
Valid examples for entry points include:
|
||||||
|
|
||||||
|
```
|
||||||
|
void program_myprogram()
|
||||||
|
void program_myprogram(void)
|
||||||
|
void program_myprogram(int argc, char* argv[])
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, code your stuff freely. The entry point function will basically be the "main" function of your program, like in a regular C file. You can make your own header file too, for example `myprogram.h`.
|
||||||
|
Keep in mind that the standard C library is not available here, so you'll have to use functions from the BlankOS C library, which is located in `src/libc`. Also feel free to look at the header files in `src/drivers` and `src/kernel`, there might be interesting functions in there too (managing input/output devices, the timer, etc..)
|
||||||
|
|
||||||
|
### Step 2 - Registering the program
|
||||||
|
|
||||||
|
Now that your program is done, you will need to make it a part of the OS.
|
||||||
|
|
||||||
|
#### General program header file registering
|
||||||
|
|
||||||
|
To make the entry point function reachable from the shell, you first have to include it in the general programs header file located in `src/programs/programs.h`.
|
||||||
|
|
||||||
|
Put the entry point function prototype in that file. A valid example might be:
|
||||||
|
|
||||||
|
```
|
||||||
|
void program_myprogram(int argc, char* argv[]);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Shell command registering
|
||||||
|
|
||||||
|
Now that your entry point is reachable from the shell source file, you'll have to register it as a command. To do that, locate the section in `src/kernel/shell.c`, in the very beginning of the `shell_install()` function that has a lot of similar lines to the one below:
|
||||||
|
|
||||||
|
```
|
||||||
|
register_command("myprogram", program_myprogram);
|
||||||
|
```
|
||||||
|
|
||||||
|
Add one of these lines for your entry point and the command name you'd like. (like the line above). First argument is the desired command name, and second argument is the entry point for your program.
|
||||||
|
|
||||||
|
Don't make your command name too long, preferably a few characters, like the other ones.
|
||||||
|
|
||||||
|
#### Help utility registering (optional)
|
||||||
|
|
||||||
|
Finally, you can add your command to the list of available commands by adding it to the `printf` call in the `src/programs/misc.c` source file, in the function `program_help()`.
|
||||||
|
|
||||||
|
If possible make sure that the new command name is aligned with the other ones.
|
||||||
|
|
||||||
|
### Step 3 - Compiling and linking
|
||||||
|
|
||||||
|
The linking process should be taken care of by the appropriate Linker script `link.ld` and the Makefile instructions and targets. Nothing should be changed in those files, and your source files should be added automatically.
|
||||||
|
|
||||||
|
### Step 4 - Contributing to the project (optional)
|
||||||
|
|
||||||
|
If you're proud of what you've made, you can clone the repo, make your changes, open a pull request and maybe your program will be added to the main BlankOS repo, and later distributed in the new ISOs!
|
||||||
|
|
||||||
|
## Changing the TTY font
|
||||||
|
|
||||||
|
In order to change the default font, first get your hands on a 8x16 `.psf` (PC Screen Font 2) formatted font. Then, put it in `include/fonts` and remove the default one (`UniCyr_8x16.psf`).
|
||||||
|
|
||||||
|
Go ahead and run `make` one time. The compilation/linking will fail because of unresolved symbols, but an object file should have been created in `build/fonts` with your custom font's name.
|
||||||
|
|
||||||
|
Read the symbols in that object file:
|
||||||
|
|
||||||
|
```
|
||||||
|
readelf -s -W build/fonts/YOUR_FONT_8x16.o
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the symbol name that ends with `_start` and replace all occurences of it in the `src/drivers/framebuffer.c` file.
|
||||||
|
|
||||||
|
Then, run `make` again and the font should have changed properly.
|
||||||
|
|
||||||
|
## Changing the initial ramdisk content
|
||||||
|
|
||||||
|
The system loads an initial ramdisk as a simple TAR file located in `iso/boot/initrd.tar`.
|
||||||
|
You can add, delete, or modify this file's contents by doing that in the `src/initrd` folder. Anything in that folder will be added to the initial ramdisk and will therefore be loaded into the system.
|
||||||
|
|
||||||
|
The ramdisk gets loaded as a GRUB2 module.
|
||||||
|
|
||||||
|
## Changing the framebuffer resolution
|
||||||
|
|
||||||
|
Locate the framebuffer request tag from the Multiboot2 header in `src/kernel/loader.s`. It should look like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
align 8
|
||||||
|
dw 5 ; 2
|
||||||
|
dw 0 ; 2
|
||||||
|
dd 20 ; 4
|
||||||
|
dd 1920 ; 4
|
||||||
|
dd 1080 ; 4
|
||||||
|
dd 32 ; 4
|
||||||
|
```
|
||||||
|
|
||||||
|
Change the `1920` and `1080` values with the resolution you want, according to your screen. Be aware that this might break some programs that rely on the hardcoded Full HD framebuffer value (1920x1080x32). You can also try switching the value under that,`32`, but it will break the display because the kernel is made for 32bpp.
|
||||||
145
docs/USERS.md
Normal file
145
docs/USERS.md
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Blank OS User's Manual
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
First, let me introduce you some features of this project.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Serial port driver (output & debug)
|
||||||
|
- Framebuffer driver (output)
|
||||||
|
- PS/2 Keyboard and PIC driver (input)
|
||||||
|
- PIT (system clock/timer) driver
|
||||||
|
- Working IDT, GDT, ISRs, and IRQs
|
||||||
|
- Kernel panicking (exception handling)
|
||||||
|
- A kernel-space shell
|
||||||
|
- Cool color output!!
|
||||||
|
- Some small working kernel-space programs, such as...
|
||||||
|
- A brainfuck interpreter
|
||||||
|
- An arithmetic calculator
|
||||||
|
- ROT13 and Morse cipher programs
|
||||||
|
- Conway's Game of Life
|
||||||
|
- And some more...
|
||||||
|
|
||||||
|
### Installation and emulation/execution
|
||||||
|
|
||||||
|
Please refer to the relevant sections in the project `README.md` available in the root folder.
|
||||||
|
|
||||||
|
### First steps
|
||||||
|
|
||||||
|
Once you have launched the OS for the first time, you should first see the welcome banner with the system version. Then, the kernel shell will spawn and you will be able to execute commands.
|
||||||
|
|
||||||
|
To get the list of available commands on the system, type `help`.
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
#### `help`
|
||||||
|
|
||||||
|
Shows all of the available commands, which are explained here.
|
||||||
|
|
||||||
|
#### `panic`
|
||||||
|
|
||||||
|
Triggers a kernel panic by reserved exception.
|
||||||
|
|
||||||
|
#### `words`
|
||||||
|
|
||||||
|
Prints random words using an arbitrary dictionary that you can expand in `src/programs/words.c`.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
- `<nothing>` will default amount of words to 10
|
||||||
|
- `<integer>` will set the amount of words to that number
|
||||||
|
|
||||||
|
#### `primes`
|
||||||
|
|
||||||
|
Computes prime numbers.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
- `<nothing>` will default to `PRIMES_MAX` (a million)
|
||||||
|
- `<integer>` will compute primes up to that number
|
||||||
|
|
||||||
|
#### `rainbow <string>`
|
||||||
|
|
||||||
|
Asks for text and then outputs it with different vibrant colors.
|
||||||
|
|
||||||
|
#### `clear`
|
||||||
|
|
||||||
|
Clears the screen by scrolling (screen height) times.
|
||||||
|
|
||||||
|
#### `math`
|
||||||
|
|
||||||
|
A math lexer & parser that can calculate simple arithmetic operations. Adding, subtracting, multiplying, dividing, and factoring are supported. (I plan to get support for trigonometric functions maybe)
|
||||||
|
|
||||||
|
#### `bf <optional: file>`
|
||||||
|
|
||||||
|
A brainfuck interpreter with every instruction and default tape size (30k cells). Takes an optional argument, the filename for a Brainfuck source file.
|
||||||
|
|
||||||
|
#### `uptime`
|
||||||
|
|
||||||
|
Gets system uptime from the timer in ticks. Ticks are incremented at a rate of 18.222Hz (18.222 ticks per second).
|
||||||
|
|
||||||
|
#### `echo <string>`
|
||||||
|
|
||||||
|
The classic echo command, that outputs your input.
|
||||||
|
|
||||||
|
#### `sysinfo [option]`
|
||||||
|
|
||||||
|
Outputs information about the current system (CPU and RAM).
|
||||||
|
|
||||||
|
Options:
|
||||||
|
- `<nothing>` will show basic info about the CPUid and lower/upper memory.
|
||||||
|
- `-v` will output the CPUID, lower/upper memory, and the memory map.
|
||||||
|
|
||||||
|
#### `conway [option]`
|
||||||
|
|
||||||
|
A classic Game of Life implementation with standard rules and 100 generations.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
- `<nothing>` will spawn a random soup of cells
|
||||||
|
- `-g` will spawn a classic glider
|
||||||
|
- `-l` will spawn a lightweight spaceship
|
||||||
|
|
||||||
|
#### `rot13 <string>`
|
||||||
|
|
||||||
|
Encode a string using the rot13 cipher.
|
||||||
|
|
||||||
|
#### `morse <string>`
|
||||||
|
|
||||||
|
Convert a string to its morse equivalent.
|
||||||
|
|
||||||
|
#### `cowsay <string>`
|
||||||
|
|
||||||
|
Makes a cow speak!
|
||||||
|
|
||||||
|
#### `pi <terms>`
|
||||||
|
|
||||||
|
Computes Pi up to a couple of digits using the Leibniz series; takes one integer argument, the number of terms of the series to compute.
|
||||||
|
|
||||||
|
#### `bmp <file>`
|
||||||
|
|
||||||
|
Shows information about a 24-bit BMP image and renders it in the terminal.
|
||||||
|
|
||||||
|
### Initrd utilities
|
||||||
|
|
||||||
|
You can browse the (really) simple TAR filesystem with the following commands:
|
||||||
|
|
||||||
|
#### `ls`
|
||||||
|
|
||||||
|
Lists all files present in `initrd.tar`.
|
||||||
|
|
||||||
|
#### `cat <file>`
|
||||||
|
|
||||||
|
Prints file content to terminal. Filename must be specified the same way as it is outputted when using `ls`.
|
||||||
|
|
||||||
|
### Games
|
||||||
|
|
||||||
|
#### `naval`
|
||||||
|
|
||||||
|
Starts a simplified naval battle game with 5 ships, one position each.
|
||||||
|
|
||||||
|
#### `snake <ticks>`
|
||||||
|
|
||||||
|
Starts a simplified and buggy snake game. You can choose the speed by setting the `ticks` argument, or let it default to a normal speed.
|
||||||
|
|
||||||
|
Controls:
|
||||||
|
- `q` to quit
|
||||||
|
- `wasd` to move
|
||||||
4
grub.cfg
4
grub.cfg
@@ -1,4 +1,6 @@
|
|||||||
menuentry "Blank OS" {
|
menuentry "Blank OS" {
|
||||||
multiboot /boot/kernel.elf
|
insmod all_video
|
||||||
|
multiboot2 /boot/kernel.elf
|
||||||
|
module2 /boot/initrd.tar
|
||||||
boot
|
boot
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
include/fonts/UniCyr_8x16.psf
Normal file
BIN
include/fonts/UniCyr_8x16.psf
Normal file
Binary file not shown.
@@ -1,5 +0,0 @@
|
|||||||
default=0
|
|
||||||
timeout=0
|
|
||||||
|
|
||||||
title os
|
|
||||||
kernel /boot/kernel.elf
|
|
||||||
Binary file not shown.
Binary file not shown.
17
link.ld
17
link.ld
@@ -1,30 +1,31 @@
|
|||||||
ENTRY(loader)
|
ENTRY(loader)
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
/* Address to load at; 1MB */
|
/* Address to load at; 2MB */
|
||||||
|
|
||||||
. = 0x00100000;
|
. = 2M;
|
||||||
|
|
||||||
.__mbHeader : {
|
.multiboot_header ALIGN(4K) : {
|
||||||
*(.__mbHeader)
|
*(.multiboot_header)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Align relevant sections at 4KB */
|
/* Align relevant sections at 4KB */
|
||||||
|
|
||||||
.text ALIGN (0x1000) :
|
.text ALIGN (4K) :
|
||||||
{
|
{
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
}
|
}
|
||||||
|
|
||||||
.data ALIGN (0x1000) :
|
.data ALIGN (4K) :
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
.bss ALIGN (0x1000) :
|
.bss ALIGN (4K) :
|
||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end = .; _end = .; __end = .;
|
||||||
}
|
}
|
||||||
|
|||||||
58
makefile
58
makefile
@@ -1,5 +1,5 @@
|
|||||||
CC = i386-elf-7.5.0-Linux-x86_64/bin/i386-elf-gcc
|
CC = i386-elf-7.5.0-Linux-x86_64/bin/i386-elf-gcc
|
||||||
CFLAGS = -Wall -Wextra -Wno-div-by-zero -Wno-builtin-declaration-mismatch -c -I src/
|
CFLAGS = -ffreestanding -g -Wall -Wextra -Wno-builtin-declaration-mismatch -mno-sse -mno-mmx -mno-avx -march=i386 -c -I src/
|
||||||
LDFLAGS = -T link.ld -melf_i386
|
LDFLAGS = -T link.ld -melf_i386
|
||||||
AS = nasm
|
AS = nasm
|
||||||
ASFLAGS = -f elf
|
ASFLAGS = -f elf
|
||||||
@@ -9,6 +9,8 @@ KERNEL_DIR = $(SRC_DIR)/kernel
|
|||||||
LIBC_DIR = $(SRC_DIR)/libc
|
LIBC_DIR = $(SRC_DIR)/libc
|
||||||
PROGRAMS_DIR = $(SRC_DIR)/programs
|
PROGRAMS_DIR = $(SRC_DIR)/programs
|
||||||
DRIVERS_DIR = $(SRC_DIR)/drivers
|
DRIVERS_DIR = $(SRC_DIR)/drivers
|
||||||
|
INCLUDE_DIR = include
|
||||||
|
FONTS_DIR = $(INCLUDE_DIR)/fonts
|
||||||
OBJ_DIR = build
|
OBJ_DIR = build
|
||||||
|
|
||||||
C_SOURCES = $(wildcard $(KERNEL_DIR)/*.c) $(wildcard $(LIBC_DIR)/*.c) $(wildcard $(PROGRAMS_DIR)/*.c) $(wildcard $(DRIVERS_DIR)/*.c)
|
C_SOURCES = $(wildcard $(KERNEL_DIR)/*.c) $(wildcard $(LIBC_DIR)/*.c) $(wildcard $(PROGRAMS_DIR)/*.c) $(wildcard $(DRIVERS_DIR)/*.c)
|
||||||
@@ -16,14 +18,20 @@ ASM_SOURCES = $(wildcard $(KERNEL_DIR)/*.s) $(wildcard $(LIBC_DIR)/*.s) $(wildca
|
|||||||
|
|
||||||
OBJECTS = $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.s=.o))
|
OBJECTS = $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.s=.o))
|
||||||
|
|
||||||
|
TOOLCHAIN_SRC = https://newos.org/toolchains/i386-elf-7.5.0-Linux-x86_64.tar.xz
|
||||||
|
TOOLCHAIN_FILE = i386-elf-7.5.0-Linux-x86_64.tar.xz
|
||||||
|
|
||||||
|
FONT_OBJ = $(OBJ_DIR)/fonts/UniCyr_8x16.o
|
||||||
|
FONT_SRC = $(FONTS_DIR)/UniCyr_8x16.psf
|
||||||
|
|
||||||
all: $(OBJ_DIR) kernel.elf
|
all: $(OBJ_DIR) kernel.elf
|
||||||
|
|
||||||
$(OBJ_DIR):
|
$(OBJ_DIR):
|
||||||
mkdir -p $(OBJ_DIR)
|
mkdir -p $(OBJ_DIR)
|
||||||
mkdir -p $(OBJ_DIR)/kernel $(OBJ_DIR)/libc $(OBJ_DIR)/programs $(OBJ_DIR)/drivers
|
mkdir -p $(OBJ_DIR)/kernel $(OBJ_DIR)/libc $(OBJ_DIR)/programs $(OBJ_DIR)/drivers $(OBJ_DIR)/fonts
|
||||||
|
|
||||||
kernel.elf: $(OBJECTS)
|
kernel.elf: $(OBJECTS) $(FONT_OBJ)
|
||||||
ld $(LDFLAGS) $(OBJECTS) -o kernel.elf
|
ld $(LDFLAGS) $(OBJECTS) $(FONT_OBJ) -o kernel.elf
|
||||||
|
|
||||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
||||||
$(CC) $(CFLAGS) $< -o $@
|
$(CC) $(CFLAGS) $< -o $@
|
||||||
@@ -31,28 +39,32 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
|||||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
|
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
|
||||||
$(AS) $(ASFLAGS) $< -o $@
|
$(AS) $(ASFLAGS) $< -o $@
|
||||||
|
|
||||||
os.iso: kernel.elf
|
$(FONT_OBJ): $(FONT_SRC) | $(OBJ_DIR)/fonts
|
||||||
|
objcopy -O elf32-i386 -B i386 -I binary $(FONT_SRC) $(FONT_OBJ)
|
||||||
|
|
||||||
|
$(OBJ_DIR)/fonts:
|
||||||
|
mkdir -p $(OBJ_DIR)/fonts
|
||||||
|
|
||||||
|
toolchain:
|
||||||
|
wget $(TOOLCHAIN_SRC)
|
||||||
|
tar xf $(TOOLCHAIN_FILE)
|
||||||
|
|
||||||
|
iso: kernel.elf initrd
|
||||||
cp kernel.elf iso/boot/kernel.elf
|
cp kernel.elf iso/boot/kernel.elf
|
||||||
genisoimage -R \
|
cp grub.cfg iso/boot/grub/grub.cfg
|
||||||
-b boot/grub/stage2_eltorito \
|
grub-mkrescue iso -o blankos.iso
|
||||||
-no-emul-boot \
|
|
||||||
-boot-load-size 4 \
|
|
||||||
-A os \
|
|
||||||
-input-charset utf8 \
|
|
||||||
-quiet \
|
|
||||||
-boot-info-table \
|
|
||||||
-o os.iso \
|
|
||||||
iso
|
|
||||||
|
|
||||||
real: kernel.elf
|
initrd:
|
||||||
mkdir -p real/boot/grub
|
mkdir -p iso/boot/grub
|
||||||
cp kernel.elf real/boot/kernel.elf
|
tar -cf $(OBJ_DIR)/initrd.tar -C $(SRC_DIR)/initrd .
|
||||||
cp grub.cfg real/boot/grub/grub.cfg
|
cp $(OBJ_DIR)/initrd.tar iso/boot
|
||||||
grub-mkrescue real -o blankos.iso
|
|
||||||
|
|
||||||
run: os.iso
|
run: iso
|
||||||
bochs -f bochsrc.txt -q
|
qemu-system-i386 -drive file=blankos.iso,format=raw
|
||||||
|
|
||||||
|
debug:
|
||||||
|
./debug.sh
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJ_DIR) kernel.elf os.iso blankos.iso real
|
rm -rf $(OBJ_DIR) kernel.elf blankos.iso $(TOOLCHAIN_FILE)
|
||||||
|
|
||||||
|
|||||||
62
src/drivers/ata.c
Normal file
62
src/drivers/ata.c
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// ATA PIO driver implementation
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../kernel/io.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "ata.h"
|
||||||
|
|
||||||
|
static inline uint16_t inw(uint16_t port) {
|
||||||
|
uint16_t result;
|
||||||
|
asm volatile("inw %1, %0" : "=a"(result) : "dN"(port));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void outw(uint16_t port, uint16_t data) {
|
||||||
|
asm volatile("outw %1, %0" : : "dN"(port), "a"(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ata_wait_bsy() {
|
||||||
|
while (inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_BSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ata_wait_drq() {
|
||||||
|
while (!(inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_DRQ));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ata_select_drive(uint8_t drive) {
|
||||||
|
outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | (drive << 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ata_read_sector(uint32_t lba, uint8_t* buffer) {
|
||||||
|
ata_wait_bsy();
|
||||||
|
ata_select_drive(0);
|
||||||
|
|
||||||
|
outb(ATA_PRIMARY_IO + ATA_REG_SECCOUNT0, 1);
|
||||||
|
outb(ATA_PRIMARY_IO + ATA_REG_LBA0, (uint8_t)lba);
|
||||||
|
outb(ATA_PRIMARY_IO + ATA_REG_LBA1, (uint8_t)(lba >> 8));
|
||||||
|
outb(ATA_PRIMARY_IO + ATA_REG_LBA2, (uint8_t)(lba >> 16));
|
||||||
|
outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | ((lba >> 24) & 0x0F));
|
||||||
|
|
||||||
|
outb(ATA_PRIMARY_IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
|
||||||
|
|
||||||
|
ata_wait_bsy();
|
||||||
|
ata_wait_drq();
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
((uint16_t*)buffer)[i] = inw(ATA_PRIMARY_IO + ATA_REG_DATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Works only w/o paging
|
||||||
|
void test_read_sector() {
|
||||||
|
uint8_t buffer[512];
|
||||||
|
ata_read_sector(0, buffer);
|
||||||
|
|
||||||
|
for (int i = 0; i < 512; i++) {
|
||||||
|
if (i%25==0) puts("\n");
|
||||||
|
printf("%02x ", buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/drivers/ata.h
Normal file
35
src/drivers/ata.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// ATA PIO driver implementation header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef ATA_H
|
||||||
|
#define ATA_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define ATA_PRIMARY_IO 0x1F0
|
||||||
|
#define ATA_PRIMARY_CTRL 0x3F6
|
||||||
|
#define ATA_CMD_READ_PIO 0x20
|
||||||
|
#define ATA_CMD_WRITE_PIO 0x30
|
||||||
|
#define ATA_IDENTIFY 0xEC
|
||||||
|
|
||||||
|
#define ATA_REG_DATA 0x00
|
||||||
|
#define ATA_REG_ERROR 0x01
|
||||||
|
#define ATA_REG_SECCOUNT0 0x02
|
||||||
|
#define ATA_REG_LBA0 0x03
|
||||||
|
#define ATA_REG_LBA1 0x04
|
||||||
|
#define ATA_REG_LBA2 0x05
|
||||||
|
#define ATA_REG_HDDEVSEL 0x06
|
||||||
|
#define ATA_REG_COMMAND 0x07
|
||||||
|
#define ATA_REG_STATUS 0x07
|
||||||
|
|
||||||
|
#define ATA_SR_BSY 0x80
|
||||||
|
#define ATA_SR_DRDY 0x40
|
||||||
|
#define ATA_SR_DRQ 0x08
|
||||||
|
#define ATA_SR_ERR 0x01
|
||||||
|
|
||||||
|
void ata_read_sector(uint32_t lba, uint8_t* buffer);
|
||||||
|
void test_read_sector();
|
||||||
|
|
||||||
|
#endif
|
||||||
89
src/drivers/framebuffer.c
Normal file
89
src/drivers/framebuffer.c
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// Framebuffer driver
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "framebuffer.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
|
||||||
|
extern char* framebuffer;
|
||||||
|
|
||||||
|
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color)
|
||||||
|
{
|
||||||
|
uint32_t* pixel_addr = (uint32_t*)((uint8_t*)fb + y * pitch + x *(bpp / 8));
|
||||||
|
*pixel_addr = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg)
|
||||||
|
{
|
||||||
|
PSF_font *font = (PSF_font*)&_binary_include_fonts_UniCyr_8x16_psf_start;
|
||||||
|
int bytesperline=(font->width+7)/8;
|
||||||
|
if (unicode != NULL) {
|
||||||
|
c = unicode[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* glyph = (unsigned char*)&_binary_include_fonts_UniCyr_8x16_psf_start + font->headersize + (c>0&&c<font->numglyph?c:0)*font->bytesperglyph;
|
||||||
|
|
||||||
|
int offs =
|
||||||
|
(cy * font->height * scanline) +
|
||||||
|
(cx * (font->width) * sizeof(PIXEL));
|
||||||
|
|
||||||
|
unsigned int x, y;
|
||||||
|
int line, mask;
|
||||||
|
|
||||||
|
for (y=0; y<font->height; y++)
|
||||||
|
{
|
||||||
|
line=offs;
|
||||||
|
mask=1<<(font->width-1);
|
||||||
|
|
||||||
|
for (x=0; x<font->width; x++)
|
||||||
|
{
|
||||||
|
*((PIXEL*)(framebuffer + line)) = *((unsigned int*)glyph) & mask ? fg : bg;
|
||||||
|
mask >>= 1;
|
||||||
|
line += sizeof(PIXEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
glyph += bytesperline;
|
||||||
|
offs += scanline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scroll()
|
||||||
|
{
|
||||||
|
serial_printf(3, "Scrolling...\r");
|
||||||
|
uint32_t bg_color = 0x00000000;
|
||||||
|
PSF_font *font = (PSF_font*)&_binary_include_fonts_UniCyr_8x16_psf_start;
|
||||||
|
|
||||||
|
int line_size = font->height * scanline;
|
||||||
|
int framebuffer_size = scanline * font->height * (1080/font->height);
|
||||||
|
|
||||||
|
// Erasing first line
|
||||||
|
for (uint32_t y=0; y<font->height; y++)
|
||||||
|
{
|
||||||
|
for (uint32_t x=0; x<scanline/sizeof(PIXEL); x++)
|
||||||
|
{
|
||||||
|
*((PIXEL*)(framebuffer + y * scanline + x * sizeof(PIXEL))) = bg_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moving all lines up by 1 line
|
||||||
|
for (int y=1; y<(framebuffer_size/line_size); y++)
|
||||||
|
{
|
||||||
|
void* src = framebuffer + y*line_size;
|
||||||
|
void* dst = framebuffer + (y-1)*line_size;
|
||||||
|
memmove(dst, src, line_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erasing last line
|
||||||
|
int last_line_start = (framebuffer_size/line_size-1) * line_size;
|
||||||
|
for (uint32_t y=0; y<font->height; y++)
|
||||||
|
{
|
||||||
|
for (uint32_t x=0; x<scanline/sizeof(PIXEL); x++)
|
||||||
|
{
|
||||||
|
*((PIXEL*)(framebuffer + last_line_start + y * scanline + x * sizeof(PIXEL))) = bg_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
42
src/drivers/framebuffer.h
Normal file
42
src/drivers/framebuffer.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Framebuffer driver header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef FRAMEBUFFER_H
|
||||||
|
#define FRAMEBUFFER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern int scanline;
|
||||||
|
extern char _binary_include_fonts_UniCyr_8x16_psf_start;
|
||||||
|
uint16_t* unicode;
|
||||||
|
|
||||||
|
#define PIXEL uint32_t
|
||||||
|
|
||||||
|
#define PSF1_FONT_MAGIC 0x0436
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t magic; // Magic bytes for identification.
|
||||||
|
uint8_t fontMode; // PSF font mode.
|
||||||
|
uint8_t characterSize; // PSF character size.
|
||||||
|
} PSF1_Header;
|
||||||
|
|
||||||
|
#define PSF_FONT_MAGIC 0x864ab572
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t magic; /* magic bytes to identify PSF */
|
||||||
|
uint32_t version; /* zero */
|
||||||
|
uint32_t headersize; /* offset of bitmaps in file, 32 */
|
||||||
|
uint32_t flags; /* 0 if there's no unicode table */
|
||||||
|
uint32_t numglyph; /* number of glyphs */
|
||||||
|
uint32_t bytesperglyph; /* size of each glyph */
|
||||||
|
uint32_t height; /* height in pixels */
|
||||||
|
uint32_t width; /* width in pixels */
|
||||||
|
} PSF_font;
|
||||||
|
|
||||||
|
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color);
|
||||||
|
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg);
|
||||||
|
void scroll();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
|
// Keyboard driver
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../kernel/io.h"
|
#include "../kernel/io.h"
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
|
#include "kb.h"
|
||||||
#define KEYBOARD_BUFFER_SIZE 256
|
|
||||||
|
|
||||||
#define LEFT_SHIFT_PRESSED 0x2A
|
|
||||||
#define RIGHT_SHIFT_PRESSED 0x36
|
|
||||||
#define LEFT_SHIFT_RELEASED 0xAA
|
|
||||||
#define RIGHT_SHIFT_RELEASED 0xB6
|
|
||||||
|
|
||||||
unsigned char kbdus[128] =
|
unsigned char kbdus[128] =
|
||||||
{
|
{
|
||||||
@@ -130,6 +129,7 @@ void keyboard_handler()
|
|||||||
void keyboard_install()
|
void keyboard_install()
|
||||||
{
|
{
|
||||||
irq_install_handler(1, keyboard_handler);
|
irq_install_handler(1, keyboard_handler);
|
||||||
|
printf("[keyboard] installed irq handler\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
char keyboard_getchar()
|
char keyboard_getchar()
|
||||||
@@ -140,3 +140,19 @@ char keyboard_getchar()
|
|||||||
keyboard_buffer_start = (keyboard_buffer_start+1) % KEYBOARD_BUFFER_SIZE;
|
keyboard_buffer_start = (keyboard_buffer_start+1) % KEYBOARD_BUFFER_SIZE;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int keyboard_has_input()
|
||||||
|
{
|
||||||
|
return keyboard_buffer_start != keyboard_buffer_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
char keyboard_getchar_non_blocking()
|
||||||
|
{
|
||||||
|
if (keyboard_has_input())
|
||||||
|
{
|
||||||
|
char c = keyboard_buffer[keyboard_buffer_start];
|
||||||
|
keyboard_buffer_start = (keyboard_buffer_start+1)%KEYBOARD_BUFFER_SIZE;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,20 @@
|
|||||||
|
// Keyboard driver header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#ifndef KB_H
|
#ifndef KB_H
|
||||||
#define KB_H
|
#define KB_H
|
||||||
|
|
||||||
|
#define KEYBOARD_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
#define LEFT_SHIFT_PRESSED 0x2A
|
||||||
|
#define RIGHT_SHIFT_PRESSED 0x36
|
||||||
|
#define LEFT_SHIFT_RELEASED 0xAA
|
||||||
|
#define RIGHT_SHIFT_RELEASED 0xB6
|
||||||
|
|
||||||
char keyboard_getchar();
|
char keyboard_getchar();
|
||||||
|
int keyboard_has_input();
|
||||||
|
char keyboard_getchar_non_blocking();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
103
src/drivers/pci.c
Normal file
103
src/drivers/pci.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// PCI bus driver implementation
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "pci.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
|
static inline void outl(uint16_t port, uint32_t value)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t inl(uint16_t port)
|
||||||
|
{
|
||||||
|
uint32_t ret;
|
||||||
|
__asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_write_config_address(uint32_t address)
|
||||||
|
{
|
||||||
|
outl(PCI_CONFIG_ADDRESS, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pci_read_config_data()
|
||||||
|
{
|
||||||
|
return inl(PCI_CONFIG_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pci_config_address(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||||
|
{
|
||||||
|
return (1 << 31) | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pci_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||||
|
{
|
||||||
|
uint32_t address = pci_config_address(bus, device, function, offset);
|
||||||
|
pci_write_config_address(address);
|
||||||
|
return pci_read_config_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_device_t pci_get_device(uint8_t bus, uint8_t device, uint8_t function)
|
||||||
|
{
|
||||||
|
pci_device_t dev;
|
||||||
|
|
||||||
|
uint32_t reg0 = pci_read(bus, device, function, 0x00); // Vendor ID, Device ID
|
||||||
|
uint32_t reg2 = pci_read(bus, device, function, 0x08); // Class, Subclass, Prog IF, Revision
|
||||||
|
|
||||||
|
dev.vendor_id = reg0 & 0xFFFF;
|
||||||
|
dev.device_id = (reg0 >> 16) & 0xFFFF;
|
||||||
|
dev.class_code = (reg2 >> 24) & 0xFF;
|
||||||
|
dev.subclass = (reg2 >> 16) & 0xFF;
|
||||||
|
dev.prog_if = (reg2 >> 8) & 0xFF;
|
||||||
|
dev.revision_id = reg2 & 0xFF;
|
||||||
|
dev.bus = bus;
|
||||||
|
dev.device = device;
|
||||||
|
dev.function = function;
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan_pci_bus()
|
||||||
|
{
|
||||||
|
for (uint16_t bus = 0; bus < 256; bus++) {
|
||||||
|
for (uint8_t device = 0; device < 32; device++) {
|
||||||
|
for (uint8_t function = 0; function < 8; function++) {
|
||||||
|
pci_device_t dev = pci_get_device(bus, device, function);
|
||||||
|
|
||||||
|
if (dev.vendor_id != 0xFFFF) {
|
||||||
|
|
||||||
|
// Maybe put that in a database in initrd.tar?
|
||||||
|
char* vendor_string;
|
||||||
|
switch(dev.vendor_id)
|
||||||
|
{
|
||||||
|
case 0x8086:
|
||||||
|
vendor_string = "Intel Corporation";
|
||||||
|
break;
|
||||||
|
case 0x1234:
|
||||||
|
vendor_string = "Brain Actuated Technologies";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vendor_string = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* device_string;
|
||||||
|
switch(dev.device_id)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
device_string = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("PCI Device found: Bus %u, Device %u, Function %u, Vendor ID: 0x%x (%s), Device ID: 0x%x (%s), Class: 0x%x\n",
|
||||||
|
dev.bus, dev.device, dev.function, dev.vendor_id, vendor_string, dev.device_id, device_string, dev.class_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
29
src/drivers/pci.h
Normal file
29
src/drivers/pci.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// PCI bus driver implementation header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef PCI_H
|
||||||
|
#define PCI_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||||
|
#define PCI_CONFIG_DATA 0xCFC
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t vendor_id;
|
||||||
|
uint16_t device_id;
|
||||||
|
uint8_t class_code;
|
||||||
|
uint8_t subclass;
|
||||||
|
uint8_t prog_if;
|
||||||
|
uint8_t revision_id;
|
||||||
|
uint8_t bus;
|
||||||
|
uint8_t device;
|
||||||
|
uint8_t function;
|
||||||
|
} pci_device_t;
|
||||||
|
|
||||||
|
void scan_pci_bus();
|
||||||
|
|
||||||
|
#endif
|
||||||
64
src/drivers/rtc.c
Normal file
64
src/drivers/rtc.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Real-time clock driver implementation for better PRNG
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "rtc.h"
|
||||||
|
#include "../kernel/io.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
|
uint8_t rtc_read_register(uint8_t reg)
|
||||||
|
{
|
||||||
|
outb(0x70, reg);
|
||||||
|
return inb(0x71);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bcd_to_bin(uint8_t bcd)
|
||||||
|
{
|
||||||
|
return ((bcd/16)*10) + (bcd%16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtc_is_updating()
|
||||||
|
{
|
||||||
|
outb(0x70, 0x0A);
|
||||||
|
return (inb(0x71) & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_read_time(rtc_time_t *time)
|
||||||
|
{
|
||||||
|
while (rtc_is_updating());
|
||||||
|
|
||||||
|
time->seconds = rtc_read_register(0x00);
|
||||||
|
time->minutes = rtc_read_register(0x02);
|
||||||
|
time->hours = rtc_read_register(0x04);
|
||||||
|
time->day = rtc_read_register(0x06);
|
||||||
|
time->month = rtc_read_register(0x07);
|
||||||
|
time->year = rtc_read_register(0x08);
|
||||||
|
|
||||||
|
outb(0x70, 0x0B);
|
||||||
|
uint8_t registerB = inb(0x71);
|
||||||
|
|
||||||
|
if (!(registerB & 0x04))
|
||||||
|
{
|
||||||
|
time->seconds = bcd_to_bin(time->seconds);
|
||||||
|
time->minutes = bcd_to_bin(time->minutes);
|
||||||
|
time->hours = bcd_to_bin(time->hours);
|
||||||
|
time->day = bcd_to_bin(time->day);
|
||||||
|
time->month = bcd_to_bin(time->month);
|
||||||
|
time->year = bcd_to_bin(time->year);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_time(const rtc_time_t *time)
|
||||||
|
{
|
||||||
|
printf("%02d/%02d/%02d %02d:%02d:%02d\n", time->day, time->month, time->year, time->hours, time->minutes, time->seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
long time_seed()
|
||||||
|
{
|
||||||
|
rtc_time_t* time = {0};
|
||||||
|
rtc_read_time(time);
|
||||||
|
|
||||||
|
return time->day + time->month + time->year + time->hours + time->minutes + time->seconds;
|
||||||
|
}
|
||||||
23
src/drivers/rtc.h
Normal file
23
src/drivers/rtc.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Real-time clock driver implementation header for better PRNG
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef RTC_H
|
||||||
|
#define RTC_H
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t seconds;
|
||||||
|
uint8_t minutes;
|
||||||
|
uint8_t hours;
|
||||||
|
uint8_t day;
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t year;
|
||||||
|
} rtc_time_t;
|
||||||
|
|
||||||
|
void rtc_read_time(rtc_time_t *time);
|
||||||
|
long time_seed();
|
||||||
|
void print_time(const rtc_time_t *time);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
|
// Serial I/O driver
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../kernel/io.h"
|
#include "../kernel/io.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
int init_serial()
|
int init_serial()
|
||||||
{
|
{
|
||||||
@@ -19,6 +25,7 @@ int init_serial()
|
|||||||
}
|
}
|
||||||
|
|
||||||
outb(PORT+4, 0x0F);
|
outb(PORT+4, 0x0F);
|
||||||
|
puts("[serial] initialized i/o on port COM1\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,5 +68,219 @@ void log(const char* str, const int errlevel)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
serial_puts(str);
|
serial_puts(str);
|
||||||
serial_puts("\n");
|
}
|
||||||
|
|
||||||
|
const char serial_charset[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
int* serial_printf_number(int* argp, int length, bool sign, int radix)
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
unsigned long long number;
|
||||||
|
int number_sign = 1;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
switch(length)
|
||||||
|
{
|
||||||
|
case PRINTF_LENGTH_SHORT_SHORT:
|
||||||
|
case PRINTF_LENGTH_SHORT:
|
||||||
|
case PRINTF_LENGTH_START:
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
int n = *argp;
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
number_sign = -1;
|
||||||
|
}
|
||||||
|
number = (unsigned long long) n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
number = *(unsigned int*) argp;
|
||||||
|
}
|
||||||
|
argp++;
|
||||||
|
break;
|
||||||
|
case PRINTF_LENGTH_LONG:
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
long int n = *(long int*)argp;
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
number_sign = -1;
|
||||||
|
}
|
||||||
|
number = (unsigned long long) n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
number = *(unsigned long int*) argp;
|
||||||
|
}
|
||||||
|
argp += 2;
|
||||||
|
break;
|
||||||
|
case PRINTF_LENGTH_LONG_LONG:
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
long long int n = *(long long int*)argp;
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
number_sign = -1;
|
||||||
|
}
|
||||||
|
number = (unsigned long long) n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
number = *(unsigned long long int*) argp;
|
||||||
|
}
|
||||||
|
argp += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint32_t rem;
|
||||||
|
x86_div64_32(number, radix, &number, &rem);
|
||||||
|
buffer[pos++] = serial_charset[rem];
|
||||||
|
} while (number > 0);
|
||||||
|
|
||||||
|
if (sign && number_sign < 0)
|
||||||
|
{
|
||||||
|
buffer[pos++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
while (--pos >= 0)
|
||||||
|
{
|
||||||
|
write_serial(buffer[pos]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return argp;
|
||||||
|
}
|
||||||
|
void serial_printf(int errlevel, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
switch (errlevel)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
serial_puts("[ERROR] ");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
serial_puts("[WARNING] ");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
serial_puts("[INFO] ");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
serial_puts("[DEBUG] ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int* argp = (int*) &fmt;
|
||||||
|
int state = PRINTF_STATE_START;
|
||||||
|
int length = PRINTF_LENGTH_START;
|
||||||
|
int radix = 10;
|
||||||
|
bool sign = false;
|
||||||
|
|
||||||
|
argp++;
|
||||||
|
while (*fmt)
|
||||||
|
{
|
||||||
|
switch(state) {
|
||||||
|
case PRINTF_STATE_START:
|
||||||
|
if (*fmt == '%')
|
||||||
|
{
|
||||||
|
state = PRINTF_STATE_LENGTH;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
write_serial(*fmt);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PRINTF_STATE_LENGTH:
|
||||||
|
if (*fmt == 'h')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_SHORT;
|
||||||
|
state = PRINTF_STATE_SHORT;
|
||||||
|
}
|
||||||
|
else if (*fmt == 'l')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_LONG;
|
||||||
|
state = PRINTF_STATE_LONG;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PRINTF_STATE_SHORT:
|
||||||
|
if (*fmt == 'h')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_SHORT_SHORT;
|
||||||
|
state = PRINTF_STATE_SPEC;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PRINTF_STATE_LONG:
|
||||||
|
if (*fmt == 'l')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_LONG_LONG;
|
||||||
|
state = PRINTF_STATE_SPEC;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PRINTF_STATE_SPEC:
|
||||||
|
PRINTF_STATE_SPEC_:
|
||||||
|
switch(*fmt)
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
serial_puts(*(const char **)argp);
|
||||||
|
argp++;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
serial_puts(*(const char **)argp);
|
||||||
|
argp++;
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
putc('%');
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
radix = 10;
|
||||||
|
sign = true;
|
||||||
|
argp = serial_printf_number(argp, length, sign, radix);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
radix = 10;
|
||||||
|
sign = false;
|
||||||
|
argp = serial_printf_number(argp, length, sign, radix);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
case 'p':
|
||||||
|
radix = 16;
|
||||||
|
sign = false;
|
||||||
|
argp = serial_printf_number(argp, length, sign, radix);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
radix = 8;
|
||||||
|
sign = false;
|
||||||
|
argp = serial_printf_number(argp, length, sign, radix);
|
||||||
|
break;
|
||||||
|
case 'f': {
|
||||||
|
// Handle floating-point numbers
|
||||||
|
double* dargp = (double*)argp;
|
||||||
|
double d = *(double*)dargp;
|
||||||
|
char buffer[64];
|
||||||
|
dtostrf(d, buffer, 6); // Default precision: 6
|
||||||
|
serial_puts(buffer);
|
||||||
|
argp += 2; // Incrementing by 2 to move past the double argument
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state = PRINTF_STATE_START;
|
||||||
|
length = PRINTF_LENGTH_START;
|
||||||
|
radix = 10;
|
||||||
|
sign = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
serial_puts("\r\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
#ifndef INCLUDE_SERIAL_H
|
// Serial I/O driver header
|
||||||
#define INCLUDE_SERIAL_H
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef SERIAL_H
|
||||||
|
#define SERIAL_H
|
||||||
|
|
||||||
#define PORT 0x3f8 //COM1
|
#define PORT 0x3f8 //COM1
|
||||||
|
|
||||||
@@ -8,5 +13,6 @@ int is_transmit_empty();
|
|||||||
void write_serial(const char a);
|
void write_serial(const char a);
|
||||||
void serial_puts(const char* str);
|
void serial_puts(const char* str);
|
||||||
void log(const char* str, const int errlevel);
|
void log(const char* str, const int errlevel);
|
||||||
|
void serial_printf(int errlevel, const char* fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
// Programmable Interval Timer channel 0 driver
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
@@ -6,11 +11,18 @@ volatile unsigned long global_ticks = 0;
|
|||||||
void timer_handler()
|
void timer_handler()
|
||||||
{
|
{
|
||||||
global_ticks++;
|
global_ticks++;
|
||||||
|
if (global_ticks % 20 == 0)
|
||||||
|
{
|
||||||
|
draw_cursor(white);
|
||||||
|
} else if (global_ticks % 20 == 10) {
|
||||||
|
erase_cursor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_install()
|
void timer_install()
|
||||||
{
|
{
|
||||||
irq_install_handler(0, timer_handler);
|
irq_install_handler(0, timer_handler);
|
||||||
|
printf("[timer] initialized, starting g_ticks...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void delay(int ticks)
|
void delay(int ticks)
|
||||||
|
|||||||
BIN
src/initrd/flower.bmp
Normal file
BIN
src/initrd/flower.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
1
src/initrd/hello.bf
Normal file
1
src/initrd/hello.bf
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-[------->+<]>-.-[->+++++<]>++.+++++++..+++.[--->+<]>-----.---[->+++<]>.-[--->+<]>---.+++.------.--------.
|
||||||
1
src/initrd/hello.txt
Normal file
1
src/initrd/hello.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
hello, ramdisk world!
|
||||||
BIN
src/initrd/hibou.bmp
Normal file
BIN
src/initrd/hibou.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 192 KiB |
BIN
src/initrd/red.bmp
Normal file
BIN
src/initrd/red.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
src/initrd/smiley.bmp
Normal file
BIN
src/initrd/smiley.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
8
src/initrd/stuff/nice.txt
Normal file
8
src/initrd/stuff/nice.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Subfolder support!
|
||||||
|
|
||||||
|
I am making a bit of scurity improvements but clearly it has no meaing here.
|
||||||
|
The real meanng is the tellin of the Genesis; a true work of art. So many
|
||||||
|
cool stuff here!! Look, there are functions, comands, bits and bytes, conditions,
|
||||||
|
and lgorithms. What a fantastic world! But after all it stays formless and empty.
|
||||||
|
|
||||||
|
1:5:1 1:1:1 7:8:1 1:7:3 1:4:3 2:1:2
|
||||||
37
src/initrd/welcome.txt
Normal file
37
src/initrd/welcome.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
***********************
|
||||||
|
* Welcome to BlankOS! *
|
||||||
|
***********************
|
||||||
|
|
||||||
|
Congratulations, you've entered my small world!
|
||||||
|
|
||||||
|
You can try all the commands, try tweaking stuff like explained
|
||||||
|
in the DEVELOPERS.md file, and even contribute if you got the
|
||||||
|
guts. lol.
|
||||||
|
|
||||||
|
Don't look too much at the code, it's badly designed, but hey,
|
||||||
|
that's my first OS project so I find it kinda cool.
|
||||||
|
|
||||||
|
There's no paging, ring 3, processes... I am not smart enough
|
||||||
|
for all this modern stuff. Let's keep it simple and stay in
|
||||||
|
ring0, without processes, maybe one day there'll be more
|
||||||
|
advanced features, but not today.
|
||||||
|
|
||||||
|
** Why am I doing this?
|
||||||
|
|
||||||
|
I wanted to explore the world of low-level programing.
|
||||||
|
As I had only 1 year of experience in C, it was super challenging
|
||||||
|
especially at the beginning, and I needed much time to understand
|
||||||
|
even the most basic things around OSDev.
|
||||||
|
|
||||||
|
I'll backup the project on archival media once it'll be at a good
|
||||||
|
enough point; I think it's cool to leave a trace of my passage on
|
||||||
|
Earth.
|
||||||
|
|
||||||
|
** Easter eggs
|
||||||
|
|
||||||
|
To make the exploration a bit funnier, I hid some easter eggs
|
||||||
|
around. You can try to find them if you have time to lose.
|
||||||
|
|
||||||
|
** Ravtzn
|
||||||
|
|
||||||
|
Jub xabjf? Znlor fbzrguvat'f uvqqra va gurer...
|
||||||
@@ -1,20 +1,10 @@
|
|||||||
|
// Global descriptor table setup
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
struct gdt_entry
|
|
||||||
{
|
|
||||||
unsigned short limit_low;
|
|
||||||
unsigned short base_low;
|
|
||||||
unsigned char base_middle;
|
|
||||||
unsigned char access;
|
|
||||||
unsigned char granularity;
|
|
||||||
unsigned char base_high;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct gdt_ptr
|
|
||||||
{
|
|
||||||
unsigned short limit;
|
|
||||||
unsigned int base;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct gdt_entry gdt[3];
|
struct gdt_entry gdt[3];
|
||||||
struct gdt_ptr gp;
|
struct gdt_ptr gp;
|
||||||
@@ -41,8 +31,14 @@ void gdt_install()
|
|||||||
|
|
||||||
gdt_set_gate(0, 0, 0, 0, 0);
|
gdt_set_gate(0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Ring 0 code + data
|
||||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
|
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
|
||||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
|
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
|
||||||
|
|
||||||
|
// Ring 3
|
||||||
|
//gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
|
||||||
|
//gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
|
||||||
|
|
||||||
gdt_flush();
|
gdt_flush();
|
||||||
|
printf("[kernel] GDT gates set (ring 0), gdt=0x%x\n", (unsigned int)&gdt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,28 @@
|
|||||||
|
// Global descriptor table setup header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#ifndef GDT_H
|
#ifndef GDT_H
|
||||||
#define GDT_H
|
#define GDT_H
|
||||||
|
|
||||||
void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran);
|
struct gdt_entry
|
||||||
|
{
|
||||||
|
unsigned short limit_low;
|
||||||
|
unsigned short base_low;
|
||||||
|
unsigned char base_middle;
|
||||||
|
unsigned char access;
|
||||||
|
unsigned char granularity;
|
||||||
|
unsigned char base_high;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct gdt_ptr
|
||||||
|
{
|
||||||
|
unsigned short limit;
|
||||||
|
unsigned int base;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran);
|
||||||
void gdt_install();
|
void gdt_install();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
|
// Interrupt descriptor table setup
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
struct idt_entry
|
|
||||||
{
|
|
||||||
unsigned short base_lo;
|
|
||||||
unsigned short sel;
|
|
||||||
unsigned char always0;
|
|
||||||
unsigned char flags;
|
|
||||||
unsigned short base_hi;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct idt_ptr
|
|
||||||
{
|
|
||||||
unsigned short limit;
|
|
||||||
unsigned int base;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct idt_entry idt[256];
|
struct idt_entry idt[256];
|
||||||
struct idt_ptr idtp;
|
struct idt_ptr idtp;
|
||||||
@@ -39,4 +30,5 @@ void idt_install()
|
|||||||
memset(&idt, 0, sizeof(struct idt_entry)*256);
|
memset(&idt, 0, sizeof(struct idt_entry)*256);
|
||||||
|
|
||||||
idt_load();
|
idt_load();
|
||||||
|
printf("[kernel] loaded IDT at idt=0x%x\n", (unsigned int)&idt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,27 @@
|
|||||||
|
// Interrupt descriptor table setup header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#ifndef IDT_H
|
#ifndef IDT_H
|
||||||
#define IDT_H
|
#define IDT_H
|
||||||
|
|
||||||
void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags);
|
struct idt_entry
|
||||||
|
{
|
||||||
|
unsigned short base_lo;
|
||||||
|
unsigned short sel;
|
||||||
|
unsigned char always0;
|
||||||
|
unsigned char flags;
|
||||||
|
unsigned short base_hi;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct idt_ptr
|
||||||
|
{
|
||||||
|
unsigned short limit;
|
||||||
|
unsigned int base;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags);
|
||||||
void idt_install();
|
void idt_install();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
176
src/kernel/initrd.c
Normal file
176
src/kernel/initrd.c
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// Initial TAR ramdisk kernel module
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "initrd.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
static unsigned int octal_to_int(const char* str, size_t size)
|
||||||
|
{
|
||||||
|
unsigned int result = 0;
|
||||||
|
while (*str && size-- > 0)
|
||||||
|
{
|
||||||
|
result = (result << 3) | (*str - '0');
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tar_parse_size(const char* in)
|
||||||
|
{
|
||||||
|
uint32_t size = 0;
|
||||||
|
while (*in >= '0' && *in <= '7')
|
||||||
|
{
|
||||||
|
size = (size*8) + (*in - '0');
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tar_find_file(uint8_t *tar_start, const char* filename)
|
||||||
|
{
|
||||||
|
uint8_t *ptr = tar_start;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
tar_header_t *header = (tar_header_t*)ptr;
|
||||||
|
|
||||||
|
if (header->filename[0] == '\0')
|
||||||
|
{
|
||||||
|
puts("[tar] EOF\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int filesize = octal_to_int(header->size, 11);
|
||||||
|
|
||||||
|
if (strcmp(header->filename, filename) == 0)
|
||||||
|
{
|
||||||
|
printf("[tar] found file '%s', size=%u bytes\n", header->filename, filesize);
|
||||||
|
|
||||||
|
uint8_t *file_data = ptr+TAR_BLOCK_SIZE;
|
||||||
|
printf("[tar] content of '%s':\n", filename);
|
||||||
|
for (unsigned int i=0; i<filesize; i++)
|
||||||
|
{
|
||||||
|
putc(file_data[i]);
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += TAR_BLOCK_SIZE + ((filesize + TAR_BLOCK_SIZE-1) / TAR_BLOCK_SIZE) * TAR_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[tar] file '%s' not found\n", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls_initrd(uint8_t* initrd, int verbose)
|
||||||
|
{
|
||||||
|
tar_header_t *header = (tar_header_t*)initrd;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
puts("Size Type Filename\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (header->filename[0] != '\0')
|
||||||
|
{
|
||||||
|
if (!verbose)
|
||||||
|
{
|
||||||
|
printf("%s\n", header->filename);
|
||||||
|
} else {
|
||||||
|
printf("%7d\t%c\t %s\n", (int)header->size, header->typeflag, header->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size = tar_parse_size(header->size);
|
||||||
|
uint32_t next_file_offset = ((size+TAR_BLOCK_SIZE-1)/TAR_BLOCK_SIZE)*TAR_BLOCK_SIZE;
|
||||||
|
header = (tar_header_t*)((uint8_t*)header + next_file_offset + TAR_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cat_initrd(uint8_t* initrd, const char* filename)
|
||||||
|
{
|
||||||
|
tar_header_t *header = (tar_header_t*)initrd;
|
||||||
|
|
||||||
|
while (header->filename[0] != '\0')
|
||||||
|
{
|
||||||
|
if (strcmp(header->filename, filename) == 0)
|
||||||
|
{
|
||||||
|
uint32_t size = tar_parse_size(header->size);
|
||||||
|
uint8_t* file_content = (uint8_t*)header + 512;
|
||||||
|
|
||||||
|
for (uint32_t i=0; i<size; i++) putc(file_content[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t next_file_offset = ((tar_parse_size(header->size)+TAR_BLOCK_SIZE-1)/TAR_BLOCK_SIZE)*TAR_BLOCK_SIZE;
|
||||||
|
header = (tar_header_t*)((uint8_t*)header + next_file_offset + TAR_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("File '%s' not found\n", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tar_file_to_buffer(uint8_t* initrd, const char* filename, char* buffer)
|
||||||
|
{
|
||||||
|
uint8_t* current_block = initrd;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (current_block[0] == '\0')
|
||||||
|
{
|
||||||
|
//puts("[tar] EOF\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* file_name = (const char*)current_block;
|
||||||
|
uint32_t file_size = tar_parse_size((const char*)(current_block+124));
|
||||||
|
|
||||||
|
if (strcmp(file_name, filename) == 0)
|
||||||
|
{
|
||||||
|
uint8_t* file_data = current_block + TAR_BLOCK_SIZE;
|
||||||
|
if (sizeof(buffer) >= sizeof(file_data))
|
||||||
|
{
|
||||||
|
memcpy(buffer, file_data, file_size);
|
||||||
|
buffer[file_size] = '\0';
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
printf("Invalid destination buffer size %d bytes < %d bytes\n", sizeof(buffer), sizeof(file_data));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t total_size = ((file_size + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE) * TAR_BLOCK_SIZE;
|
||||||
|
current_block += TAR_BLOCK_SIZE + total_size;
|
||||||
|
}
|
||||||
|
printf("[tar] file '%s' not found\n", filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tar_get_file_size(uint8_t* initrd, const char* filename)
|
||||||
|
{
|
||||||
|
uint8_t* current_block = initrd;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (current_block[0] == '\0')
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* file_name = (const char*)current_block;
|
||||||
|
uint32_t file_size = tar_parse_size((const char*)(current_block+124));
|
||||||
|
|
||||||
|
if (strcmp(file_name, filename) == 0)
|
||||||
|
{
|
||||||
|
return file_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t total_size = ((file_size + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE) * TAR_BLOCK_SIZE;
|
||||||
|
current_block += TAR_BLOCK_SIZE + total_size;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
39
src/kernel/initrd.h
Normal file
39
src/kernel/initrd.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Initial TAR ramdisk kernel module header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef INITRD_H
|
||||||
|
#define INITRD_H
|
||||||
|
|
||||||
|
#define TAR_BLOCK_SIZE 512
|
||||||
|
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char filename[100];
|
||||||
|
char mode[8];
|
||||||
|
char owner[8];
|
||||||
|
char group[8];
|
||||||
|
char size[12];
|
||||||
|
char mtime[12];
|
||||||
|
char checksum[8];
|
||||||
|
char typeflag;
|
||||||
|
char linkname[100];
|
||||||
|
char magic[6];
|
||||||
|
char version[2];
|
||||||
|
char uname[32];
|
||||||
|
char gname[32];
|
||||||
|
char devmajor[8];
|
||||||
|
char devminor[8];
|
||||||
|
char prefix[155];
|
||||||
|
} tar_header_t;
|
||||||
|
|
||||||
|
void tar_find_file(uint8_t *tar_start, const char* filename);
|
||||||
|
void ls_initrd(uint8_t* initrd, int verbose);
|
||||||
|
void cat_initrd(uint8_t* initrd, const char* filename);
|
||||||
|
int tar_file_to_buffer(uint8_t* initrd, const char* filename, char* buffer);
|
||||||
|
uint32_t tar_get_file_size(uint8_t* initrd, const char* filename);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
#ifndef INCLUDE_IO_H
|
// Raw CPU port I/O kernel module header
|
||||||
#define INCLUDE_IO_H
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../libc/stdint.h"
|
#ifndef IO_H
|
||||||
|
#define IO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void outb(unsigned short port, unsigned char data);
|
void outb(unsigned short port, unsigned char data);
|
||||||
unsigned char inb(unsigned short port);
|
unsigned char inb(unsigned short port);
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
; Raw CPU port I/O kernel module
|
||||||
|
; Author: xamidev
|
||||||
|
; Licensed under the Unlicense. See the repo below.
|
||||||
|
; https://github.com/xamidev/blankos
|
||||||
|
|
||||||
global outb
|
global outb
|
||||||
|
|
||||||
outb:
|
outb:
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
|
// Interrupt Requests setup
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
extern void irq0();
|
extern void irq0();
|
||||||
extern void irq1();
|
extern void irq1();
|
||||||
@@ -69,6 +75,7 @@ void irq_install()
|
|||||||
idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E);
|
idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E);
|
||||||
idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
|
idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
|
||||||
idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
|
idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
|
||||||
|
printf("[kernel] installed irq 0-15\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_handler(struct regs *r)
|
void irq_handler(struct regs *r)
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
// Interrupt service routines setup
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
@@ -37,7 +42,6 @@ extern void isr31();
|
|||||||
|
|
||||||
void isr_install()
|
void isr_install()
|
||||||
{
|
{
|
||||||
|
|
||||||
idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
|
idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
|
||||||
idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E);
|
idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E);
|
||||||
idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E);
|
idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E);
|
||||||
@@ -70,6 +74,7 @@ void isr_install()
|
|||||||
idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
|
idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E);
|
||||||
idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
|
idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E);
|
||||||
idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
|
idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
|
||||||
|
printf("[kernel] set ISRs 0-31\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
char *exception_messages[] =
|
char *exception_messages[] =
|
||||||
@@ -111,8 +116,7 @@ void fault_handler(struct regs *r)
|
|||||||
{
|
{
|
||||||
if (r->int_no < 32)
|
if (r->int_no < 32)
|
||||||
{
|
{
|
||||||
printf("\n\n*** [Kernel panic - %s Exception] ***\nInterrupt error code %u\nedi: %x esi: %u ebp: %u esp: %u\nebx: %u edx: %u ecx: %u eax: %u\neip: %x cs:%x eflags: %x ss: %x\ngs: %x fs: %x es: %x ds: %x\nHalting!\n", exception_messages[r->int_no], r->err_code, r->edi, r->esi, r->ebp, r->esp, r->ebx, r->edx, r->ecx, r->eax, r->eip, r->cs, r->eflags, r->ss, r->gs, r->fs, r->es, r->ds);
|
colorprintf(white, red, "\n\n*** [Kernel panic - %s Exception] ***\nInterrupt error code %u\nedi: 0x%x\nesi: 0x%x\nebp: 0x%x\nesp: 0x%x\neip: 0x%x\neax: 0x%x\nebx: 0x%x\necx: 0x%x\nedx: 0x%x\ncs: 0x%x\neflags: 0x%x\nss: 0x%x\ngs: 0x%x\nfs: 0x%x\nes: 0x%x\nds: 0x%x\nHalting!\n", exception_messages[r->int_no], r->err_code, r->edi, r->esi, r->ebp, r->esp, r->eip, r->eax, r->ebx, r->ecx, r->edx, r->cs, r->eflags, r->ss, r->gs, r->fs, r->es, r->ds);
|
||||||
for (;;);
|
for (;;);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
64
src/kernel/kheap.c
Normal file
64
src/kernel/kheap.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Kernel heap management
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "kheap.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
// Free list allocator
|
||||||
|
|
||||||
|
static uint8_t heap[HEAP_SIZE];
|
||||||
|
static block_t* free_list = NULL;
|
||||||
|
|
||||||
|
void init_alloc()
|
||||||
|
{
|
||||||
|
free_list = (block_t*)heap;
|
||||||
|
free_list->size = HEAP_SIZE-sizeof(block_t);
|
||||||
|
free_list->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* malloc(size_t size)
|
||||||
|
{
|
||||||
|
block_t* prev = NULL;
|
||||||
|
block_t* curr = free_list;
|
||||||
|
|
||||||
|
while (curr != NULL)
|
||||||
|
{
|
||||||
|
if (curr->size >= size)
|
||||||
|
{
|
||||||
|
if (curr->size > (size_t)(size + sizeof(block_t)))
|
||||||
|
{
|
||||||
|
block_t* new_block = (block_t*)((uint8_t*)curr + sizeof(block_t) + size);
|
||||||
|
new_block->size = curr->size - size - sizeof(block_t);
|
||||||
|
new_block->next = curr->next;
|
||||||
|
curr->size = size;
|
||||||
|
curr->next = new_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev == NULL)
|
||||||
|
{
|
||||||
|
free_list = curr->next;
|
||||||
|
} else {
|
||||||
|
prev->next = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)((uint8_t*)curr + sizeof(block_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = curr;
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr)
|
||||||
|
{
|
||||||
|
if (ptr == NULL) return;
|
||||||
|
|
||||||
|
block_t* block_to_free = (block_t*)((uint8_t*)ptr - sizeof(block_t));
|
||||||
|
block_to_free->next = free_list;
|
||||||
|
free_list = block_to_free;
|
||||||
|
}
|
||||||
25
src/kernel/kheap.h
Normal file
25
src/kernel/kheap.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Kernel heap management header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef KHEAP_H
|
||||||
|
#define KHEAP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
typedef struct block
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
struct block* next;
|
||||||
|
} block_t;
|
||||||
|
|
||||||
|
#define HEAP_SIZE 1024*1024 // 1MB malloc-able
|
||||||
|
|
||||||
|
|
||||||
|
void init_alloc();
|
||||||
|
void* malloc(size_t size);
|
||||||
|
void free(void* ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,46 +1,125 @@
|
|||||||
|
// Kernel entry point
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../drivers/serial.h"
|
#include "../drivers/serial.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
//#include <stdarg.h>
|
#include "../drivers/ata.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
#include "kmain.h"
|
||||||
|
#include "multiboot2.h"
|
||||||
|
#include "kheap.h"
|
||||||
|
#include "initrd.h"
|
||||||
|
#include "../programs/programs.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
|
||||||
char* ascii_title =
|
void kmain(multiboot2_info *mb_info)
|
||||||
"\n"
|
|
||||||
" oooooooooo o888 oooo ooooooo oooooooo8\n"
|
|
||||||
" 888 888 888 ooooooo oo oooooo 888 ooooo o888 888o 888 \n"
|
|
||||||
" 888oooo88 888 ooooo888 888 888 888o888 888 888 888oooooo \n"
|
|
||||||
" 888 888 888 888 888 888 888 8888 88o 888o o888 888\n"
|
|
||||||
" o888ooo888 o888o 88ooo88 8o o888o o888o o888o o888o 88ooo88 o88oooo888\n\n"
|
|
||||||
" --------------------------------- v0.3.45 --------------------------------\n\n";
|
|
||||||
|
|
||||||
int kmain(int retvalue)
|
|
||||||
{
|
{
|
||||||
|
multiboot2_tag_framebuffer *fb_info = NULL;
|
||||||
|
struct multiboot_tag_mmap *mmap_tag = NULL;
|
||||||
|
struct multiboot_tag_module *initrd_module = NULL;
|
||||||
|
|
||||||
|
uint8_t *tags = mb_info->tags;
|
||||||
|
while (1) {
|
||||||
|
uint32_t tag_type = *((uint32_t*) tags);
|
||||||
|
uint32_t tag_size = *((uint32_t*) (tags + 4));
|
||||||
|
|
||||||
|
if (tag_type == 0) break;
|
||||||
|
if (tag_type == MULTIBOOT_TAG_TYPE_FRAMEBUFFER) {
|
||||||
|
fb_info = (multiboot2_tag_framebuffer*) tags;
|
||||||
|
}
|
||||||
|
if (tag_type == MULTIBOOT_TAG_TYPE_MMAP) {
|
||||||
|
mmap_tag = (struct multiboot_tag_mmap*) tags;
|
||||||
|
}
|
||||||
|
if (tag_type == MULTIBOOT_TAG_TYPE_MODULE) {
|
||||||
|
initrd_module = (struct multiboot_tag_module*) tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
tags += ((tag_size + 7) & ~7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fb_info) { // fb setup
|
||||||
|
framebuffer = (uint32_t *)(uintptr_t) fb_info->framebuffer_addr;
|
||||||
|
|
||||||
|
uint32_t width = fb_info->framebuffer_width;
|
||||||
|
uint32_t height = fb_info->framebuffer_height;
|
||||||
|
bpp = fb_info->framebuffer_bpp;
|
||||||
|
pitch = fb_info->framebuffer_pitch;
|
||||||
|
|
||||||
|
//8x16 font, not padded
|
||||||
|
VGA_WIDTH = width/8;
|
||||||
|
VGA_HEIGHT = height/16;
|
||||||
|
serial_printf(3, "VGA_WIDTH=%d, VGA_HEIGHT=%d", VGA_WIDTH, VGA_HEIGHT);
|
||||||
|
scanline = width * (bpp/8);
|
||||||
|
|
||||||
|
serial_printf(3, "Framebuffer Address: 0x%x", fb_info->framebuffer_addr);
|
||||||
|
serial_printf(3, "Framebuffer Width: %u", fb_info->framebuffer_width);
|
||||||
|
serial_printf(3, "Framebuffer Height: %u", fb_info->framebuffer_height);
|
||||||
|
serial_printf(3, "Framebuffer Pitch: %u", fb_info->framebuffer_pitch);
|
||||||
|
serial_printf(3, "Framebuffer BPP: %u", fb_info->framebuffer_bpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[kernel] multiboot2 info at 0x%x, size=%u\n", mb_info, mb_info->total_size);
|
||||||
|
printf("[kernel] framebuffer discovered at 0x%x\n", (unsigned int)fb_info->framebuffer_addr);
|
||||||
|
printf("[kernel] fb0: width=%u, height=%u, pitch=%u, bpp=%u\n", fb_info->framebuffer_width, fb_info->framebuffer_height, fb_info->framebuffer_pitch, fb_info->framebuffer_bpp);
|
||||||
|
|
||||||
|
if (mmap_tag) // memmap debug print
|
||||||
|
{
|
||||||
|
puts("[kernel] found memory map tag by multiboot2\n");
|
||||||
|
struct multiboot_mmap_entry *mmap = mmap_tag->entries;
|
||||||
|
|
||||||
|
while ((uint8_t*) mmap < tags + mmap_tag->size)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (mmap->addr != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
serial_printf(3, "base addr=0x%x%x, length=0x%x%x, type=%u",
|
||||||
|
(uint32_t) (mmap->addr >> 32),
|
||||||
|
(uint32_t) (mmap->addr & 0xFFFFFFFF),
|
||||||
|
(uint32_t) (mmap->len >> 32),
|
||||||
|
(uint32_t) (mmap->len & 0xFFFFFFFF),
|
||||||
|
mmap->type);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mmap = (struct multiboot_mmap_entry*) ((uint8_t*)mmap + mmap_tag->entry_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initrd_module) {
|
||||||
|
initrd_addr = initrd_module->mod_start;
|
||||||
|
|
||||||
|
uint32_t initrd_start = initrd_module->mod_start;
|
||||||
|
uint32_t initrd_end = initrd_module->mod_end;
|
||||||
|
uint32_t initrd_size = initrd_end - initrd_start;
|
||||||
|
|
||||||
|
printf("[kernel] TAR initrd module found at 0x%x, size=%u bytes\n", initrd_start, initrd_size);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
puts("[kernel] TAR initrd module not found\n");
|
||||||
|
}
|
||||||
|
|
||||||
init_serial();
|
init_serial();
|
||||||
log("serial connection established", 3);
|
|
||||||
gdt_install();
|
gdt_install();
|
||||||
log("initialized GDT entries", 2);
|
|
||||||
idt_install();
|
idt_install();
|
||||||
log("initialized IDT", 2);
|
|
||||||
isr_install();
|
isr_install();
|
||||||
log("initialized ISRs", 2);
|
|
||||||
irq_install();
|
irq_install();
|
||||||
__asm__ __volatile__("sti");
|
__asm__ __volatile__("sti");
|
||||||
log("initialized IRQs", 2),
|
|
||||||
|
|
||||||
log("kernel started", 2);
|
init_alloc();
|
||||||
|
void* ptr1 = malloc(256);
|
||||||
clear();
|
void* ptr2 = malloc(512);
|
||||||
|
printf("[debug] malloc test ptr1=0x%x, ptr2=0x%x\n", (unsigned int)ptr1, (unsigned int)ptr2);
|
||||||
colorputs(ascii_title, 10);
|
free(ptr1); free(ptr2);
|
||||||
colorputs(" by @xamidev - star the repo for a cookie!\n\n", 14);
|
|
||||||
|
|
||||||
// TODO: Grub modules to load programs
|
|
||||||
|
|
||||||
timer_install();
|
timer_install();
|
||||||
keyboard_install();
|
keyboard_install();
|
||||||
|
printf("[kernel] spawning shell...\n");
|
||||||
shell_install();
|
shell_install();
|
||||||
|
|
||||||
return retvalue;
|
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/kernel/kmain.h
Normal file
44
src/kernel/kmain.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Kernel entry point header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef KMAIN_H
|
||||||
|
#define KMAIN_H
|
||||||
|
|
||||||
|
#define BLANK_VERSION "0.3.123-alpha"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t size;
|
||||||
|
uint64_t framebuffer_addr;
|
||||||
|
uint32_t framebuffer_pitch;
|
||||||
|
uint32_t framebuffer_width;
|
||||||
|
uint32_t framebuffer_height;
|
||||||
|
uint8_t framebuffer_bpp;
|
||||||
|
uint8_t framebuffer_type;
|
||||||
|
uint16_t reserved;
|
||||||
|
} multiboot2_tag_framebuffer;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t total_size;
|
||||||
|
uint32_t reserved;
|
||||||
|
uint8_t tags[0];
|
||||||
|
} multiboot2_info;
|
||||||
|
|
||||||
|
unsigned int g_multiboot_info_address;
|
||||||
|
|
||||||
|
uint32_t* framebuffer;
|
||||||
|
int scanline;
|
||||||
|
uint32_t initrd_addr;
|
||||||
|
|
||||||
|
// in characters, not pixels
|
||||||
|
uint32_t VGA_WIDTH;
|
||||||
|
uint32_t VGA_HEIGHT;
|
||||||
|
|
||||||
|
uint32_t bpp;
|
||||||
|
uint32_t pitch;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,25 +1,59 @@
|
|||||||
|
; Kernel loader assembly stub and multiboot2 header
|
||||||
|
; Author: xamidev
|
||||||
|
; Licensed under the Unlicense. See the repo below.
|
||||||
|
; https://github.com/xamidev/blankos
|
||||||
|
|
||||||
global loader
|
global loader
|
||||||
|
|
||||||
section .__mbHeader
|
section .multiboot_header
|
||||||
|
|
||||||
align 0x4
|
mb_start:
|
||||||
section .text:
|
align 8
|
||||||
|
|
||||||
MAGIC_NUMBER equ 0x1BADB002 ; multiboot magic
|
; ASM macros
|
||||||
FLAGS equ 0x0
|
|
||||||
CHECKSUM equ -MAGIC_NUMBER
|
|
||||||
KERNEL_STACK_SIZE equ 4096
|
|
||||||
|
|
||||||
dd MAGIC_NUMBER
|
MAGIC_NUMBER equ 0xe85250d6 ; multiboot2 magic
|
||||||
|
FLAGS equ 0x0 ; 32-bit protected mode for i386
|
||||||
|
HEADER_LEN equ mb_end-mb_start
|
||||||
|
CHECKSUM equ -(MAGIC_NUMBER + FLAGS + HEADER_LEN)
|
||||||
|
|
||||||
|
; Multiboot 2 header, according to specification (16bytes)
|
||||||
|
|
||||||
|
dd MAGIC_NUMBER ; dd = 4 bytes = 32bits = u32
|
||||||
dd FLAGS
|
dd FLAGS
|
||||||
|
dd HEADER_LEN
|
||||||
dd CHECKSUM
|
dd CHECKSUM
|
||||||
|
|
||||||
|
; Tags? (28bytes)
|
||||||
|
|
||||||
|
; Tag 1 : set graphics mode (only recommended, can be overriden by GRUB)
|
||||||
|
align 8
|
||||||
|
dw 5 ; 2
|
||||||
|
dw 0 ; 2
|
||||||
|
dd 20 ; 4
|
||||||
|
dd 1920 ; 4
|
||||||
|
dd 1080 ; 4
|
||||||
|
dd 32 ; 4
|
||||||
|
|
||||||
|
; End of tags
|
||||||
|
|
||||||
|
align 8
|
||||||
|
dw 0 ; 2
|
||||||
|
dw 0 ; 2
|
||||||
|
dd 8 ; 4
|
||||||
|
|
||||||
|
; End of Multiboot 2 header
|
||||||
|
mb_end:
|
||||||
|
|
||||||
|
section .text:
|
||||||
|
|
||||||
|
KERNEL_STACK_SIZE equ 4096
|
||||||
extern kmain
|
extern kmain
|
||||||
|
|
||||||
loader:
|
loader:
|
||||||
|
mov esp, kernel_stack + KERNEL_STACK_SIZE
|
||||||
cli
|
cli
|
||||||
; mov eax, 0xCAFEBABE
|
push ebx
|
||||||
push dword 42
|
|
||||||
call kmain
|
call kmain
|
||||||
|
|
||||||
.loop:
|
.loop:
|
||||||
@@ -48,225 +82,55 @@ idt_load:
|
|||||||
lidt [idtp]
|
lidt [idtp]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
global isr0
|
%macro ISR_NOERRCODE 1
|
||||||
global isr1
|
global isr%1
|
||||||
global isr2
|
isr%1:
|
||||||
global isr3
|
|
||||||
global isr4
|
|
||||||
global isr5
|
|
||||||
global isr6
|
|
||||||
global isr7
|
|
||||||
global isr8
|
|
||||||
global isr9
|
|
||||||
global isr10
|
|
||||||
global isr11
|
|
||||||
global isr12
|
|
||||||
global isr13
|
|
||||||
global isr14
|
|
||||||
global isr15
|
|
||||||
global isr16
|
|
||||||
global isr17
|
|
||||||
global isr18
|
|
||||||
global isr19
|
|
||||||
global isr20
|
|
||||||
global isr21
|
|
||||||
global isr22
|
|
||||||
global isr23
|
|
||||||
global isr24
|
|
||||||
global isr25
|
|
||||||
global isr26
|
|
||||||
global isr27
|
|
||||||
global isr28
|
|
||||||
global isr29
|
|
||||||
global isr30
|
|
||||||
global isr31
|
|
||||||
|
|
||||||
; Interrupt service routine exceptions
|
|
||||||
isr0:
|
|
||||||
cli
|
cli
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 0
|
push byte %1
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
%endmacro
|
||||||
|
|
||||||
isr1:
|
%macro ISR_ERRCODE 1
|
||||||
|
global isr%1
|
||||||
|
isr%1:
|
||||||
cli
|
cli
|
||||||
push byte 0
|
push byte %1
|
||||||
push byte 1
|
|
||||||
jmp isr_common_stub
|
jmp isr_common_stub
|
||||||
|
%endmacro
|
||||||
|
|
||||||
isr2:
|
ISR_NOERRCODE 0
|
||||||
cli
|
ISR_NOERRCODE 1
|
||||||
push byte 0
|
ISR_NOERRCODE 2
|
||||||
push byte 2
|
ISR_NOERRCODE 3
|
||||||
jmp isr_common_stub
|
ISR_NOERRCODE 4
|
||||||
|
ISR_NOERRCODE 5
|
||||||
isr3:
|
ISR_NOERRCODE 6
|
||||||
cli
|
ISR_NOERRCODE 7
|
||||||
push byte 0
|
ISR_ERRCODE 8
|
||||||
push byte 3
|
ISR_NOERRCODE 9
|
||||||
jmp isr_common_stub
|
ISR_ERRCODE 10
|
||||||
|
ISR_ERRCODE 11
|
||||||
isr4:
|
ISR_ERRCODE 12
|
||||||
cli
|
ISR_ERRCODE 13
|
||||||
push byte 0
|
ISR_ERRCODE 14
|
||||||
push byte 4
|
ISR_NOERRCODE 15
|
||||||
jmp isr_common_stub
|
ISR_NOERRCODE 16
|
||||||
|
ISR_NOERRCODE 17
|
||||||
isr5:
|
ISR_NOERRCODE 18
|
||||||
cli
|
ISR_NOERRCODE 19
|
||||||
push byte 0
|
ISR_NOERRCODE 20
|
||||||
push byte 5
|
ISR_NOERRCODE 21
|
||||||
jmp isr_common_stub
|
ISR_NOERRCODE 22
|
||||||
|
ISR_NOERRCODE 23
|
||||||
isr6:
|
ISR_NOERRCODE 24
|
||||||
cli
|
ISR_NOERRCODE 25
|
||||||
push byte 0
|
ISR_NOERRCODE 26
|
||||||
push byte 6
|
ISR_NOERRCODE 27
|
||||||
jmp isr_common_stub
|
ISR_NOERRCODE 28
|
||||||
|
ISR_NOERRCODE 29
|
||||||
isr7:
|
ISR_NOERRCODE 30
|
||||||
cli
|
ISR_NOERRCODE 31
|
||||||
push byte 0
|
|
||||||
push byte 7
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr8:
|
|
||||||
cli
|
|
||||||
push byte 8
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr9:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 9
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr10:
|
|
||||||
cli
|
|
||||||
push byte 10
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr11:
|
|
||||||
cli
|
|
||||||
push byte 11
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr12:
|
|
||||||
cli
|
|
||||||
push byte 12
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr13:
|
|
||||||
cli
|
|
||||||
push byte 13
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr14:
|
|
||||||
cli
|
|
||||||
push byte 14
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr15:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 15
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr16:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 16
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr17:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 17
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr18:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 18
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr19:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 19
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr20:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 20
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr21:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 21
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr22:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 22
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr23:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 23
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr24:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 24
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr25:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 25
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr26:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 26
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr27:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 27
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr28:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 28
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr29:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 29
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr30:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 30
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
isr31:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 31
|
|
||||||
jmp isr_common_stub
|
|
||||||
|
|
||||||
extern fault_handler
|
extern fault_handler
|
||||||
|
|
||||||
@@ -294,118 +158,31 @@ isr_common_stub:
|
|||||||
add esp, 8
|
add esp, 8
|
||||||
iret
|
iret
|
||||||
|
|
||||||
global irq0
|
%macro IRQ 2
|
||||||
global irq1
|
global irq%1
|
||||||
global irq2
|
irq%1:
|
||||||
global irq3
|
|
||||||
global irq4
|
|
||||||
global irq5
|
|
||||||
global irq6
|
|
||||||
global irq7
|
|
||||||
global irq8
|
|
||||||
global irq9
|
|
||||||
global irq10
|
|
||||||
global irq11
|
|
||||||
global irq12
|
|
||||||
global irq13
|
|
||||||
global irq14
|
|
||||||
global irq15
|
|
||||||
|
|
||||||
irq0:
|
|
||||||
cli
|
cli
|
||||||
push byte 0
|
push byte 0
|
||||||
push byte 32
|
push byte %2
|
||||||
jmp irq_common_stub
|
jmp irq_common_stub
|
||||||
|
%endmacro
|
||||||
|
|
||||||
irq1:
|
IRQ 0, 32
|
||||||
cli
|
IRQ 1, 33
|
||||||
push byte 0
|
IRQ 2, 34
|
||||||
push byte 33
|
IRQ 3, 35
|
||||||
jmp irq_common_stub
|
IRQ 4, 36
|
||||||
|
IRQ 5, 37
|
||||||
irq2:
|
IRQ 6, 38
|
||||||
cli
|
IRQ 7, 39
|
||||||
push byte 0
|
IRQ 8, 40
|
||||||
push byte 34
|
IRQ 9, 41
|
||||||
jmp irq_common_stub
|
IRQ 10, 42
|
||||||
|
IRQ 11, 43
|
||||||
irq3:
|
IRQ 12, 44
|
||||||
cli
|
IRQ 13, 45
|
||||||
push byte 0
|
IRQ 14, 46
|
||||||
push byte 35
|
IRQ 15, 47
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq4:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 36
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq5:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 37
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq6:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 38
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq7:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 39
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq8:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 40
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq9:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 41
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq10:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 42
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq11:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 43
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq12:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 44
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq13:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 45
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq14:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 46
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
irq15:
|
|
||||||
cli
|
|
||||||
push byte 0
|
|
||||||
push byte 47
|
|
||||||
jmp irq_common_stub
|
|
||||||
|
|
||||||
extern irq_handler
|
extern irq_handler
|
||||||
|
|
||||||
@@ -435,6 +212,6 @@ irq_common_stub:
|
|||||||
|
|
||||||
section .bss
|
section .bss
|
||||||
align 4
|
align 4
|
||||||
|
|
||||||
|
resb KERNEL_STACK_SIZE
|
||||||
kernel_stack:
|
kernel_stack:
|
||||||
resb KERNEL_STACK_SIZE
|
|
||||||
mov esp, kernel_stack + KERNEL_STACK_SIZE
|
|
||||||
|
|||||||
417
src/kernel/multiboot2.h
Normal file
417
src/kernel/multiboot2.h
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
/* multiboot2.h - Multiboot 2 header file. */
|
||||||
|
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
|
||||||
|
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MULTIBOOT_HEADER
|
||||||
|
#define MULTIBOOT_HEADER 1
|
||||||
|
|
||||||
|
/* How many bytes from the start of the file we search for the header. */
|
||||||
|
#define MULTIBOOT_SEARCH 32768
|
||||||
|
#define MULTIBOOT_HEADER_ALIGN 8
|
||||||
|
|
||||||
|
/* The magic field should contain this. */
|
||||||
|
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
||||||
|
|
||||||
|
/* This should be in %eax. */
|
||||||
|
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
|
||||||
|
|
||||||
|
/* Alignment of multiboot modules. */
|
||||||
|
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||||
|
|
||||||
|
/* Alignment of the multiboot info structure. */
|
||||||
|
#define MULTIBOOT_INFO_ALIGN 0x00000008
|
||||||
|
|
||||||
|
/* Flags set in the ’flags’ member of the multiboot header. */
|
||||||
|
|
||||||
|
#define MULTIBOOT_TAG_ALIGN 8
|
||||||
|
#define MULTIBOOT_TAG_TYPE_END 0
|
||||||
|
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
|
||||||
|
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
|
||||||
|
#define MULTIBOOT_TAG_TYPE_MODULE 3
|
||||||
|
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
|
||||||
|
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
|
||||||
|
#define MULTIBOOT_TAG_TYPE_MMAP 6
|
||||||
|
#define MULTIBOOT_TAG_TYPE_VBE 7
|
||||||
|
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
|
||||||
|
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
|
||||||
|
#define MULTIBOOT_TAG_TYPE_APM 10
|
||||||
|
#define MULTIBOOT_TAG_TYPE_EFI32 11
|
||||||
|
#define MULTIBOOT_TAG_TYPE_EFI64 12
|
||||||
|
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
|
||||||
|
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
|
||||||
|
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
|
||||||
|
#define MULTIBOOT_TAG_TYPE_NETWORK 16
|
||||||
|
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
|
||||||
|
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
|
||||||
|
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
|
||||||
|
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
|
||||||
|
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
|
||||||
|
|
||||||
|
#define MULTIBOOT_HEADER_TAG_END 0
|
||||||
|
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
|
||||||
|
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
|
||||||
|
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
|
||||||
|
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
|
||||||
|
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
|
||||||
|
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
|
||||||
|
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
|
||||||
|
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
|
||||||
|
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
|
||||||
|
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
|
||||||
|
|
||||||
|
#define MULTIBOOT_ARCHITECTURE_I386 0
|
||||||
|
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
|
||||||
|
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
||||||
|
|
||||||
|
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
|
||||||
|
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
|
||||||
|
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
|
||||||
|
|
||||||
|
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||||
|
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||||
|
|
||||||
|
#ifndef ASM_FILE
|
||||||
|
|
||||||
|
typedef unsigned char multiboot_uint8_t;
|
||||||
|
typedef unsigned short multiboot_uint16_t;
|
||||||
|
typedef unsigned int multiboot_uint32_t;
|
||||||
|
typedef unsigned long long multiboot_uint64_t;
|
||||||
|
|
||||||
|
struct multiboot_header
|
||||||
|
{
|
||||||
|
/* Must be MULTIBOOT_MAGIC - see above. */
|
||||||
|
multiboot_uint32_t magic;
|
||||||
|
|
||||||
|
/* ISA */
|
||||||
|
multiboot_uint32_t architecture;
|
||||||
|
|
||||||
|
/* Total header length. */
|
||||||
|
multiboot_uint32_t header_length;
|
||||||
|
|
||||||
|
/* The above fields plus this one must equal 0 mod 2^32. */
|
||||||
|
multiboot_uint32_t checksum;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag_information_request
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t requests[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag_address
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t header_addr;
|
||||||
|
multiboot_uint32_t load_addr;
|
||||||
|
multiboot_uint32_t load_end_addr;
|
||||||
|
multiboot_uint32_t bss_end_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag_entry_address
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t entry_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag_console_flags
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t console_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag_framebuffer
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t width;
|
||||||
|
multiboot_uint32_t height;
|
||||||
|
multiboot_uint32_t depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag_module_align
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_header_tag_relocatable
|
||||||
|
{
|
||||||
|
multiboot_uint16_t type;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t min_addr;
|
||||||
|
multiboot_uint32_t max_addr;
|
||||||
|
multiboot_uint32_t align;
|
||||||
|
multiboot_uint32_t preference;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_color
|
||||||
|
{
|
||||||
|
multiboot_uint8_t red;
|
||||||
|
multiboot_uint8_t green;
|
||||||
|
multiboot_uint8_t blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_mmap_entry
|
||||||
|
{
|
||||||
|
multiboot_uint64_t addr;
|
||||||
|
multiboot_uint64_t len;
|
||||||
|
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||||
|
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||||
|
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
|
||||||
|
#define MULTIBOOT_MEMORY_NVS 4
|
||||||
|
#define MULTIBOOT_MEMORY_BADRAM 5
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t zero;
|
||||||
|
};
|
||||||
|
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
|
||||||
|
|
||||||
|
struct multiboot_tag
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_string
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
char string[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_module
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t mod_start;
|
||||||
|
multiboot_uint32_t mod_end;
|
||||||
|
char cmdline[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_basic_meminfo
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t mem_lower;
|
||||||
|
multiboot_uint32_t mem_upper;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_bootdev
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t biosdev;
|
||||||
|
multiboot_uint32_t slice;
|
||||||
|
multiboot_uint32_t part;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_mmap
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t entry_size;
|
||||||
|
multiboot_uint32_t entry_version;
|
||||||
|
struct multiboot_mmap_entry entries[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_vbe_info_block
|
||||||
|
{
|
||||||
|
multiboot_uint8_t external_specification[512];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_vbe_mode_info_block
|
||||||
|
{
|
||||||
|
multiboot_uint8_t external_specification[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_vbe
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
|
||||||
|
multiboot_uint16_t vbe_mode;
|
||||||
|
multiboot_uint16_t vbe_interface_seg;
|
||||||
|
multiboot_uint16_t vbe_interface_off;
|
||||||
|
multiboot_uint16_t vbe_interface_len;
|
||||||
|
|
||||||
|
struct multiboot_vbe_info_block vbe_control_info;
|
||||||
|
struct multiboot_vbe_mode_info_block vbe_mode_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_framebuffer_common
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
|
||||||
|
multiboot_uint64_t framebuffer_addr;
|
||||||
|
multiboot_uint32_t framebuffer_pitch;
|
||||||
|
multiboot_uint32_t framebuffer_width;
|
||||||
|
multiboot_uint32_t framebuffer_height;
|
||||||
|
multiboot_uint8_t framebuffer_bpp;
|
||||||
|
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
|
||||||
|
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
|
||||||
|
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
|
||||||
|
multiboot_uint8_t framebuffer_type;
|
||||||
|
multiboot_uint16_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_framebuffer
|
||||||
|
{
|
||||||
|
struct multiboot_tag_framebuffer_common common;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
multiboot_uint16_t framebuffer_palette_num_colors;
|
||||||
|
struct multiboot_color framebuffer_palette[0];
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
multiboot_uint8_t framebuffer_red_field_position;
|
||||||
|
multiboot_uint8_t framebuffer_red_mask_size;
|
||||||
|
multiboot_uint8_t framebuffer_green_field_position;
|
||||||
|
multiboot_uint8_t framebuffer_green_mask_size;
|
||||||
|
multiboot_uint8_t framebuffer_blue_field_position;
|
||||||
|
multiboot_uint8_t framebuffer_blue_mask_size;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_elf_sections
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t num;
|
||||||
|
multiboot_uint32_t entsize;
|
||||||
|
multiboot_uint32_t shndx;
|
||||||
|
char sections[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_apm
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint16_t version;
|
||||||
|
multiboot_uint16_t cseg;
|
||||||
|
multiboot_uint32_t offset;
|
||||||
|
multiboot_uint16_t cseg_16;
|
||||||
|
multiboot_uint16_t dseg;
|
||||||
|
multiboot_uint16_t flags;
|
||||||
|
multiboot_uint16_t cseg_len;
|
||||||
|
multiboot_uint16_t cseg_16_len;
|
||||||
|
multiboot_uint16_t dseg_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_efi32
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_efi64
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint64_t pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_smbios
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint8_t major;
|
||||||
|
multiboot_uint8_t minor;
|
||||||
|
multiboot_uint8_t reserved[6];
|
||||||
|
multiboot_uint8_t tables[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_old_acpi
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint8_t rsdp[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_new_acpi
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint8_t rsdp[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_network
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint8_t dhcpack[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_efi_mmap
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t descr_size;
|
||||||
|
multiboot_uint32_t descr_vers;
|
||||||
|
multiboot_uint8_t efi_mmap[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_efi32_ih
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_efi64_ih
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint64_t pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct multiboot_tag_load_base_addr
|
||||||
|
{
|
||||||
|
multiboot_uint32_t type;
|
||||||
|
multiboot_uint32_t size;
|
||||||
|
multiboot_uint32_t load_base_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ! ASM_FILE */
|
||||||
|
|
||||||
|
#endif /* ! MULTIBOOT_HEADER */
|
||||||
@@ -1,62 +1,176 @@
|
|||||||
|
// Basic shell and commands kernel module
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../libc/string.h"
|
#include "../libc/string.h"
|
||||||
#include "../programs/programs.h"
|
#include "../programs/programs.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../drivers/rtc.h"
|
||||||
|
#include "kmain.h"
|
||||||
|
|
||||||
#define BUFFER_SIZE 256
|
#define BUFFER_SIZE 256
|
||||||
|
#define MAX_COMMANDS 64
|
||||||
|
#define MAX_ARGS 64
|
||||||
|
|
||||||
|
// Splash screen: esthetic stuff.
|
||||||
|
char* motd[] =
|
||||||
|
{
|
||||||
|
"I should be root, really.",
|
||||||
|
"Not watching you!",
|
||||||
|
"Now in 2D!",
|
||||||
|
"Supercalifragilisticexpialidocious!",
|
||||||
|
"Tylko jedno w glowie mam!",
|
||||||
|
"Greetings, magic poppy!",
|
||||||
|
"I'm stuck in this kernel's shell, get me out!",
|
||||||
|
"And now, solve that equation!",
|
||||||
|
"Powered by TCC Incorporated.",
|
||||||
|
"Compiled at 69, CoquaineBaule Ave.",
|
||||||
|
"Shouldn't we be, uh, doing something?",
|
||||||
|
"We are the florists, we pick the plants!",
|
||||||
|
"Lalalalala, I pick the plants!",
|
||||||
|
"Woah, we're half-way there...",
|
||||||
|
"The CROU will never die!",
|
||||||
|
"Technoblade never dies!",
|
||||||
|
"Hi. My name is Guitar.",
|
||||||
|
"space station No. 9",
|
||||||
|
"May the orange juice be with you !",
|
||||||
|
"Bloody grated carrots!",
|
||||||
|
"Good night, kiddos...",
|
||||||
|
"I like trains",
|
||||||
|
"I fear planes",
|
||||||
|
"Bruteforce.exe",
|
||||||
|
"Ohayogozaimasu!",
|
||||||
|
};
|
||||||
|
|
||||||
|
int motd_size = sizeof(motd)/sizeof(motd[0]);
|
||||||
|
|
||||||
|
bool do_splash = true;
|
||||||
|
|
||||||
|
void splash()
|
||||||
|
{
|
||||||
|
int random = randint(time_seed());
|
||||||
|
char* motd_pick = motd[random%motd_size];
|
||||||
|
cowsay(motd_pick, red, black);
|
||||||
|
puts(" ");
|
||||||
|
colorputs("blankOS", black, white);
|
||||||
|
puts(" ");
|
||||||
|
colorputs(BLANK_VERSION, red, black);
|
||||||
|
puts("\n");
|
||||||
|
|
||||||
|
|
||||||
|
puts(" Time: ");
|
||||||
|
rtc_time_t time;
|
||||||
|
rtc_read_time(&time);
|
||||||
|
print_time(&time);
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*command_func_t)(int argc, char *argv[]);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
command_func_t function;
|
||||||
|
} shell_command_t;
|
||||||
|
|
||||||
|
shell_command_t shell_commands[MAX_COMMANDS];
|
||||||
|
int command_count = 0;
|
||||||
|
|
||||||
|
void register_command(const char* name, command_func_t function)
|
||||||
|
{
|
||||||
|
if (command_count < MAX_COMMANDS)
|
||||||
|
{
|
||||||
|
shell_commands[command_count].name = name;
|
||||||
|
shell_commands[command_count].function = function;
|
||||||
|
command_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_func_t find_command(const char* name)
|
||||||
|
{
|
||||||
|
for (int i=0; i < command_count; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(name, shell_commands[i].name) == 0)
|
||||||
|
return shell_commands[i].function;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_input(char* input, char* argv[], int max_args)
|
||||||
|
{
|
||||||
|
int argc = 0;
|
||||||
|
char* token = strtok(input, " ");
|
||||||
|
while (token != NULL && argc < max_args - 1)
|
||||||
|
{
|
||||||
|
argv[argc++] = token;
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
}
|
||||||
|
argv[argc] = NULL;
|
||||||
|
return argc;
|
||||||
|
}
|
||||||
|
|
||||||
void shell_install()
|
void shell_install()
|
||||||
{
|
{
|
||||||
while (1) // Bad!!
|
if (do_splash == true)
|
||||||
|
{
|
||||||
|
do_splash = false;
|
||||||
|
splash();
|
||||||
|
}
|
||||||
|
|
||||||
|
register_command("help", program_help);
|
||||||
|
register_command("panic", program_panic);
|
||||||
|
register_command("words", program_words);
|
||||||
|
register_command("primes", program_primes);
|
||||||
|
register_command("rainbow", program_rainbow);
|
||||||
|
register_command("clear", program_clear);
|
||||||
|
register_command("math", program_math);
|
||||||
|
register_command("bf", program_bf);
|
||||||
|
register_command("uptime", program_uptime);
|
||||||
|
register_command("echo", program_echo);
|
||||||
|
register_command("sysinfo", program_sysinfo);
|
||||||
|
register_command("conway", program_conway);
|
||||||
|
register_command("rot13", program_rot13);
|
||||||
|
register_command("morse", program_morse);
|
||||||
|
register_command("cowsay", program_cowsay);
|
||||||
|
register_command("time", program_time);
|
||||||
|
register_command("read", program_read);
|
||||||
|
register_command("reboot", program_reboot);
|
||||||
|
register_command("pi", program_pi);
|
||||||
|
register_command("ls", program_ls);
|
||||||
|
register_command("cat", program_cat);
|
||||||
|
register_command("bmp", program_bmp);
|
||||||
|
register_command("lspci", program_lspci);
|
||||||
|
register_command("naval", program_navalbattle);
|
||||||
|
register_command("snake", program_snake);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
char input_buffer[BUFFER_SIZE];
|
char input_buffer[BUFFER_SIZE];
|
||||||
colorputs("blankos> ", 9);
|
char* argv[MAX_ARGS];
|
||||||
|
|
||||||
|
// Prompt
|
||||||
|
colorputs("root", blue, black);
|
||||||
|
colorputs("@", white, black);
|
||||||
|
colorputs("blankos", green, black);
|
||||||
|
colorputs("~$ ", white, black);
|
||||||
|
|
||||||
get_input(input_buffer, BUFFER_SIZE);
|
get_input(input_buffer, BUFFER_SIZE);
|
||||||
puts("\n");
|
puts("\n");
|
||||||
|
|
||||||
// Childish shell
|
int argc = parse_input(input_buffer, argv, MAX_ARGS);
|
||||||
if (strcmp(input_buffer, "") == 0)
|
|
||||||
|
if (argc == 0) continue;
|
||||||
|
|
||||||
|
command_func_t command = find_command(argv[0]);
|
||||||
|
if (command)
|
||||||
{
|
{
|
||||||
continue;
|
command(argc, argv);
|
||||||
}
|
} else {
|
||||||
else if (strcmp(input_buffer, "help") == 0)
|
printf("Unknown command %s\n", argv[0]);
|
||||||
{
|
|
||||||
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\tuptime\n");
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "panic") == 0)
|
|
||||||
{
|
|
||||||
printf("%d", 4/0);
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "words") == 0)
|
|
||||||
{
|
|
||||||
program_words();
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "primes") == 0)
|
|
||||||
{
|
|
||||||
program_primes();
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "rainbow") == 0)
|
|
||||||
{
|
|
||||||
program_rainbow();
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "clear") == 0)
|
|
||||||
{
|
|
||||||
program_clear();
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "math") == 0)
|
|
||||||
{
|
|
||||||
program_math();
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "bf") == 0)
|
|
||||||
{
|
|
||||||
program_bf();
|
|
||||||
}
|
|
||||||
else if (strcmp(input_buffer, "uptime") == 0)
|
|
||||||
{
|
|
||||||
program_uptime();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Unknown command %s\n", input_buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/kernel/sysinfo.c
Normal file
16
src/kernel/sysinfo.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// System information kernel module
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
|
void cpuid(int code, unsigned int* a, unsigned int* d)
|
||||||
|
{
|
||||||
|
asm volatile("cpuid"
|
||||||
|
: "=a"(*a), "=d"(*d)
|
||||||
|
: "a"(code)
|
||||||
|
: "ecx", "ebx");
|
||||||
|
}
|
||||||
|
|
||||||
11
src/kernel/sysinfo.h
Normal file
11
src/kernel/sysinfo.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// System information kernel module header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef SYSINFO_H
|
||||||
|
#define SYSINFO_H
|
||||||
|
|
||||||
|
void cpuid(int code, unsigned int* a, unsigned int* d);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
|
// System utilities and routines kernel module
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
void *memset(void *dest, char val, size_t count)
|
void *memset(void *dest, char val, size_t count)
|
||||||
{
|
{
|
||||||
@@ -6,3 +12,42 @@ void *memset(void *dest, char val, size_t count)
|
|||||||
for(; count != 0; count--) *temp++ = val;
|
for(; count != 0; count--) *temp++ = val;
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *memmove(void* dest, const void* src, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char* d = (unsigned char*)dest;
|
||||||
|
const unsigned char* s = (const unsigned char*)src;
|
||||||
|
|
||||||
|
if (d < s)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<n; i++)
|
||||||
|
{
|
||||||
|
d[i] = s[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (size_t i=n; i>0; i--)
|
||||||
|
{
|
||||||
|
d[i-1] = s[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memcpy(void* dest, const void* src, uint32_t n)
|
||||||
|
{
|
||||||
|
uint8_t* d = (uint8_t*)dest;
|
||||||
|
const uint8_t* s = (const uint8_t*)src;
|
||||||
|
|
||||||
|
for (uint32_t i=0; i<n; i++)
|
||||||
|
{
|
||||||
|
d[i] = s[i];
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void panic()
|
||||||
|
{
|
||||||
|
for (;;);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
|
// System utilities and routines kernel module header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#ifndef SYSTEM_H
|
#ifndef SYSTEM_H
|
||||||
#define SYSTEM_H
|
#define SYSTEM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef int size_t;
|
typedef int size_t;
|
||||||
|
#define NULL ((void*)0)
|
||||||
|
|
||||||
void *memset(void *dest, char val, size_t count);
|
void *memset(void *dest, char val, size_t count);
|
||||||
|
void *memmove(void* dest, const void* src, size_t n);
|
||||||
|
void *memcpy(void* dest, const void* src, uint32_t n);
|
||||||
|
|
||||||
struct regs
|
struct regs
|
||||||
{
|
{
|
||||||
@@ -13,6 +23,7 @@ struct regs
|
|||||||
unsigned int eip, cs, eflags, useresp, ss;
|
unsigned int eip, cs, eflags, useresp, ss;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void panic();
|
||||||
void isr_install();
|
void isr_install();
|
||||||
void irq_install();
|
void irq_install();
|
||||||
void irq_install_handler(int irq, void (*handler)(struct regs *r));
|
void irq_install_handler(int irq, void (*handler)(struct regs *r));
|
||||||
@@ -26,5 +37,7 @@ int uptime();
|
|||||||
|
|
||||||
extern volatile unsigned long global_ticks;
|
extern volatile unsigned long global_ticks;
|
||||||
|
|
||||||
|
extern unsigned int g_multiboot_info_address;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
|
// Cryptography routines for blankos/libc
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
int lcg(int seed)
|
int lcg(int seed)
|
||||||
{
|
{
|
||||||
@@ -22,3 +28,21 @@ int randint(int seed)
|
|||||||
int x = lcg(seed);
|
int x = lcg(seed);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t next = 1;
|
||||||
|
|
||||||
|
uint32_t rand()
|
||||||
|
{
|
||||||
|
next = next * 1103515245 + 12345;
|
||||||
|
return (next/65536) % 32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rand_float()
|
||||||
|
{
|
||||||
|
return rand() / 32767.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void srand(uint32_t seed)
|
||||||
|
{
|
||||||
|
next = seed;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
|
// Cryptography routines for blankos/libc header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#ifndef CRYPTO_H
|
#ifndef CRYPTO_H
|
||||||
#define CRYPTO_H
|
#define CRYPTO_H
|
||||||
|
|
||||||
#define RAND_MAX 1024
|
#define RAND_MAX 1024
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
int lcg(int seed);
|
int lcg(int seed);
|
||||||
int randint(int seed);
|
int randint(int seed);
|
||||||
|
uint32_t rand();
|
||||||
|
float rand_float();
|
||||||
|
void srand(uint32_t seed);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
|
// Ctype implementation for blankos/libc
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "stdint.h"
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
bool isdigit(char c)
|
bool isdigit(char c)
|
||||||
{
|
{
|
||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isspace(char c)
|
bool isspace(char c)
|
||||||
{
|
{
|
||||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
|
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
|
// Ctype implementation for blankos/libc header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#ifndef CTYPE_H
|
#ifndef CTYPE_H
|
||||||
#define CTYPE_H
|
#define CTYPE_H
|
||||||
|
|
||||||
#include "stdint.h"
|
#include <stdbool.h>
|
||||||
|
|
||||||
bool isdigit(char c);
|
bool isdigit(char c);
|
||||||
bool isspace(char c);
|
bool isspace(char c);
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
#ifndef INCLUDE_STDINT_H
|
|
||||||
#define INCLUDE_STDINT_H
|
|
||||||
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
|
|
||||||
typedef signed short int16_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
|
|
||||||
typedef signed long int int32_t;
|
|
||||||
typedef unsigned long int uint32_t;
|
|
||||||
|
|
||||||
typedef signed long long int int64_t;
|
|
||||||
typedef unsigned long long int uint64_t;
|
|
||||||
|
|
||||||
typedef uint8_t bool;
|
|
||||||
#define true 1
|
|
||||||
#define false 0
|
|
||||||
|
|
||||||
#endif
|
|
||||||
504
src/libc/stdio.c
504
src/libc/stdio.c
@@ -1,33 +1,80 @@
|
|||||||
|
// Standard input/output implementation for blankos/libc
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../kernel/io.h"
|
#include "../kernel/io.h"
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "stdint.h"
|
#include <stdint.h>
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
#include "../drivers/serial.h"
|
||||||
|
|
||||||
char* fb = (char *) 0x000B8000;
|
extern uint32_t* framebuffer;
|
||||||
const unsigned VGA_WIDTH = 80;
|
extern uint32_t VGA_WIDTH;
|
||||||
const unsigned VGA_HEIGHT = 25;
|
extern uint32_t VGA_HEIGHT;
|
||||||
const unsigned int COLOR = 0x7;
|
|
||||||
unsigned int VGA_X = 0, VGA_Y = 0;
|
unsigned int VGA_X = 0, VGA_Y = 0;
|
||||||
|
|
||||||
|
extern int scanline;
|
||||||
|
|
||||||
|
int get_cursor_x()
|
||||||
|
{
|
||||||
|
return VGA_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_cursor_y()
|
||||||
|
{
|
||||||
|
return VGA_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_cursor(uint32_t color)
|
||||||
|
{
|
||||||
|
for (int y=12; y<CURSOR_HEIGHT; y++)
|
||||||
|
{
|
||||||
|
for (int x=0; x<CURSOR_WIDTH; x++)
|
||||||
|
{
|
||||||
|
putpixel(framebuffer, scanline, 32, VGA_X * CURSOR_WIDTH + x, VGA_Y * CURSOR_HEIGHT + y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_pixel(int x, int y, uint32_t color) //high level wrapper for putpixel
|
||||||
|
{
|
||||||
|
putpixel(framebuffer, scanline, 32, x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_square(int x, int y, uint32_t color, int size)
|
||||||
|
{
|
||||||
|
int startx = x*size;
|
||||||
|
int starty = y*size;
|
||||||
|
|
||||||
|
for (int i=0; i<size; i++)
|
||||||
|
{
|
||||||
|
for (int j=0; j<size; j++)
|
||||||
|
{
|
||||||
|
draw_pixel(startx+i, starty+j, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase_cursor()
|
||||||
|
{
|
||||||
|
draw_cursor(black);
|
||||||
|
}
|
||||||
|
|
||||||
void move_cursor(int x, int y)
|
void move_cursor(int x, int y)
|
||||||
{
|
{
|
||||||
unsigned short pos = y*VGA_WIDTH+x;
|
erase_cursor();
|
||||||
|
VGA_X = x;
|
||||||
outb(FB_CMD_PORT, FB_HIGH_BYTE_CMD);
|
VGA_Y = y;
|
||||||
outb(FB_DATA_PORT, ((pos >> 8) & 0x00FF));
|
draw_cursor(white);
|
||||||
outb(FB_CMD_PORT, FB_LOW_BYTE_CMD);
|
|
||||||
outb(FB_DATA_PORT, pos & 0x00FF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void putchar(int x, int y, char c)
|
// stdio wrapper for draw_char in graphics mode
|
||||||
|
void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg)
|
||||||
{
|
{
|
||||||
fb[2*(y*VGA_WIDTH+x)] = c;
|
draw_char(c, x, y, fg, bg);
|
||||||
}
|
|
||||||
|
|
||||||
void putcolor(int x, int y, unsigned int color)
|
|
||||||
{
|
|
||||||
fb[2*(y*VGA_WIDTH+x)+1] = color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear(void)
|
void clear(void)
|
||||||
@@ -36,55 +83,15 @@ void clear(void)
|
|||||||
{
|
{
|
||||||
for (unsigned int x=0; x<VGA_WIDTH; x++)
|
for (unsigned int x=0; x<VGA_WIDTH; x++)
|
||||||
{
|
{
|
||||||
putchar(x, y, '\0');
|
putchar(' ', x, y, black, black);
|
||||||
putcolor(x, y, COLOR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VGA_X = 0;
|
move_cursor(0, 0);
|
||||||
VGA_Y = 0;
|
|
||||||
move_cursor(VGA_X, VGA_Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
char getchar(int x, int y)
|
|
||||||
{
|
|
||||||
return fb[2*(y*VGA_WIDTH+x)];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int getcolor(int x, int y)
|
|
||||||
{
|
|
||||||
return fb[2*(y*VGA_WIDTH+x)+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void scroll(int lines)
|
|
||||||
{
|
|
||||||
if (lines <= 0 || (unsigned int)lines >= VGA_HEIGHT) return;
|
|
||||||
|
|
||||||
for (unsigned int y = 0; y < VGA_HEIGHT-lines; y++)
|
|
||||||
{
|
|
||||||
for (unsigned int x = 0; x < VGA_WIDTH; x++)
|
|
||||||
{
|
|
||||||
putchar(x, y, getchar(x, y+lines));
|
|
||||||
putcolor(x, y, getcolor(x, y+lines));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int y = VGA_HEIGHT-lines; y<VGA_HEIGHT; y++)
|
|
||||||
{
|
|
||||||
for (unsigned int x = 0; x < VGA_WIDTH; x++)
|
|
||||||
{
|
|
||||||
putchar(x, y, ' ');
|
|
||||||
putcolor(x, y, COLOR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VGA_Y -= lines;
|
|
||||||
if ((int)VGA_Y < 0) {
|
|
||||||
VGA_Y = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void putc(char c)
|
void putc(char c)
|
||||||
{
|
{
|
||||||
|
erase_cursor();
|
||||||
switch(c)
|
switch(c)
|
||||||
{
|
{
|
||||||
case '\n':
|
case '\n':
|
||||||
@@ -110,10 +117,10 @@ void putc(char c)
|
|||||||
VGA_Y--;
|
VGA_Y--;
|
||||||
VGA_X = VGA_WIDTH-1;
|
VGA_X = VGA_WIDTH-1;
|
||||||
}
|
}
|
||||||
putchar(VGA_X, VGA_Y, ' ');
|
putchar(' ', VGA_X, VGA_Y, white, black);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
putchar(VGA_X, VGA_Y, c);
|
putchar(c, VGA_X, VGA_Y, white, black);
|
||||||
VGA_X++;
|
VGA_X++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -123,13 +130,19 @@ void putc(char c)
|
|||||||
VGA_Y++;
|
VGA_Y++;
|
||||||
VGA_X = 0;
|
VGA_X = 0;
|
||||||
}
|
}
|
||||||
if (VGA_Y >= VGA_HEIGHT) scroll(1);
|
if (VGA_Y >= VGA_HEIGHT)
|
||||||
|
{
|
||||||
|
serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT);
|
||||||
|
scroll();
|
||||||
|
VGA_Y = VGA_HEIGHT - 1;
|
||||||
|
}
|
||||||
|
|
||||||
move_cursor(VGA_X, VGA_Y);
|
move_cursor(VGA_X, VGA_Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorputc(char c, unsigned int color)
|
void colorputc(char c, uint32_t fg, uint32_t bg)
|
||||||
{
|
{
|
||||||
|
erase_cursor();
|
||||||
switch(c)
|
switch(c)
|
||||||
{
|
{
|
||||||
case '\n':
|
case '\n':
|
||||||
@@ -143,8 +156,7 @@ void colorputc(char c, unsigned int color)
|
|||||||
VGA_X += 4;
|
VGA_X += 4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
putchar(VGA_X, VGA_Y, c);
|
putchar(c, VGA_X, VGA_Y, fg, bg);
|
||||||
putcolor(VGA_X, VGA_Y, color);
|
|
||||||
VGA_X++;
|
VGA_X++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -154,7 +166,14 @@ void colorputc(char c, unsigned int color)
|
|||||||
VGA_Y++;
|
VGA_Y++;
|
||||||
VGA_X = 0;
|
VGA_X = 0;
|
||||||
}
|
}
|
||||||
if (VGA_Y >= VGA_HEIGHT) scroll(1);
|
|
||||||
|
if (VGA_Y >= VGA_HEIGHT)
|
||||||
|
{
|
||||||
|
serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT);
|
||||||
|
scroll();
|
||||||
|
VGA_Y = VGA_HEIGHT - 1;
|
||||||
|
}
|
||||||
|
|
||||||
move_cursor(VGA_X, VGA_Y);
|
move_cursor(VGA_X, VGA_Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,11 +186,11 @@ void puts(const char* str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorputs(const char* str, unsigned int color)
|
void colorputs(const char* str, uint32_t fg, uint32_t bg)
|
||||||
{
|
{
|
||||||
while (*str)
|
while (*str)
|
||||||
{
|
{
|
||||||
colorputc(*str, color);
|
colorputc(*str, fg, bg);
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,27 +240,44 @@ void dtostrf(double val, char *buffer, int precision)
|
|||||||
|
|
||||||
void printf(const char* fmt, ...)
|
void printf(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
int* argp = (int*) &fmt;
|
int* argp = (int*)&fmt;
|
||||||
int state = PRINTF_STATE_START;
|
int state = PRINTF_STATE_START;
|
||||||
int length = PRINTF_LENGTH_START;
|
int length = PRINTF_LENGTH_START;
|
||||||
int radix = 10;
|
int radix = 10;
|
||||||
bool sign = false;
|
bool sign = false;
|
||||||
|
int width = 0;
|
||||||
|
char pad_char = ' ';
|
||||||
|
|
||||||
argp++;
|
argp++;
|
||||||
while (*fmt)
|
while (*fmt)
|
||||||
{
|
{
|
||||||
switch(state) {
|
switch (state)
|
||||||
|
{
|
||||||
case PRINTF_STATE_START:
|
case PRINTF_STATE_START:
|
||||||
if (*fmt == '%')
|
if (*fmt == '%')
|
||||||
{
|
{
|
||||||
state = PRINTF_STATE_LENGTH;
|
state = PRINTF_STATE_LENGTH;
|
||||||
|
width = 0;
|
||||||
|
pad_char = ' ';
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
putc(*fmt);
|
putc(*fmt);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRINTF_STATE_LENGTH:
|
case PRINTF_STATE_LENGTH:
|
||||||
if (*fmt == 'h')
|
if (*fmt == '0')
|
||||||
|
{
|
||||||
|
pad_char = '0';
|
||||||
|
state = PRINTF_STATE_WIDTH;
|
||||||
|
}
|
||||||
|
else if (*fmt >= '1' && *fmt <= '9')
|
||||||
|
{
|
||||||
|
width = *fmt - '0';
|
||||||
|
state = PRINTF_STATE_WIDTH;
|
||||||
|
}
|
||||||
|
else if (*fmt == 'h')
|
||||||
{
|
{
|
||||||
length = PRINTF_LENGTH_SHORT;
|
length = PRINTF_LENGTH_SHORT;
|
||||||
state = PRINTF_STATE_SHORT;
|
state = PRINTF_STATE_SHORT;
|
||||||
@@ -251,40 +287,57 @@ void printf(const char* fmt, ...)
|
|||||||
length = PRINTF_LENGTH_LONG;
|
length = PRINTF_LENGTH_LONG;
|
||||||
state = PRINTF_STATE_LONG;
|
state = PRINTF_STATE_LONG;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
goto PRINTF_STATE_SPEC_;
|
goto PRINTF_STATE_SPEC_;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PRINTF_STATE_WIDTH:
|
||||||
|
if (*fmt >= '0' && *fmt <= '9')
|
||||||
|
{
|
||||||
|
width = width * 10 + (*fmt - '0');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PRINTF_STATE_SHORT:
|
case PRINTF_STATE_SHORT:
|
||||||
if (*fmt == 'h')
|
if (*fmt == 'h')
|
||||||
{
|
{
|
||||||
length = PRINTF_LENGTH_SHORT_SHORT;
|
length = PRINTF_LENGTH_SHORT_SHORT;
|
||||||
state = PRINTF_STATE_SPEC;
|
state = PRINTF_STATE_SPEC;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
goto PRINTF_STATE_SPEC_;
|
goto PRINTF_STATE_SPEC_;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRINTF_STATE_LONG:
|
case PRINTF_STATE_LONG:
|
||||||
if (*fmt == 'l')
|
if (*fmt == 'l')
|
||||||
{
|
{
|
||||||
length = PRINTF_LENGTH_LONG_LONG;
|
length = PRINTF_LENGTH_LONG_LONG;
|
||||||
state = PRINTF_STATE_SPEC;
|
state = PRINTF_STATE_SPEC;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
goto PRINTF_STATE_SPEC_;
|
goto PRINTF_STATE_SPEC_;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRINTF_STATE_SPEC:
|
case PRINTF_STATE_SPEC:
|
||||||
PRINTF_STATE_SPEC_:
|
PRINTF_STATE_SPEC_:
|
||||||
switch(*fmt)
|
switch (*fmt)
|
||||||
{
|
{
|
||||||
case 'c':
|
case 'c':
|
||||||
putc((char)*argp);
|
putc((char)*argp);
|
||||||
argp++;
|
argp++;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
puts(*(const char **)argp);
|
puts(*(const char**)argp);
|
||||||
argp++;
|
argp++;
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
@@ -294,33 +347,32 @@ void printf(const char* fmt, ...)
|
|||||||
case 'i':
|
case 'i':
|
||||||
radix = 10;
|
radix = 10;
|
||||||
sign = true;
|
sign = true;
|
||||||
argp = printf_number(argp, length, sign, radix);
|
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
radix = 10;
|
radix = 10;
|
||||||
sign = false;
|
sign = false;
|
||||||
argp = printf_number(argp, length, sign, radix);
|
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||||
break;
|
break;
|
||||||
case 'X':
|
case 'X':
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'p':
|
case 'p':
|
||||||
radix = 16;
|
radix = 16;
|
||||||
sign = false;
|
sign = false;
|
||||||
argp = printf_number(argp, length, sign, radix);
|
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
radix = 8;
|
radix = 8;
|
||||||
sign = false;
|
sign = false;
|
||||||
argp = printf_number(argp, length, sign, radix);
|
argp = printf_number(argp, length, sign, radix, width, pad_char);
|
||||||
break;
|
break;
|
||||||
case 'f': {
|
case 'f': {
|
||||||
// Handle floating-point numbers
|
|
||||||
double* dargp = (double*)argp;
|
double* dargp = (double*)argp;
|
||||||
double d = *(double*)dargp;
|
double d = *(double*)dargp;
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
dtostrf(d, buffer, 6); // Default precision: 6
|
dtostrf(d, buffer, 6);
|
||||||
puts(buffer);
|
puts(buffer);
|
||||||
argp += 2; // Incrementing by 2 to move past the double argument
|
argp += 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -330,6 +382,8 @@ void printf(const char* fmt, ...)
|
|||||||
length = PRINTF_LENGTH_START;
|
length = PRINTF_LENGTH_START;
|
||||||
radix = 10;
|
radix = 10;
|
||||||
sign = false;
|
sign = false;
|
||||||
|
width = 0;
|
||||||
|
pad_char = ' ';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fmt++;
|
fmt++;
|
||||||
@@ -338,14 +392,14 @@ void printf(const char* fmt, ...)
|
|||||||
|
|
||||||
const char charset[] = "0123456789abcdef";
|
const char charset[] = "0123456789abcdef";
|
||||||
|
|
||||||
int* printf_number(int* argp, int length, bool sign, int radix)
|
int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char)
|
||||||
{
|
{
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
unsigned long long number;
|
unsigned long long number;
|
||||||
int number_sign = 1;
|
int number_sign = 1;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
switch(length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case PRINTF_LENGTH_SHORT_SHORT:
|
case PRINTF_LENGTH_SHORT_SHORT:
|
||||||
case PRINTF_LENGTH_SHORT:
|
case PRINTF_LENGTH_SHORT:
|
||||||
@@ -358,10 +412,11 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
|||||||
n = -n;
|
n = -n;
|
||||||
number_sign = -1;
|
number_sign = -1;
|
||||||
}
|
}
|
||||||
number = (unsigned long long) n;
|
number = (unsigned long long)n;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
number = *(unsigned int*) argp;
|
{
|
||||||
|
number = *(unsigned int*)argp;
|
||||||
}
|
}
|
||||||
argp++;
|
argp++;
|
||||||
break;
|
break;
|
||||||
@@ -374,10 +429,11 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
|||||||
n = -n;
|
n = -n;
|
||||||
number_sign = -1;
|
number_sign = -1;
|
||||||
}
|
}
|
||||||
number = (unsigned long long) n;
|
number = (unsigned long long)n;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
number = *(unsigned long int*) argp;
|
{
|
||||||
|
number = *(unsigned long int*)argp;
|
||||||
}
|
}
|
||||||
argp += 2;
|
argp += 2;
|
||||||
break;
|
break;
|
||||||
@@ -390,16 +446,18 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
|||||||
n = -n;
|
n = -n;
|
||||||
number_sign = -1;
|
number_sign = -1;
|
||||||
}
|
}
|
||||||
number = (unsigned long long) n;
|
number = (unsigned long long)n;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
number = *(unsigned long long int*) argp;
|
{
|
||||||
|
number = *(unsigned long long int*)argp;
|
||||||
}
|
}
|
||||||
argp += 4;
|
argp += 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
uint32_t rem;
|
uint32_t rem;
|
||||||
x86_div64_32(number, radix, &number, &rem);
|
x86_div64_32(number, radix, &number, &rem);
|
||||||
buffer[pos++] = charset[rem];
|
buffer[pos++] = charset[rem];
|
||||||
@@ -410,6 +468,13 @@ int* printf_number(int* argp, int length, bool sign, int radix)
|
|||||||
buffer[pos++] = '-';
|
buffer[pos++] = '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int padding = width - pos;
|
||||||
|
|
||||||
|
while (padding-- > 0)
|
||||||
|
{
|
||||||
|
putc(pad_char);
|
||||||
|
}
|
||||||
|
|
||||||
while (--pos >= 0)
|
while (--pos >= 0)
|
||||||
{
|
{
|
||||||
putc(buffer[pos]);
|
putc(buffer[pos]);
|
||||||
@@ -446,3 +511,246 @@ void get_input(char *buffer, int size) {
|
|||||||
}
|
}
|
||||||
buffer[index] = '\0';
|
buffer[index] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void colorprintf(uint32_t fg, uint32_t bg, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
int* argp = (int*)&fmt;
|
||||||
|
int state = PRINTF_STATE_START;
|
||||||
|
int length = PRINTF_LENGTH_START;
|
||||||
|
int radix = 10;
|
||||||
|
bool sign = false;
|
||||||
|
int width = 0;
|
||||||
|
char pad_char = ' ';
|
||||||
|
|
||||||
|
argp++;
|
||||||
|
while (*fmt)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case PRINTF_STATE_START:
|
||||||
|
if (*fmt == '%')
|
||||||
|
{
|
||||||
|
state = PRINTF_STATE_LENGTH;
|
||||||
|
width = 0;
|
||||||
|
pad_char = ' ';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
colorputc(*fmt, fg, bg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINTF_STATE_LENGTH:
|
||||||
|
if (*fmt == '0')
|
||||||
|
{
|
||||||
|
pad_char = '0';
|
||||||
|
state = PRINTF_STATE_WIDTH;
|
||||||
|
}
|
||||||
|
else if (*fmt >= '1' && *fmt <= '9')
|
||||||
|
{
|
||||||
|
width = *fmt - '0';
|
||||||
|
state = PRINTF_STATE_WIDTH;
|
||||||
|
}
|
||||||
|
else if (*fmt == 'h')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_SHORT;
|
||||||
|
state = PRINTF_STATE_SHORT;
|
||||||
|
}
|
||||||
|
else if (*fmt == 'l')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_LONG;
|
||||||
|
state = PRINTF_STATE_LONG;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINTF_STATE_WIDTH:
|
||||||
|
if (*fmt >= '0' && *fmt <= '9')
|
||||||
|
{
|
||||||
|
width = width * 10 + (*fmt - '0');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINTF_STATE_SHORT:
|
||||||
|
if (*fmt == 'h')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_SHORT_SHORT;
|
||||||
|
state = PRINTF_STATE_SPEC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINTF_STATE_LONG:
|
||||||
|
if (*fmt == 'l')
|
||||||
|
{
|
||||||
|
length = PRINTF_LENGTH_LONG_LONG;
|
||||||
|
state = PRINTF_STATE_SPEC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto PRINTF_STATE_SPEC_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRINTF_STATE_SPEC:
|
||||||
|
PRINTF_STATE_SPEC_:
|
||||||
|
switch (*fmt)
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
colorputc((char)*argp, fg, bg);
|
||||||
|
argp++;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
colorputs(*(const char**)argp, fg, bg);
|
||||||
|
argp++;
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
putc('%');
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'i':
|
||||||
|
radix = 10;
|
||||||
|
sign = true;
|
||||||
|
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
radix = 10;
|
||||||
|
sign = false;
|
||||||
|
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
case 'p':
|
||||||
|
radix = 16;
|
||||||
|
sign = false;
|
||||||
|
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
radix = 8;
|
||||||
|
sign = false;
|
||||||
|
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
|
||||||
|
break;
|
||||||
|
case 'f': {
|
||||||
|
double* dargp = (double*)argp;
|
||||||
|
double d = *(double*)dargp;
|
||||||
|
char buffer[64];
|
||||||
|
dtostrf(d, buffer, 6);
|
||||||
|
colorputs(buffer, fg, bg);
|
||||||
|
argp += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state = PRINTF_STATE_START;
|
||||||
|
length = PRINTF_LENGTH_START;
|
||||||
|
radix = 10;
|
||||||
|
sign = false;
|
||||||
|
width = 0;
|
||||||
|
pad_char = ' ';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int* colorprintf_number(int* argp, int length, bool sign, int radix, int width, char pad_char, uint32_t fg, uint32_t bg)
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
unsigned long long number;
|
||||||
|
int number_sign = 1;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
switch (length)
|
||||||
|
{
|
||||||
|
case PRINTF_LENGTH_SHORT_SHORT:
|
||||||
|
case PRINTF_LENGTH_SHORT:
|
||||||
|
case PRINTF_LENGTH_START:
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
int n = *argp;
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
number_sign = -1;
|
||||||
|
}
|
||||||
|
number = (unsigned long long)n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
number = *(unsigned int*)argp;
|
||||||
|
}
|
||||||
|
argp++;
|
||||||
|
break;
|
||||||
|
case PRINTF_LENGTH_LONG:
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
long int n = *(long int*)argp;
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
number_sign = -1;
|
||||||
|
}
|
||||||
|
number = (unsigned long long)n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
number = *(unsigned long int*)argp;
|
||||||
|
}
|
||||||
|
argp += 2;
|
||||||
|
break;
|
||||||
|
case PRINTF_LENGTH_LONG_LONG:
|
||||||
|
if (sign)
|
||||||
|
{
|
||||||
|
long long int n = *(long long int*)argp;
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
n = -n;
|
||||||
|
number_sign = -1;
|
||||||
|
}
|
||||||
|
number = (unsigned long long)n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
number = *(unsigned long long int*)argp;
|
||||||
|
}
|
||||||
|
argp += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uint32_t rem;
|
||||||
|
x86_div64_32(number, radix, &number, &rem);
|
||||||
|
buffer[pos++] = charset[rem];
|
||||||
|
} while (number > 0);
|
||||||
|
|
||||||
|
if (sign && number_sign < 0)
|
||||||
|
{
|
||||||
|
buffer[pos++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
int padding = width - pos;
|
||||||
|
|
||||||
|
while (padding-- > 0)
|
||||||
|
{
|
||||||
|
colorputc(pad_char, fg, bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (--pos >= 0)
|
||||||
|
{
|
||||||
|
colorputc(buffer[pos], fg, bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return argp;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
#ifndef INCLUDE_STDIO_H
|
// Standard input/output implementation for blankos/libc header
|
||||||
#define INCLUDE_STDIO_H
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "stdint.h"
|
#ifndef STDIO_H
|
||||||
|
#define STDIO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define FB_GREEN 2
|
#define FB_GREEN 2
|
||||||
#define FB_DARK_GREY 8
|
#define FB_DARK_GREY 8
|
||||||
@@ -11,23 +17,33 @@
|
|||||||
#define FB_HIGH_BYTE_CMD 14
|
#define FB_HIGH_BYTE_CMD 14
|
||||||
#define FB_LOW_BYTE_CMD 15
|
#define FB_LOW_BYTE_CMD 15
|
||||||
|
|
||||||
|
#define CURSOR_WIDTH 8
|
||||||
|
#define CURSOR_HEIGHT 16
|
||||||
|
|
||||||
|
void draw_cursor(uint32_t color);
|
||||||
|
void erase_cursor();
|
||||||
void move_cursor(int x, int y);
|
void move_cursor(int x, int y);
|
||||||
void putchar(int x, int y, char c);
|
|
||||||
|
void draw_pixel(int x, int y, uint32_t color);
|
||||||
|
void draw_square(int x, int y, uint32_t color, int size);
|
||||||
|
void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg);
|
||||||
void puts(const char* str);
|
void puts(const char* str);
|
||||||
void colorputs(const char* str, unsigned int color);
|
|
||||||
void clear(void);
|
void clear(void);
|
||||||
|
void colorputs(const char* str, uint32_t fg, uint32_t bg);
|
||||||
void putcolor(int x, int y, unsigned int color);
|
void putcolor(int x, int y, unsigned int color);
|
||||||
char getchar(int x, int y);
|
char getchar(int x, int y);
|
||||||
unsigned int getcolor(int x, int y);
|
unsigned int getcolor(int x, int y);
|
||||||
void scroll(int lines);
|
|
||||||
void putc(char c);
|
void putc(char c);
|
||||||
void colorputc(char c, unsigned int color);
|
void colorputc(char c, uint32_t fg, uint32_t bg);
|
||||||
|
void colorprintf(uint32_t fg, uint32_t bg, const char* fmt, ...);
|
||||||
|
int* colorprintf_number(int* argp, int length, bool sign, int radix, int width, char pad_char, uint32_t fg, uint32_t bg);
|
||||||
|
|
||||||
#define PRINTF_STATE_START 0
|
#define PRINTF_STATE_START 0
|
||||||
#define PRINTF_STATE_LENGTH 1
|
#define PRINTF_STATE_LENGTH 1
|
||||||
#define PRINTF_STATE_SHORT 2
|
#define PRINTF_STATE_SHORT 2
|
||||||
#define PRINTF_STATE_LONG 3
|
#define PRINTF_STATE_LONG 3
|
||||||
#define PRINTF_STATE_SPEC 4
|
#define PRINTF_STATE_SPEC 4
|
||||||
|
#define PRINTF_STATE_WIDTH 5
|
||||||
|
|
||||||
#define PRINTF_LENGTH_START 0
|
#define PRINTF_LENGTH_START 0
|
||||||
#define PRINTF_LENGTH_SHORT_SHORT 1
|
#define PRINTF_LENGTH_SHORT_SHORT 1
|
||||||
@@ -36,8 +52,46 @@ void colorputc(char c, unsigned int color);
|
|||||||
#define PRINTF_LENGTH_LONG_LONG 4
|
#define PRINTF_LENGTH_LONG_LONG 4
|
||||||
|
|
||||||
void printf(const char* fmt, ...);
|
void printf(const char* fmt, ...);
|
||||||
int* printf_number(int* argp, int length, bool sign, int radix);
|
int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char);
|
||||||
int getch();
|
int getch();
|
||||||
void get_input(char *buffer, int size);
|
void get_input(char *buffer, int size);
|
||||||
|
void dtostrf(double val, char *buffer, int precision);
|
||||||
|
|
||||||
|
enum Colors
|
||||||
|
{
|
||||||
|
// AARRGGBB?
|
||||||
|
white = 0xFFFFFFFF,
|
||||||
|
black = 0x00000000,
|
||||||
|
red = 0x00FF0000,
|
||||||
|
green = 0x0000FF00,
|
||||||
|
blue = 0x000000FF,
|
||||||
|
yellow = 0x00FFFF00,
|
||||||
|
cyan = 0x0000FFFF,
|
||||||
|
magenta = 0x00FF00FF,
|
||||||
|
orange = 0x00FFA500,
|
||||||
|
purple = 0x00800080,
|
||||||
|
brown = 0x00A52A2A,
|
||||||
|
gray = 0x00808080,
|
||||||
|
pink = 0x00FFC0CB,
|
||||||
|
lime = 0x00BFFF00,
|
||||||
|
navy = 0x00000080,
|
||||||
|
teal = 0x00008080,
|
||||||
|
maroon = 0x00800000,
|
||||||
|
olive = 0x00808000,
|
||||||
|
silver = 0x00C0C0C0,
|
||||||
|
gold = 0x00FFD700,
|
||||||
|
indigo = 0x004B0082,
|
||||||
|
violet = 0x00EE82EE,
|
||||||
|
coral = 0x00FF7F50,
|
||||||
|
turquoise = 0x0040E0D0,
|
||||||
|
salmon = 0x00FA8072,
|
||||||
|
chocolate = 0x00D2691E,
|
||||||
|
khaki = 0x00F0E68C,
|
||||||
|
lavender = 0x00E6E6FA,
|
||||||
|
beige = 0x00F5F5DC
|
||||||
|
};
|
||||||
|
|
||||||
|
int get_cursor_x();
|
||||||
|
int get_cursor_y();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
int strlen(char* str)
|
// String operations implementation for blankos/libc
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
|
||||||
|
int strlen(const char* str)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
while (*str++)
|
while (*str++)
|
||||||
@@ -8,7 +16,7 @@ int strlen(char* str)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int strcmp(char* str1, char* str2)
|
int strcmp(const char* str1, const char* str2)
|
||||||
{
|
{
|
||||||
while (*str1 && (*str1 == *str2))
|
while (*str1 && (*str1 == *str2))
|
||||||
{
|
{
|
||||||
@@ -17,3 +25,110 @@ int strcmp(char* str1, char* str2)
|
|||||||
}
|
}
|
||||||
return *(const unsigned char*)str1 - *(const unsigned char*)str2;
|
return *(const unsigned char*)str1 - *(const unsigned char*)str2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* strchr(const char* str, int c)
|
||||||
|
{
|
||||||
|
while (*str)
|
||||||
|
{
|
||||||
|
if (*str == (char)c)
|
||||||
|
{
|
||||||
|
return (char*)str;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
if (c == '\0')
|
||||||
|
{
|
||||||
|
return (char*)str;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strtok(char* str, const char* delimiter)
|
||||||
|
{
|
||||||
|
static char* last;
|
||||||
|
if (str)
|
||||||
|
{
|
||||||
|
last = str;
|
||||||
|
} else {
|
||||||
|
str = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str || *str == '\0')
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* token_start = str;
|
||||||
|
while (*str && !strchr(delimiter, *str))
|
||||||
|
{
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*str)
|
||||||
|
{
|
||||||
|
*str = '\0';
|
||||||
|
last = str + 1;
|
||||||
|
} else {
|
||||||
|
last = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int atoi(char* str)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (int i=0; str[i] != '\0'; i++)
|
||||||
|
{
|
||||||
|
result = result*10 + str[i] - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void strcat(char* dest, const char* src)
|
||||||
|
{
|
||||||
|
while (*dest)
|
||||||
|
{
|
||||||
|
dest++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src)
|
||||||
|
{
|
||||||
|
*dest = *src;
|
||||||
|
dest++;
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strnlen(const char* str, size_t max_len)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
while (*str && len < max_len)
|
||||||
|
{
|
||||||
|
len++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void strncat(char* dest, const char* src, size_t n)
|
||||||
|
{
|
||||||
|
while (*dest)
|
||||||
|
{
|
||||||
|
dest++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src && n > 0)
|
||||||
|
{
|
||||||
|
*dest = *src;
|
||||||
|
dest++;
|
||||||
|
src++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = '\0';
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,21 @@
|
|||||||
#ifndef INCLUDE_STRING_H
|
// String operations implementation for blankos/libc header
|
||||||
#define INCLUDE_STRING_H
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
int strlen(char* str);
|
#ifndef STRING_H
|
||||||
int strcmp(char* str1, char* str2);
|
#define STRING_H
|
||||||
|
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
|
||||||
|
int strlen(const char* str);
|
||||||
|
int strcmp(const char* str1, const char* str2);
|
||||||
|
char* strtok(char* str, const char* delimiter);
|
||||||
|
int atoi(char* str);
|
||||||
|
void strcat(char* dest, const char* src);
|
||||||
|
|
||||||
|
// Safer functions
|
||||||
|
size_t strnlen(const char* str, size_t max_len);
|
||||||
|
void strncat(char* dest, const char* src, size_t n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
|
// Simple brainfuck interpreter program
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
|
#include "../kernel/kmain.h"
|
||||||
|
#include "../kernel/initrd.h"
|
||||||
|
|
||||||
#define BUF_SIZE 256
|
#define BUF_SIZE 256
|
||||||
|
|
||||||
@@ -44,12 +50,25 @@ void brainfuck(char* input)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void program_bf()
|
void program_bf(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
char input_buffer[BUF_SIZE];
|
char input_buffer[BUF_SIZE];
|
||||||
puts("Brainfuck code? ");
|
puts("Brainfuck code? ");
|
||||||
get_input(input_buffer, BUF_SIZE);
|
get_input(input_buffer, BUF_SIZE);
|
||||||
brainfuck(input_buffer);
|
brainfuck(input_buffer);
|
||||||
//brainfuck(",[.[-],]");
|
|
||||||
puts("\n");
|
puts("\n");
|
||||||
|
} else if (argc == 2) {
|
||||||
|
// Read file content into buffer, then interpret it
|
||||||
|
char input_buffer[BUF_SIZE];
|
||||||
|
int read = tar_file_to_buffer((uint8_t*)initrd_addr, argv[1], input_buffer);
|
||||||
|
if (read == 0)
|
||||||
|
{
|
||||||
|
brainfuck(input_buffer);
|
||||||
|
puts("\n");
|
||||||
|
} else {
|
||||||
|
printf("Could not find file '%s'\n", argv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
99
src/programs/bmp.c
Normal file
99
src/programs/bmp.c
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Bitmap image renderer
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../kernel/kmain.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../kernel/initrd.h"
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../drivers/serial.h"
|
||||||
|
#include "../kernel/kheap.h"
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t bfType;
|
||||||
|
uint32_t bfSize;
|
||||||
|
uint16_t bfReserved1;
|
||||||
|
uint16_t bfReserved2;
|
||||||
|
uint32_t bfOffBits;
|
||||||
|
} BMPHeader;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t biSize;
|
||||||
|
int32_t biWidth;
|
||||||
|
int32_t biHeight;
|
||||||
|
uint16_t biPlanes;
|
||||||
|
uint16_t biBitCount;
|
||||||
|
uint32_t biCompression;
|
||||||
|
uint32_t biSizeImage;
|
||||||
|
int32_t biXPelsPerMeter;
|
||||||
|
int32_t biYPelsPerMeter;
|
||||||
|
uint32_t biClrUsed;
|
||||||
|
uint32_t biClrImportant;
|
||||||
|
} BMPInfoHeader;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
void display_bmp(uint32_t* fb, int pitch, int bpp, uint8_t* initrd, const char* filename)
|
||||||
|
{
|
||||||
|
uint32_t buf_size = tar_get_file_size(initrd, filename);
|
||||||
|
char* buffer = (char*)malloc(buf_size);
|
||||||
|
int file_status = tar_file_to_buffer(initrd, filename, buffer);
|
||||||
|
|
||||||
|
if (file_status != 0)
|
||||||
|
{
|
||||||
|
printf("Error loading file '%s'\n", filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BMPHeader* bmp_header = (BMPHeader*)buffer;
|
||||||
|
BMPInfoHeader* bmp_info = (BMPInfoHeader*) (buffer+sizeof(BMPHeader));
|
||||||
|
|
||||||
|
if (bmp_header->bfType != 0x4D42)
|
||||||
|
{
|
||||||
|
printf("'%s' is not a valid BMP file\n", filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = bmp_info->biWidth;
|
||||||
|
int height = bmp_info->biHeight;
|
||||||
|
int pixel_offset = bmp_header->bfOffBits;
|
||||||
|
|
||||||
|
printf("%d-bit BMP, width: %d, height: %d, pixel offset: %d\n", bmp_info->biBitCount, bmp_info->biWidth, bmp_info->biHeight, (int)bmp_header->bfOffBits);
|
||||||
|
erase_cursor();
|
||||||
|
uint8_t* pixel_data = (uint8_t*)(buffer + pixel_offset);
|
||||||
|
|
||||||
|
int cursor_y = (get_cursor_y()+1)*16;
|
||||||
|
serial_printf(3, "cursor_y=%d\n", cursor_y);
|
||||||
|
|
||||||
|
for (int y=cursor_y; y<height+cursor_y; y++)
|
||||||
|
{
|
||||||
|
for (int x=0; x<width; x++)
|
||||||
|
{
|
||||||
|
int index = (x+(height-y-1+cursor_y)*width)*3;
|
||||||
|
uint8_t blue = pixel_data[index];
|
||||||
|
uint8_t green = pixel_data[index+1];
|
||||||
|
uint8_t red = pixel_data[index+2];
|
||||||
|
|
||||||
|
uint32_t color = (0xFF << 24) | (red << 16) | (green << 8) | blue;
|
||||||
|
putpixel(fb, pitch, bpp, x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update cursor pos after image drawing
|
||||||
|
move_cursor(get_cursor_x(), get_cursor_y()+(height/16)+2);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_bmp(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
puts("Usage: bmp <file>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
display_bmp(framebuffer, pitch, bpp, (uint8_t*)initrd_addr, argv[1]);
|
||||||
|
}
|
||||||
160
src/programs/ciphers.c
Normal file
160
src/programs/ciphers.c
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// Cipher programs
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "ciphers.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void rot13(char* input, char* output)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (input[i] != '\0')
|
||||||
|
{
|
||||||
|
char c = input[i];
|
||||||
|
|
||||||
|
if (c >= 'a' && c <= 'z') {
|
||||||
|
output[i] = ((c - 'a' + 13) % 26) + 'a';
|
||||||
|
} else if (c >= 'A' && c <= 'Z') {
|
||||||
|
output[i] = ((c - 'A' + 13) % 26) + 'A';
|
||||||
|
} else {
|
||||||
|
output[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
output[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_rot13(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s <string>\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char input_buffer[BUFFER_SIZE] = {0};
|
||||||
|
char output[BUFFER_SIZE] = {0};
|
||||||
|
|
||||||
|
for (int i=1; i<argc; i++)
|
||||||
|
{
|
||||||
|
strcat(input_buffer, argv[i]);
|
||||||
|
if (i<argc-1)
|
||||||
|
{
|
||||||
|
strcat(input_buffer, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rot13(input_buffer, output);
|
||||||
|
printf("%s\n", output);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* morse_alphabet[] = {
|
||||||
|
".-", // A
|
||||||
|
"-...", // B
|
||||||
|
"-.-.", // C
|
||||||
|
"-..", // D
|
||||||
|
".", // E
|
||||||
|
"..-.", // F
|
||||||
|
"--.", // G
|
||||||
|
"....", // H
|
||||||
|
"..", // I
|
||||||
|
".---", // J
|
||||||
|
"-.-", // K
|
||||||
|
".-..", // L
|
||||||
|
"--", // M
|
||||||
|
"-.", // N
|
||||||
|
"---", // O
|
||||||
|
".--.", // P
|
||||||
|
"--.-", // Q
|
||||||
|
".-.", // R
|
||||||
|
"...", // S
|
||||||
|
"-", // T
|
||||||
|
"..-", // U
|
||||||
|
"...-", // V
|
||||||
|
".--", // W
|
||||||
|
"-..-", // X
|
||||||
|
"-.--", // Y
|
||||||
|
"--.." // Z
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* morse_digits[] = {
|
||||||
|
"-----", // 0
|
||||||
|
".----", // 1
|
||||||
|
"..---", // 2
|
||||||
|
"...--", // 3
|
||||||
|
"....-", // 4
|
||||||
|
".....", // 5
|
||||||
|
"-....", // 6
|
||||||
|
"--...", // 7
|
||||||
|
"---..", // 8
|
||||||
|
"----." // 9
|
||||||
|
};
|
||||||
|
|
||||||
|
void to_morse(const char* input, char* output) {
|
||||||
|
int i = 0;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (input[i] != '\0') {
|
||||||
|
char c = input[i];
|
||||||
|
|
||||||
|
if (c >= 'a' && c <= 'z') {
|
||||||
|
const char* morse_code = morse_alphabet[c - 'a'];
|
||||||
|
int j = 0;
|
||||||
|
while (morse_code[j] != '\0') {
|
||||||
|
output[pos++] = morse_code[j++];
|
||||||
|
}
|
||||||
|
} else if (c >= 'A' && c <= 'Z') {
|
||||||
|
const char* morse_code = morse_alphabet[c - 'A'];
|
||||||
|
int j = 0;
|
||||||
|
while (morse_code[j] != '\0') {
|
||||||
|
output[pos++] = morse_code[j++];
|
||||||
|
}
|
||||||
|
} else if (c >= '0' && c <= '9') {
|
||||||
|
const char* morse_code = morse_digits[c - '0'];
|
||||||
|
int j = 0;
|
||||||
|
while (morse_code[j] != '\0') {
|
||||||
|
output[pos++] = morse_code[j++];
|
||||||
|
}
|
||||||
|
} else if (c == ' ') {
|
||||||
|
output[pos++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
output[pos++] = ' ';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos > 0) {
|
||||||
|
output[pos - 1] = '\0';
|
||||||
|
} else {
|
||||||
|
output[pos] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_morse(int argc, char* argv[]) {
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s <string>\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char output[512];
|
||||||
|
char message[BUFFER_SIZE];
|
||||||
|
|
||||||
|
for (int i=1; i<argc; i++)
|
||||||
|
{
|
||||||
|
strcat(message, argv[i]);
|
||||||
|
if (i < argc-1)
|
||||||
|
{
|
||||||
|
strcat(message, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
to_morse(message, output);
|
||||||
|
printf("%s\n", output);
|
||||||
|
}
|
||||||
|
|
||||||
11
src/programs/ciphers.h
Normal file
11
src/programs/ciphers.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Cipher programs header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef CIPHERS_H
|
||||||
|
#define CIPHERS_H
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 256
|
||||||
|
|
||||||
|
#endif
|
||||||
136
src/programs/conway.c
Normal file
136
src/programs/conway.c
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// Conway's Game of Life program
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "conway.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../drivers/serial.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
|
void print_grid(const unsigned char grid[X][Y])
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
for (int i=0; i<X; i++)
|
||||||
|
{
|
||||||
|
for (int j=0; j<Y; j++)
|
||||||
|
{
|
||||||
|
if (grid[i][j] == LIVE) {
|
||||||
|
putc(35);
|
||||||
|
} else {
|
||||||
|
putc(32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int count_live_neighbors(const unsigned char grid[X][Y], int i, int j)
|
||||||
|
{
|
||||||
|
int live_neighbors = 0;
|
||||||
|
|
||||||
|
for (int x=-1; x<=1; x++)
|
||||||
|
{
|
||||||
|
for (int y=-1; y<=1; y++)
|
||||||
|
{
|
||||||
|
if (x==0 && y==0) continue;
|
||||||
|
|
||||||
|
int ni = i+x;
|
||||||
|
int nj = j+y;
|
||||||
|
|
||||||
|
if (ni >= 0 && ni < X && nj >= 0)
|
||||||
|
{
|
||||||
|
if (grid[ni][nj] == LIVE) live_neighbors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return live_neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void grid_new_generation(unsigned char grid[X][Y], unsigned char temp[X][Y])
|
||||||
|
{
|
||||||
|
for (int i=0; i<X; i++)
|
||||||
|
{
|
||||||
|
for (int j=0; j<Y; j++)
|
||||||
|
{
|
||||||
|
int cell = grid[i][j];
|
||||||
|
int live_neighbors = count_live_neighbors(grid, i, j);
|
||||||
|
|
||||||
|
if (cell == LIVE)
|
||||||
|
{
|
||||||
|
switch(live_neighbors)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
temp[i][j] = LIVE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
temp[i][j] = DEAD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cell == DEAD && live_neighbors == 3)
|
||||||
|
{
|
||||||
|
temp[i][j] = LIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<X; i++)
|
||||||
|
{
|
||||||
|
for (int j=0; j<Y; j++)
|
||||||
|
{
|
||||||
|
grid[i][j] = temp[i][j];
|
||||||
|
temp[i][j] = DEAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void soup(unsigned char grid[X][Y])
|
||||||
|
{
|
||||||
|
srand(global_ticks);
|
||||||
|
for (int i=0; i<X; i++)
|
||||||
|
{
|
||||||
|
for (int j=0; j<Y; j++)
|
||||||
|
{
|
||||||
|
grid[i][j] = rand_float() > SOUP_PROB ? LIVE : DEAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_conway(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
unsigned char grid[X][Y] = {0};
|
||||||
|
unsigned char temp[X][Y] = {0};
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
soup(grid);
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "-g") == 0) {
|
||||||
|
grid[1][2] = LIVE;
|
||||||
|
grid[2][3] = LIVE;
|
||||||
|
grid[3][1] = LIVE;
|
||||||
|
grid[3][2] = LIVE;
|
||||||
|
grid[3][3] = LIVE;
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "-l") == 0) {
|
||||||
|
grid[10][3] = LIVE; grid[10][4] = LIVE; grid[10][5] = LIVE; grid[10][6] = LIVE;
|
||||||
|
grid[11][2] = LIVE; grid[11][6] = LIVE;
|
||||||
|
grid[12][6] = LIVE;
|
||||||
|
grid[13][2] = LIVE; grid[13][5] = LIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_grid(grid);
|
||||||
|
puts("generation 0");
|
||||||
|
for (int i=1; i<GENERATIONS; i++)
|
||||||
|
{
|
||||||
|
grid_new_generation(grid, temp);
|
||||||
|
delay(DELAY);
|
||||||
|
clear();
|
||||||
|
print_grid(grid);
|
||||||
|
printf("generation %d", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
23
src/programs/conway.h
Normal file
23
src/programs/conway.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Conway's Game of Life program header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef CONWAY_H
|
||||||
|
#define CONWAY_H
|
||||||
|
|
||||||
|
#define X 66
|
||||||
|
#define Y 240
|
||||||
|
|
||||||
|
#define GENERATIONS 100
|
||||||
|
#define DEAD 0
|
||||||
|
#define LIVE 1
|
||||||
|
#define SOUP_PROB 0.7
|
||||||
|
#define DELAY 10
|
||||||
|
|
||||||
|
void print_grid(const unsigned char grid[X][Y]);
|
||||||
|
int count_live_neighbors(const unsigned char grid[X][Y], int i, int j);
|
||||||
|
void grid_new_generation(unsigned char grid[X][Y], unsigned char temp[X][Y]);
|
||||||
|
void soup(unsigned char grid[X][Y]);
|
||||||
|
|
||||||
|
#endif
|
||||||
72
src/programs/cowsay.c
Normal file
72
src/programs/cowsay.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// Cowsay-like program
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
|
#define MAX_MSG_LEN 128
|
||||||
|
|
||||||
|
const char* cow =
|
||||||
|
" \\ ^__^\n"
|
||||||
|
" \\ (oo)\\_______\n"
|
||||||
|
" (__)\\ )\\/\\\n"
|
||||||
|
" ||----w |\n"
|
||||||
|
" || ||\n";
|
||||||
|
|
||||||
|
void print_bubble(const char* message)
|
||||||
|
{
|
||||||
|
int len = strlen(message);
|
||||||
|
puts(" ");
|
||||||
|
for (int i=0; i<len+2; i++)
|
||||||
|
{
|
||||||
|
puts("_");
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
|
||||||
|
printf("< %s >\n", message);
|
||||||
|
|
||||||
|
puts(" ");
|
||||||
|
for (int i=0; i<len+2; i++)
|
||||||
|
{
|
||||||
|
puts("-");
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cowsay(char* msg, uint32_t fg, uint32_t bg)
|
||||||
|
{
|
||||||
|
print_bubble(msg);
|
||||||
|
colorputs(cow, fg, bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_cowsay(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s <message>\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char message[MAX_MSG_LEN];
|
||||||
|
message[0] = '\0';
|
||||||
|
|
||||||
|
for (int i=1; i<argc; i++)
|
||||||
|
{
|
||||||
|
if (strlen(message) + strlen(argv[i]) + 1 < MAX_MSG_LEN)
|
||||||
|
{
|
||||||
|
strcat(message, argv[i]);
|
||||||
|
if (i < argc-1)
|
||||||
|
{
|
||||||
|
strcat(message, " ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
puts("Too long message.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_bubble(message);
|
||||||
|
printf("%s", cow);
|
||||||
|
}
|
||||||
30
src/programs/fs.c
Normal file
30
src/programs/fs.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Filesystem utilities (for initrd)
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../kernel/initrd.h"
|
||||||
|
#include "../kernel/kmain.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
|
void program_ls(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
ls_initrd((uint8_t*)initrd_addr, 0);
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "-l") == 0) {
|
||||||
|
ls_initrd((uint8_t*)initrd_addr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic cat just to read, no concatenation here
|
||||||
|
void program_cat(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
puts("Usage: cat <file>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cat_initrd((uint8_t*)initrd_addr, argv[1]);
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
// Math expression lexer and parser
|
// Basic math expression lexer and parser program
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../libc/stdint.h"
|
#include <stdint.h>
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../libc/ctype.h"
|
#include "../libc/ctype.h"
|
||||||
|
|||||||
@@ -1,23 +1,53 @@
|
|||||||
// Miscellaneous small programs
|
// Miscellaneous small programs
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
#include "../drivers/ata.h"
|
||||||
|
#include "../drivers/rtc.h"
|
||||||
|
#include "../kernel/io.h"
|
||||||
|
#include "../drivers/pci.h"
|
||||||
|
|
||||||
// Print a rainbow colorful text for testing
|
// Print a rainbow colorful text for testing
|
||||||
|
|
||||||
#define BUF_SIZE 256
|
#define BUF_SIZE 256
|
||||||
#define COLORS 20
|
#define COLORS 20
|
||||||
|
|
||||||
void program_rainbow()
|
void program_rainbow(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
char input_buffer[BUF_SIZE];
|
if (argc < 2)
|
||||||
puts("What to print? ");
|
|
||||||
get_input(input_buffer, BUF_SIZE);
|
|
||||||
puts("\n");
|
|
||||||
|
|
||||||
for (int i=0; i<COLORS; i++)
|
|
||||||
{
|
{
|
||||||
colorputs(input_buffer, i);
|
printf("Usage: %s <string>\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char input_buffer[BUF_SIZE] = {0};
|
||||||
|
for (int i=1; i<argc; i++)
|
||||||
|
{
|
||||||
|
strcat(input_buffer, argv[i]);
|
||||||
|
if (i<argc-1)
|
||||||
|
{
|
||||||
|
strcat(input_buffer, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Colors colors[] = {
|
||||||
|
white, black, red, green, blue, yellow,
|
||||||
|
cyan, magenta, orange, purple, brown,
|
||||||
|
gray, pink, lime, navy, teal, maroon,
|
||||||
|
olive, silver, gold, indigo, violet,
|
||||||
|
coral, turquoise, salmon, chocolate,
|
||||||
|
khaki, lavender, beige
|
||||||
|
};
|
||||||
|
int colors_count = sizeof(colors)/sizeof(colors[0]);
|
||||||
|
|
||||||
|
for (int i=0; i<colors_count-1; i++)
|
||||||
|
{
|
||||||
|
colorputs(input_buffer, colors[i], colors[i+1]);
|
||||||
puts("\n");
|
puts("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +58,7 @@ void program_rainbow()
|
|||||||
|
|
||||||
void program_clear()
|
void program_clear()
|
||||||
{
|
{
|
||||||
for (int i=0; i<ROWS; i++) scroll(1);
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get uptime in ticks
|
// Get uptime in ticks
|
||||||
@@ -36,6 +66,88 @@ void program_clear()
|
|||||||
void program_uptime()
|
void program_uptime()
|
||||||
{
|
{
|
||||||
int ticks = uptime();
|
int ticks = uptime();
|
||||||
double seconds = ticks/18.2065; // PIC channel 0 freq
|
double seconds = ticks/18.2065; // PIT channel 0 freq
|
||||||
printf("%d ticks\t%f seconds\n", ticks, seconds);
|
printf("%d ticks\t%f seconds\n", ticks, seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get help
|
||||||
|
|
||||||
|
void program_help()
|
||||||
|
{
|
||||||
|
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\t uptime echo\t sysinfo\tconway\nrot13 morse\tcowsay time\t read\t reboot\npi\t ls\t cat\t bmp\t lspci\t naval\nsnake\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic
|
||||||
|
|
||||||
|
void program_panic()
|
||||||
|
{
|
||||||
|
asm volatile("int $0x13");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output input
|
||||||
|
|
||||||
|
void program_echo(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
for (int i=1; i<argc; i++)
|
||||||
|
{
|
||||||
|
puts(argv[i]);
|
||||||
|
if (i < argc-1) {
|
||||||
|
putc(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current RTC time
|
||||||
|
|
||||||
|
void program_time()
|
||||||
|
{
|
||||||
|
rtc_time_t time;
|
||||||
|
rtc_read_time(&time);
|
||||||
|
puts("Current RTC time: ");
|
||||||
|
print_time(&time);
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a sector
|
||||||
|
|
||||||
|
void program_read(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s <sector>\n", argv[0]);
|
||||||
|
} else if (argc == 2)
|
||||||
|
{
|
||||||
|
uint8_t buffer[512];
|
||||||
|
ata_read_sector(atoi(argv[1]), buffer);
|
||||||
|
|
||||||
|
for (int i=0; i<512; i++)
|
||||||
|
{
|
||||||
|
if (i%50==0) puts("\n"); // hardcoded = bad
|
||||||
|
printf("%02x ", buffer[i]);
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
puts("Invalid argument number\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reboots the machine (might just shutdown)
|
||||||
|
|
||||||
|
void program_reboot()
|
||||||
|
{
|
||||||
|
puts("Rebooting...\n");
|
||||||
|
|
||||||
|
while(inb(0x64) & 0x02);
|
||||||
|
outb(0x64, 0xFE);
|
||||||
|
|
||||||
|
while (1) asm volatile("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
// List PCI buses and devices
|
||||||
|
|
||||||
|
void program_lspci()
|
||||||
|
{
|
||||||
|
scan_pci_bus();
|
||||||
|
}
|
||||||
|
|||||||
348
src/programs/navalbattle.c
Normal file
348
src/programs/navalbattle.c
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
// Simplified naval battle game
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "navalbattle.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
#include "../kernel/kheap.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
#include "../drivers/serial.h"
|
||||||
|
|
||||||
|
// Porting problems:
|
||||||
|
// - Color printf? (Need to implement ANSI escape sequences).
|
||||||
|
// - Scanf?
|
||||||
|
// - Malloc? (proof of concept)
|
||||||
|
|
||||||
|
void program_navalbattle()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
grid_t* grid[SIZE][SIZE];
|
||||||
|
grid_t* enemyGrid[SIZE][SIZE];
|
||||||
|
|
||||||
|
init_battlefield(grid);
|
||||||
|
init_battlefield(enemyGrid);
|
||||||
|
|
||||||
|
placing_ally_ships(grid);
|
||||||
|
puts("Now, time for the enemies to prepare...\n");
|
||||||
|
placing_enemy_ships(enemyGrid);
|
||||||
|
|
||||||
|
delay((rand()%MAX_WAIT_TIME)+10);
|
||||||
|
|
||||||
|
puts("Here we go!\n");
|
||||||
|
show_game_stats(grid, enemyGrid);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ally_do_attack(enemyGrid);
|
||||||
|
enemy_do_attack(grid);
|
||||||
|
show_game_stats(grid, enemyGrid);
|
||||||
|
} while (check_victory(grid, enemyGrid) == 0);
|
||||||
|
|
||||||
|
free_grid(grid);
|
||||||
|
free_grid(enemyGrid);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_battlefield(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
grid[i][j] = (grid_t*)malloc(sizeof(grid_t));
|
||||||
|
grid[i][j]->x = i;
|
||||||
|
grid[i][j]->y = j;
|
||||||
|
grid[i][j]->role = 0;
|
||||||
|
grid[i][j]->state = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid memory leaks..
|
||||||
|
void free_grid(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
free(grid[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_ally_battlefield(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
puts("\n*** Ally grid ***\n");
|
||||||
|
puts(" 0 1 2 3 4 5\n");
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
printf("%d ", i);
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
char roleChar = 0;
|
||||||
|
switch(grid[i][j]->state)
|
||||||
|
{
|
||||||
|
case -2:
|
||||||
|
roleChar = 32; // space
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
roleChar = 120;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
roleChar = 79;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
roleChar = 88;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Error: bad value in grid at x=%d y=%d\n", grid[i][j]->x, grid[i][j]->y);
|
||||||
|
shell_install();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == SIZE-1)
|
||||||
|
{
|
||||||
|
printf("%c]", roleChar);
|
||||||
|
} else if (j == 0) {
|
||||||
|
printf("[%c|", roleChar);
|
||||||
|
} else {
|
||||||
|
printf("%c|", roleChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void placing_ally_ships(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
puts("==== Allied preparation phase =====\nPlease enter the positions for your ships, sir.\n");
|
||||||
|
|
||||||
|
for (size_t i=0; i<BOATS; i++)
|
||||||
|
{
|
||||||
|
int posX = 0, posY = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
printf("Ship %d\n------\n", (int)i);
|
||||||
|
puts("X coord: ");
|
||||||
|
char input_buffer[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer, BUFFER_SIZE);
|
||||||
|
posY = atoi(input_buffer);
|
||||||
|
|
||||||
|
puts("\nY coord: ");
|
||||||
|
char input_buffer2[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer2, BUFFER_SIZE);
|
||||||
|
posX = atoi(input_buffer2);
|
||||||
|
|
||||||
|
puts("\n");
|
||||||
|
if (posX < 0 || posX >= SIZE || posY < 0 || posY >= SIZE)
|
||||||
|
{
|
||||||
|
printf("Invalid position x=%d y=%d, please retry.\n", posX, posY);
|
||||||
|
}
|
||||||
|
if (grid[posX][posY]->role == 1)
|
||||||
|
{
|
||||||
|
printf("A ship is already in x=%d y=%d, please retry.\n", posX, posY);
|
||||||
|
}
|
||||||
|
} while (posX < 0 || posX >= SIZE || posY < 0 || posY >= SIZE || grid[posX][posY]->role == 1);
|
||||||
|
|
||||||
|
grid[posX][posY]->role = 1;
|
||||||
|
grid[posX][posY]->state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void placing_enemy_ships(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<BOATS; i++)
|
||||||
|
{
|
||||||
|
int posX = 0, posY = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
posX = rand() % SIZE;
|
||||||
|
posY = rand() % SIZE;
|
||||||
|
} while (grid[posX][posY]->role != 0);
|
||||||
|
|
||||||
|
grid[posX][posY]->role = 1;
|
||||||
|
grid[posX][posY]->state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_enemy_battlefield(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
puts("\n*** Enemy grid ***\n");
|
||||||
|
puts(" 0 1 2 3 4 5\n");
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
printf("%d ", (int)i);
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
char roleChar = 0;
|
||||||
|
switch(grid[i][j]->state)
|
||||||
|
{
|
||||||
|
case -2:
|
||||||
|
case 0:
|
||||||
|
roleChar = 32;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
roleChar = 120;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
roleChar = 88;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Error: bad value in battlefield at x=%d y=%d\n", grid[i][j]->x, grid[i][j]->y);
|
||||||
|
shell_install();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j == SIZE-1)
|
||||||
|
{
|
||||||
|
printf("%c]", roleChar);
|
||||||
|
} else if (j == 0) {
|
||||||
|
printf("[%c|", roleChar);
|
||||||
|
} else {
|
||||||
|
printf("%c|", roleChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_remaining_boats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int allyShips = 0;
|
||||||
|
int enemyShips = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
if (allyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
allyShips++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
enemyShips++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%d ally ships and %d enemy ships remaining.\n", allyShips, enemyShips);
|
||||||
|
allyShips >= enemyShips ? colorputs("The allies are in a good posture.\n", yellow, black) : colorputs("The allies are losing terrain...\n", salmon, black);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_game_stats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
colorputs("\n\n\nShowing known information:\n\n", cyan, black);
|
||||||
|
show_ally_battlefield(allyGrid);
|
||||||
|
show_enemy_battlefield(enemyGrid);
|
||||||
|
show_remaining_boats(allyGrid, enemyGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_attack(grid_t* grid[SIZE][SIZE], int x, int y)
|
||||||
|
{
|
||||||
|
switch(grid[x][y]->state)
|
||||||
|
{
|
||||||
|
case -2: // Untouched ocean
|
||||||
|
colorputs("The torpedo explodes in water. Missed.\n", orange, black);
|
||||||
|
grid[x][y]->state = -1;
|
||||||
|
delay(30);
|
||||||
|
break;
|
||||||
|
case -1: // Already hit ocean
|
||||||
|
colorputs("We already striked here, sir... Too late.\n", orange, black);
|
||||||
|
break;
|
||||||
|
case 0: // Ship
|
||||||
|
colorputs("Hit! Well done!\n", green, black);
|
||||||
|
grid[x][y]->state = 1;
|
||||||
|
delay(30);
|
||||||
|
break;
|
||||||
|
case 1: // Already hit ship
|
||||||
|
colorputs("Sir, we already sunk that ship... (looser)\n", orange, black);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ally_do_attack(grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int x = 0, y = 0;
|
||||||
|
colorputs("\n* Ally attack preparation *\n", blue, black);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// yes, x and y are inverted.
|
||||||
|
puts("X coord: ");
|
||||||
|
char input_buffer[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer, BUFFER_SIZE);
|
||||||
|
y = atoi(input_buffer);
|
||||||
|
|
||||||
|
puts("\nY coord: ");
|
||||||
|
char input_buffer2[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer2, BUFFER_SIZE);
|
||||||
|
x = atoi(input_buffer2);
|
||||||
|
|
||||||
|
puts("\n");
|
||||||
|
|
||||||
|
if (x < 0 || x >= SIZE || y < 0 || y >= SIZE)
|
||||||
|
{
|
||||||
|
puts("Sir, this zone is not in our operation area! Please retry.\n");
|
||||||
|
}
|
||||||
|
} while (x < 0 || x >= SIZE || y < 0 || y >= SIZE);
|
||||||
|
|
||||||
|
do_attack(enemyGrid, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enemy_do_attack(grid_t* allyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int x = 0, y = 0;
|
||||||
|
colorputs("\n* Enemies are preparing for attack, everyone take shelter! *\n", blue, black);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
x = rand() % SIZE;
|
||||||
|
y = rand() % SIZE;
|
||||||
|
} while (allyGrid[x][y]->state == -1 || allyGrid[x][y]->state == 1);
|
||||||
|
|
||||||
|
delay((rand()%MAX_WAIT_TIME)+10);
|
||||||
|
do_attack(allyGrid, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_victory(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int allyShips = 0;
|
||||||
|
int enemyShips = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
if (allyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
allyShips++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
enemyShips++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allyShips > 0 && enemyShips == 0)
|
||||||
|
{
|
||||||
|
colorputs("The allies have won! Congratulations, chief!\n", green, black);
|
||||||
|
return 1;
|
||||||
|
} else if (enemyShips > 0 && allyShips == 0)
|
||||||
|
{
|
||||||
|
colorputs("The ennemies have won.. We must retreat.\n", red, black);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
37
src/programs/navalbattle.h
Normal file
37
src/programs/navalbattle.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Simplified naval battle game header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef NAVALBATTLE_H
|
||||||
|
#define NAVALBATTLE_H
|
||||||
|
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int role;
|
||||||
|
int state;
|
||||||
|
} grid_t;
|
||||||
|
|
||||||
|
#define SIZE 6
|
||||||
|
#define BOATS 5
|
||||||
|
#define MAX_WAIT_TIME 20
|
||||||
|
#define BUFFER_SIZE 16
|
||||||
|
|
||||||
|
void init_battlefield(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void free_grid(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void show_ally_battlefield(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void placing_ally_ships(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void placing_enemy_ships(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void show_enemy_battlefield(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void show_remaining_boats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
void show_game_stats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
void do_attack(grid_t* grid[SIZE][SIZE], int x, int y);
|
||||||
|
void ally_do_attack(grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
void enemy_do_attack(grid_t* allyGrid[SIZE][SIZE]);
|
||||||
|
int check_victory(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
|
||||||
|
#endif
|
||||||
34
src/programs/pi.c
Normal file
34
src/programs/pi.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Program for Pi computation using Leibniz series
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
|
void program_pi(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
printf("Usage: %s <terms>\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double pi = 0.0;
|
||||||
|
int terms = atoi(argv[1]);
|
||||||
|
|
||||||
|
for (int i=0; i<terms; i++)
|
||||||
|
{
|
||||||
|
double term = 1.0/(2*i+1);
|
||||||
|
if (i%2 == 0)
|
||||||
|
{
|
||||||
|
pi += term;
|
||||||
|
} else {
|
||||||
|
pi -= term;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pi *= 4;
|
||||||
|
|
||||||
|
printf("%f\n", pi);
|
||||||
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
#include "../libc/stdint.h"
|
// Prime number computation program
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
#define PRIMES_MAX 1000000
|
#define PRIMES_MAX 1000000
|
||||||
|
|
||||||
@@ -11,15 +17,28 @@ bool isPrime(int n)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void program_primes()
|
void program_primes(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
for (long long x=0; x<PRIMES_MAX; x++)
|
int primes_max;
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
{
|
{
|
||||||
if (isPrime(x))
|
primes_max = PRIMES_MAX;
|
||||||
|
} else if (argc == 2)
|
||||||
{
|
{
|
||||||
printf("%d ", x);
|
primes_max = atoi(argv[1]);
|
||||||
}
|
}
|
||||||
delay(2);
|
|
||||||
|
for (long long x=0; x<primes_max; x++)
|
||||||
|
{
|
||||||
|
if (isPrime(x) && x != 3301)
|
||||||
|
{
|
||||||
|
printf("%d ", (int)x);
|
||||||
|
} else if(x == 3301)
|
||||||
|
{
|
||||||
|
colorputs("3301 ", red, black);
|
||||||
|
}
|
||||||
|
delay(1);
|
||||||
}
|
}
|
||||||
puts("\n");
|
puts("\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
// Global program entry points header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#ifndef PROGRAMS_H
|
#ifndef PROGRAMS_H
|
||||||
#define PROGRAMS_H
|
#define PROGRAMS_H
|
||||||
|
|
||||||
@@ -5,10 +10,39 @@ void program_words();
|
|||||||
void program_primes();
|
void program_primes();
|
||||||
void program_math();
|
void program_math();
|
||||||
void program_bf();
|
void program_bf();
|
||||||
|
void program_sysinfo();
|
||||||
|
|
||||||
|
void get_cpuid();
|
||||||
|
void get_meminfo(unsigned int multiboot_info_address); // to be fixed: cannot get full memory map (sysinfo -v)
|
||||||
|
void program_cowsay();
|
||||||
|
void cowsay(); // Splash screen
|
||||||
|
void program_pi();
|
||||||
|
|
||||||
|
// Ciphers
|
||||||
|
void program_rot13();
|
||||||
|
void program_morse();
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
void program_rainbow();
|
void program_rainbow();
|
||||||
void program_clear();
|
void program_clear();
|
||||||
void program_uptime();
|
void program_uptime();
|
||||||
|
void program_panic();
|
||||||
|
void program_help();
|
||||||
|
void program_echo();
|
||||||
|
void program_time();
|
||||||
|
void program_read();
|
||||||
|
void program_reboot();
|
||||||
|
|
||||||
|
// Filesystem (initrd)
|
||||||
|
void program_ls();
|
||||||
|
void program_cat();
|
||||||
|
|
||||||
|
void program_bmp();
|
||||||
|
void program_lspci();
|
||||||
|
|
||||||
|
// Games
|
||||||
|
void program_navalbattle();
|
||||||
|
void program_conway();
|
||||||
|
void program_snake();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
200
src/programs/snake.c
Normal file
200
src/programs/snake.c
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
// Snake game
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
#include "../drivers/kb.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
|
||||||
|
#define WIDTH 25
|
||||||
|
#define HEIGHT 25
|
||||||
|
#define PIXEL_SIZE 20
|
||||||
|
#define MAX_SNAKE_LENGTH 256
|
||||||
|
// to add:
|
||||||
|
// sound
|
||||||
|
// optimization (shit)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} SnakeSegment;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SnakeSegment segments[MAX_SNAKE_LENGTH];
|
||||||
|
int length;
|
||||||
|
int dx;
|
||||||
|
int dy;
|
||||||
|
} Snake;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} Food;
|
||||||
|
|
||||||
|
Snake snake;
|
||||||
|
Food food;
|
||||||
|
int score = 0;
|
||||||
|
bool onSnake;
|
||||||
|
|
||||||
|
int is_snake(int x, int y);
|
||||||
|
|
||||||
|
void init_game()
|
||||||
|
{
|
||||||
|
snake.length = 1;
|
||||||
|
snake.segments[0].x = WIDTH/2;
|
||||||
|
snake.segments[0].y = HEIGHT/2;
|
||||||
|
snake.dx = 1;
|
||||||
|
snake.dy = 0;
|
||||||
|
|
||||||
|
food.x = rand() % (WIDTH-1);
|
||||||
|
food.y = rand() % (HEIGHT-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_board()
|
||||||
|
{
|
||||||
|
for (int y=0; y<=HEIGHT; y++)
|
||||||
|
{
|
||||||
|
for (int x=0; x<=WIDTH; x++)
|
||||||
|
{
|
||||||
|
if (x == 0 || x == WIDTH || y == 0 || y == HEIGHT)
|
||||||
|
{
|
||||||
|
draw_square(x, y, white, PIXEL_SIZE);
|
||||||
|
}
|
||||||
|
else if (is_snake(x, y)) {
|
||||||
|
draw_square(x, y, green, PIXEL_SIZE);
|
||||||
|
} else if(x == food.x && y == food.y) {
|
||||||
|
draw_square(x, y, red, PIXEL_SIZE);
|
||||||
|
} else {
|
||||||
|
draw_square(x, y, black, PIXEL_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
move_cursor(WIDTH+42, 2);
|
||||||
|
colorputs("Snake Game!", black, green);
|
||||||
|
move_cursor(WIDTH+42, 4);
|
||||||
|
colorprintf(yellow, black, "Score: %d", score);
|
||||||
|
move_cursor(WIDTH+42, 5);
|
||||||
|
puts("Use WASD keys to move");
|
||||||
|
move_cursor(WIDTH+42, 6);
|
||||||
|
puts("Press Q to quit");
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_snake(int x, int y)
|
||||||
|
{
|
||||||
|
for (int i=0; i<snake.length; i++)
|
||||||
|
{
|
||||||
|
if (snake.segments[i].x == x && snake.segments[i].y == y)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_snake()
|
||||||
|
{
|
||||||
|
for (int i=snake.length-1; i>0; i--)
|
||||||
|
{
|
||||||
|
snake.segments[i] = snake.segments[i-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
snake.segments[0].x += snake.dx;
|
||||||
|
snake.segments[0].y += snake.dy;
|
||||||
|
|
||||||
|
if (snake.segments[0].x < 0) snake.segments[0].x = WIDTH-1;
|
||||||
|
if (snake.segments[0].x >= WIDTH) snake.segments[0].x = 0;
|
||||||
|
if (snake.segments[0].y < 0) snake.segments[0].y = HEIGHT-1;
|
||||||
|
if (snake.segments[0].y >= HEIGHT) snake.segments[0].y = 0;
|
||||||
|
|
||||||
|
if (snake.segments[0].x == food.x && snake.segments[0].y == food.y)
|
||||||
|
{
|
||||||
|
snake.length++;
|
||||||
|
score++;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
onSnake = false;
|
||||||
|
food.x = rand() % (WIDTH-1) + 1;
|
||||||
|
food.y = rand() % (HEIGHT-1) + 1;
|
||||||
|
|
||||||
|
for (int i=0; i<snake.length; i++)
|
||||||
|
{
|
||||||
|
if (snake.segments[i].x == food.x && snake.segments[i].y == food.y)
|
||||||
|
{
|
||||||
|
onSnake = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (onSnake);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=1; i<snake.length; i++)
|
||||||
|
{
|
||||||
|
if (snake.segments[0].x == snake.segments[i].x && snake.segments[0].y == snake.segments[i].y)
|
||||||
|
{
|
||||||
|
|
||||||
|
move_cursor(WIDTH+42, 8);
|
||||||
|
colorputs("Game Over!\n", white, red);
|
||||||
|
move_cursor(0, HEIGHT+10);
|
||||||
|
shell_install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_input(char key)
|
||||||
|
{
|
||||||
|
if (key == 'w' && snake.dy == 0) {
|
||||||
|
snake.dx = 0;
|
||||||
|
snake.dy = -1;
|
||||||
|
} else if (key == 's' && snake.dy == 0) {
|
||||||
|
snake.dx = 0;
|
||||||
|
snake.dy = 1;
|
||||||
|
} else if (key == 'a' && snake.dx == 0) {
|
||||||
|
snake.dx = -1;
|
||||||
|
snake.dy = 0;
|
||||||
|
} else if (key == 'd' && snake.dx == 0) {
|
||||||
|
snake.dx = 1;
|
||||||
|
snake.dy = 0;
|
||||||
|
} else if (key =='q') {
|
||||||
|
move_cursor(0, HEIGHT+10);
|
||||||
|
shell_install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_snake(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int game_speed;
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
game_speed = 4;
|
||||||
|
} else {
|
||||||
|
game_speed = atoi(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear();
|
||||||
|
init_game();
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
char key = keyboard_getchar_non_blocking();
|
||||||
|
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
handle_input(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
move_snake();
|
||||||
|
draw_board();
|
||||||
|
delay(game_speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
85
src/programs/sysinfo.c
Normal file
85
src/programs/sysinfo.c
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// System information program
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../kernel/sysinfo.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
|
extern unsigned int multiboot_info_address;
|
||||||
|
|
||||||
|
typedef struct multiboot_memory_map
|
||||||
|
{
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int base_addr_low;
|
||||||
|
unsigned int base_addr_high;
|
||||||
|
unsigned int length_low;
|
||||||
|
unsigned int length_high;
|
||||||
|
unsigned int type;
|
||||||
|
} multiboot_memory_map_t;
|
||||||
|
|
||||||
|
void get_cpuid()
|
||||||
|
{
|
||||||
|
// CPUid
|
||||||
|
|
||||||
|
unsigned int eax, edx;
|
||||||
|
char vendor[13];
|
||||||
|
unsigned int* v = (unsigned int*)vendor;
|
||||||
|
|
||||||
|
asm volatile("cpuid"
|
||||||
|
: "=b"(v[0]), "=d"(v[1]), "=c"(v[2])
|
||||||
|
: "a"(0));
|
||||||
|
vendor[12] = '\0';
|
||||||
|
|
||||||
|
cpuid(1, &eax, &edx);
|
||||||
|
unsigned int model = (eax >> 4) & 0xF;
|
||||||
|
unsigned int family = (eax >> 8) & 0xF;
|
||||||
|
|
||||||
|
printf("CPU information\n\tvendor: %s\n\tfamily: %u\n\tmodel: %u\n\tfeatures: 0x%x\n", vendor, family, model, edx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not really working anymore as it was made for multiboot1, now using multiboot2
|
||||||
|
void get_meminfo(unsigned int multiboot_info_address, int verbose)
|
||||||
|
{
|
||||||
|
// RAM
|
||||||
|
|
||||||
|
unsigned int mem_lower = *((unsigned int*)(multiboot_info_address + 4));
|
||||||
|
unsigned int mem_upper = *((unsigned int*)(multiboot_info_address + 8));
|
||||||
|
|
||||||
|
printf("RAM information\n\tLower memory: %u KB\n\tUpper memory: %u KB\n", mem_lower, mem_upper);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*)*((unsigned int*)(multiboot_info_address + 44));
|
||||||
|
printf("Memory map:\nBase addr | Length | Type\n----------------------------------------------------\n");
|
||||||
|
|
||||||
|
while ((unsigned int)mmap < multiboot_info_address + *((unsigned int*)(multiboot_info_address + 40)))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (mmap->length_high != 0 && mmap->length_low != 0)
|
||||||
|
{*/
|
||||||
|
printf("0x%x%x | 0x%x%x | %u\n",
|
||||||
|
mmap->base_addr_high, mmap->base_addr_low,
|
||||||
|
mmap->length_high, mmap->length_low,
|
||||||
|
mmap->type);
|
||||||
|
//}
|
||||||
|
|
||||||
|
mmap = (multiboot_memory_map_t*)((unsigned int)mmap + mmap->size + sizeof(unsigned int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_sysinfo(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
get_cpuid();
|
||||||
|
get_meminfo(g_multiboot_info_address, 0);
|
||||||
|
} else if (argc == 2 && strcmp(argv[1], "-v") == 0)
|
||||||
|
{
|
||||||
|
get_cpuid();
|
||||||
|
get_meminfo(g_multiboot_info_address, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,46 +1,211 @@
|
|||||||
|
// Pseudo-random word generation program
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../libc/crypto.h"
|
#include "../libc/crypto.h"
|
||||||
#include "../kernel/system.h"
|
#include "../kernel/system.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
|
||||||
|
// Small dictionary
|
||||||
|
|
||||||
char* words[] =
|
char* words[] =
|
||||||
{
|
{
|
||||||
|
// A
|
||||||
"I", "us", "they", "my",
|
"I", "us", "they", "my",
|
||||||
"a", "an", "is", "are", "for", "while", "not", "none", "yes", "no",
|
"a", "an", "is", "are", "for", "while", "not", "none", "yes", "no",
|
||||||
"absolutely", "addition", "additive", "afternoon", "architect", "ask",
|
"absolutely", "addition", "additive", "afternoon", "architect", "ask",
|
||||||
"be", "blindfold", "brilliant", "boy", "brilliant", "bring", "buddy",
|
"ability", "above", "absence", "academy", "account", "achieve", "acquire",
|
||||||
|
"adapt", "admit", "adventure", "affection", "agenda", "agreement", "airport",
|
||||||
|
"alert", "alibi", "alive", "allow", "almond", "alphabet", "always",
|
||||||
|
|
||||||
|
// B
|
||||||
|
"be", "blindfold", "brilliant", "boy", "bring", "buddy",
|
||||||
|
"balance", "bamboo", "band", "banjo", "bank", "banner", "barrel",
|
||||||
|
"basic", "battery", "beach", "beacon", "beard", "behavior", "believe",
|
||||||
|
"belt", "benefit", "berry", "bicycle", "bingo", "biology", "birthday",
|
||||||
|
"biscuit", "bitter", "blanket", "blizzard", "blossom", "blueprint", "board",
|
||||||
|
|
||||||
|
// C
|
||||||
"career", "caterpillar", "change", "cheeky", "chop",
|
"career", "caterpillar", "change", "cheeky", "chop",
|
||||||
|
"cabin", "cactus", "camera", "candle", "candy", "canoe", "canvas",
|
||||||
|
"capital", "captain", "caravan", "carbon", "carpet", "cartoon", "castle",
|
||||||
|
"casual", "catalog", "catch", "category", "celebrate", "ceremony", "certain",
|
||||||
|
"chain", "chair", "chamber", "charge", "charity", "cheese", "chef",
|
||||||
|
|
||||||
|
// D
|
||||||
"decide", "demonstrate", "draw", "druggist",
|
"decide", "demonstrate", "draw", "druggist",
|
||||||
|
"daisy", "dance", "danger", "daring", "database", "debate", "decade",
|
||||||
|
"decline", "decorate", "decrease", "dedicate", "defeat", "defend", "define",
|
||||||
|
"degree", "delight", "delivery", "demand", "dentist", "deny", "depart",
|
||||||
|
"depth", "describe", "deserve", "desire", "destroy", "develop", "device",
|
||||||
|
|
||||||
|
// E
|
||||||
"eagle", "ear", "effort", "evening",
|
"eagle", "ear", "effort", "evening",
|
||||||
|
"early", "earn", "earth", "ease", "east", "easy", "echo",
|
||||||
|
"eclipse", "economy", "edge", "edit", "educate", "effect", "effort",
|
||||||
|
"egg", "eight", "either", "elder", "elect", "elegant", "element",
|
||||||
|
"elephant", "elevator", "elite", "embark", "embrace", "emerge", "emotion",
|
||||||
|
|
||||||
|
// F
|
||||||
"fabric", "famous", "fuse",
|
"fabric", "famous", "fuse",
|
||||||
|
"face", "factor", "fail", "fair", "fall", "false", "fame",
|
||||||
|
"family", "fancy", "fantasy", "farewell", "farm", "fashion", "fast",
|
||||||
|
"fault", "favor", "feather", "feature", "federal", "feedback", "feeling",
|
||||||
|
"female", "fence", "festival", "fever", "fiber", "fiction", "field",
|
||||||
|
|
||||||
|
// G
|
||||||
"generation", "generous", "girl", "gypsy", "grip",
|
"generation", "generous", "girl", "gypsy", "grip",
|
||||||
|
"gallery", "game", "garage", "garden", "garlic", "gas", "gate",
|
||||||
|
"gather", "general", "genius", "gentle", "genuine", "geography", "gesture",
|
||||||
|
"ghost", "giant", "gift", "giggle", "ginger", "giraffe", "glance",
|
||||||
|
"glass", "globe", "glory", "glove", "glue", "goal", "gold",
|
||||||
|
|
||||||
|
// H
|
||||||
"habit", "handsome", "helmet", "help", "horror",
|
"habit", "handsome", "helmet", "help", "horror",
|
||||||
|
"hair", "half", "hammer", "hand", "handle", "hang", "happen",
|
||||||
|
"harbor", "hard", "harm", "harvest", "hat", "hate", "have",
|
||||||
|
"head", "health", "heart", "heat", "heaven", "heavy", "hedge",
|
||||||
|
"height", "hello", "heritage", "hero", "hesitate", "hidden", "high",
|
||||||
|
|
||||||
|
// I
|
||||||
"insist", "inventor", "itself", "ivory",
|
"insist", "inventor", "itself", "ivory",
|
||||||
|
"ice", "idea", "ideal", "identify", "ignore", "ill", "image",
|
||||||
|
"imagine", "impact", "import", "impress", "improve", "impulse", "inch",
|
||||||
|
"include", "income", "increase", "index", "industry", "infant", "inform",
|
||||||
|
"insect", "inside", "inspire", "install", "instead", "insult", "intact",
|
||||||
|
|
||||||
|
// J
|
||||||
"jog", "joint", "joke", "judge",
|
"jog", "joint", "joke", "judge",
|
||||||
|
"jacket", "jaguar", "jail", "jam", "january", "jar", "jazz",
|
||||||
|
"jealous", "jeans", "jelly", "jewel", "job", "join", "journey",
|
||||||
|
"joy", "judge", "juice", "jump", "jungle", "junior", "justice",
|
||||||
|
"just", "justify", "juggle", "juice", "jumper", "junction", "jury",
|
||||||
|
|
||||||
|
// K
|
||||||
"karate", "kebab", "kitchen",
|
"karate", "kebab", "kitchen",
|
||||||
|
"kangaroo", "keen", "keep", "kettle", "key", "keyboard", "kick",
|
||||||
|
"kid", "kidney", "king", "kiss", "kite", "knee", "knife",
|
||||||
|
"knit", "knock", "knot", "know", "knowledge", "koala", "kudos",
|
||||||
|
"keen", "kernel", "kit", "kitten", "knack", "knight", "knock",
|
||||||
|
|
||||||
|
// L
|
||||||
"lamb", "lawnmower", "left", "lock",
|
"lamb", "lawnmower", "left", "lock",
|
||||||
|
"label", "labor", "lace", "ladder", "lady", "lake", "lamp",
|
||||||
|
"land", "language", "large", "laser", "last", "later", "laugh",
|
||||||
|
"launch", "law", "layer", "lead", "leaf", "learn", "least",
|
||||||
|
"leather", "leave", "lecture", "legal", "legend", "lemon", "length",
|
||||||
|
|
||||||
|
// M
|
||||||
"math", "medicine", "most",
|
"math", "medicine", "most",
|
||||||
|
"machine", "magnet", "mail", "main", "major", "make", "male",
|
||||||
|
"manage", "mango", "manner", "manual", "map", "marble", "march",
|
||||||
|
"mark", "market", "marriage", "master", "match", "material", "matter",
|
||||||
|
"maximum", "mayor", "meal", "mean", "measure", "media", "memory",
|
||||||
|
|
||||||
|
// N
|
||||||
"noodles", "nowadays", "nowhere",
|
"noodles", "nowadays", "nowhere",
|
||||||
|
"nail", "name", "narrow", "nation", "native", "nature", "navy",
|
||||||
|
"near", "neat", "necessary", "neck", "need", "negative", "neglect",
|
||||||
|
"neither", "nerve", "nest", "net", "network", "neutral", "never",
|
||||||
|
"new", "news", "next", "nice", "night", "noble", "noise",
|
||||||
|
|
||||||
|
// O
|
||||||
"ocean", "older", "ounce",
|
"ocean", "older", "ounce",
|
||||||
|
"object", "observe", "obtain", "occasion", "occupy", "occur", "ocean",
|
||||||
|
"offer", "office", "often", "oil", "old", "olive", "olympic",
|
||||||
|
"omit", "once", "one", "onion", "online", "only", "open",
|
||||||
|
"opera", "opinion", "oppose", "option", "orange", "orbit", "order",
|
||||||
|
|
||||||
|
// P
|
||||||
"part", "pathetic", "pastime",
|
"part", "pathetic", "pastime",
|
||||||
|
"pace", "package", "page", "pain", "paint", "pair", "palm",
|
||||||
|
"panel", "panic", "paper", "parent", "park", "part", "party",
|
||||||
|
"pass", "path", "patient", "pattern", "pause", "peace", "peak",
|
||||||
|
"pen", "pencil", "people", "pepper", "perfect", "perform", "permit",
|
||||||
|
|
||||||
|
// Q
|
||||||
"quite", "quits", "quotation",
|
"quite", "quits", "quotation",
|
||||||
|
"quality", "quantity", "quarter", "queen", "query", "quest", "quick",
|
||||||
|
"quiet", "quilt", "quit", "quote", "quiz", "quota", "quiver",
|
||||||
|
"quirky", "quaint", "quake", "qualification", "qualify", "quark", "quartz",
|
||||||
|
"queue", "quench", "question", "quote", "quiver", "quorum", "quote",
|
||||||
|
|
||||||
|
// R
|
||||||
"race", "raise", "reality",
|
"race", "raise", "reality",
|
||||||
|
"rabbit", "race", "radio", "rain", "raise", "random", "range",
|
||||||
|
"rapid", "rare", "rate", "rather", "ratio", "reach", "react",
|
||||||
|
"read", "ready", "real", "reason", "rebel", "recall", "receive",
|
||||||
|
"recipe", "record", "recover", "reduce", "refer", "reflect", "reform",
|
||||||
|
|
||||||
|
// S
|
||||||
"safe", "scare", "screen",
|
"safe", "scare", "screen",
|
||||||
|
"sack", "sail", "salad", "salt", "same", "sample", "sand",
|
||||||
|
"save", "scale", "scan", "scar", "scene", "school", "science",
|
||||||
|
"score", "scratch", "scream", "screen", "script", "search", "season",
|
||||||
|
"seat", "second", "secret", "section", "secure", "see", "seed",
|
||||||
|
|
||||||
|
// T
|
||||||
"taught", "temple", "that", "this",
|
"taught", "temple", "that", "this",
|
||||||
|
"table", "tackle", "tail", "take", "tale", "talent", "talk",
|
||||||
|
"tank", "tape", "target", "task", "taste", "tax", "teach",
|
||||||
|
"team", "tear", "technology", "telephone", "television", "temperature", "tend",
|
||||||
|
"tennis", "tent", "term", "test", "text", "thank", "theory",
|
||||||
|
|
||||||
|
// U
|
||||||
"unable", "unkind", "usual",
|
"unable", "unkind", "usual",
|
||||||
|
"umbrella", "unable", "uncle", "under", "undo", "unfair", "unfold",
|
||||||
|
"union", "unique", "unit", "universe", "unknown", "unless", "unlike",
|
||||||
|
"unlock", "until", "unusual", "update", "upgrade", "upon", "upper",
|
||||||
|
"upset", "urban", "urge", "use", "usual", "utility", "utter",
|
||||||
|
|
||||||
|
// V
|
||||||
"velvet", "vivid", "vote",
|
"velvet", "vivid", "vote",
|
||||||
|
"vacuum", "valid", "valley", "value", "vampire", "van", "vase",
|
||||||
|
"vast", "vault", "vector", "vehicle", "velvet", "vendor", "venture",
|
||||||
|
"verb", "verify", "version", "vessel", "veteran", "veto", "vibrate",
|
||||||
|
"victory", "video", "view", "village", "violin", "virtue", "virus",
|
||||||
|
|
||||||
|
// W
|
||||||
"we", "warm", "watch",
|
"we", "warm", "watch",
|
||||||
|
"wage", "wait", "walk", "wall", "wander", "want", "war",
|
||||||
|
"wash", "waste", "watch", "water", "wave", "way", "wealth",
|
||||||
|
"weapon", "wear", "weather", "weave", "wedding", "week", "weight",
|
||||||
|
"welcome", "well", "west", "wheel", "when", "whisper", "white",
|
||||||
|
|
||||||
|
// X
|
||||||
"xylophone",
|
"xylophone",
|
||||||
|
"xenon", "xenophobia", "xerox", "xmas", "x-ray", "xylophone", "xylem",
|
||||||
|
|
||||||
|
// Y
|
||||||
"yolk", "young", "your",
|
"yolk", "young", "your",
|
||||||
|
"yard", "yarn", "year", "yell", "yellow", "yes", "yesterday",
|
||||||
|
"yet", "yield", "yogurt", "yoke", "youth", "yawn", "yearn",
|
||||||
|
"yacht", "yummy", "yogurt", "yoga", "yardstick", "yonder", "yummy",
|
||||||
|
|
||||||
|
// Z
|
||||||
"zebra", "zodiac", "zucchini",
|
"zebra", "zodiac", "zucchini",
|
||||||
|
"zero", "zone", "zoo", "zoom", "zeal", "zip", "zigzag",
|
||||||
|
"zenith", "zest", "zipper", "zombie", "zonal", "zinc", "zephyr"
|
||||||
};
|
};
|
||||||
|
|
||||||
int words_size = sizeof(words)/sizeof(words[0]);
|
int words_size = sizeof(words)/sizeof(words[0]);
|
||||||
|
|
||||||
// Generates 5 random words
|
// Generates random words
|
||||||
void program_words()
|
void program_words(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
for (int i=0; i<10; i++)
|
int amount;
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
amount = 10;
|
||||||
|
} else if (argc == 2)
|
||||||
|
{
|
||||||
|
amount = atoi(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<amount; i++)
|
||||||
{
|
{
|
||||||
int random = randint(global_ticks);
|
int random = randint(global_ticks);
|
||||||
char* word = words[random%words_size];
|
char* word = words[random%words_size];
|
||||||
|
|||||||
BIN
stage2_eltorito
BIN
stage2_eltorito
Binary file not shown.
Reference in New Issue
Block a user