42 Commits

Author SHA1 Message Date
xamidev
f1f45fbeb6 Update README.md 2024-08-26 16:10:50 +02:00
xamidev
6f5c05e0d9 Fix version 2024-08-26 16:03:51 +02:00
xamidev
a4b036dfbd Merge pull request #5 from xamidev/dev
Small adjustments, pi program
2024-08-26 16:02:18 +02:00
xamidev
a316367236 Small fixes as always, + add pi program 2024-08-26 16:01:26 +02:00
xamidev
93f5feff85 Merge branch 'dev' of https://github.com/xamidev/blankos into dev 2024-08-26 13:00:42 +02:00
xamidev
7c80cc8af9 Update DEVELOPERS.md 2024-08-26 13:00:16 +02:00
xamidev
88debf5085 small multiboot fix 2024-08-26 12:57:51 +02:00
xamidev
449873f55d Merge pull request #4 from xamidev/dev
Dev: small fixes in programs + new programs
2024-08-25 18:49:20 +02:00
xamidev
adcfdc8231 Fix: program safety (zero-init some input buffers) + program args 2024-08-25 12:52:23 +02:00
xamidev
deafe2439b Add: reboot utility 2024-08-25 11:33:09 +02:00
xamidev
b1e4ef8ad2 Add: programs time and read 2024-08-25 11:25:46 +02:00
xamidev
cde6bb4522 Minor fixes in docs 2024-08-24 22:22:13 +02:00
xamidev
9992f84fdb Merge pull request #3 from xamidev/dev
Esthetic improvements
2024-08-24 22:19:29 +02:00
xamidev
8e51ab357e Add: cool splash screen 2024-08-24 22:18:21 +02:00
xamidev
942b4fa88e Add: cowsay, splash 2024-08-24 21:50:20 +02:00
xamidev
2893e75ad1 fix: conway, words 2024-08-24 20:30:14 +02:00
xamidev
0646536f35 Merge pull request #2 from xamidev/cleanup
Codebase cleanup & harmonization
2024-08-24 19:03:45 +02:00
xamidev
75d120efcd Rewrite: documentation 2024-08-24 19:02:42 +02:00
xamidev
d10e00835c Fix: header-comment link 2024-08-24 17:23:26 +02:00
xamidev
fbd4fa6089 Clean: harmonizing & header-commenting code 2024-08-24 17:17:53 +02:00
xamidev
a915ac15a1 Clean: kmain 2024-08-24 16:40:23 +02:00
xamidev
a03bb42790 Switch: to freestanding stdint and stdbool headers 2024-08-24 16:26:14 +02:00
xamidev
0146613ce7 Add: UEFI support (32-bit protected still) 2024-08-24 11:52:16 +02:00
xamidev
b3ee5f5dc9 Update README.md 2024-08-23 15:33:23 +02:00
xamidev
f4f7a37554 Update README.md 2024-08-23 15:26:40 +02:00
xamidev
7089ddd052 Merge pull request #1 from xamidev/dev
Graphics mode & linear framebuffer update
2024-08-23 15:24:09 +02:00
xamidev
a029218acd Add: cursor & verbose output 2024-08-23 15:22:19 +02:00
xamidev
6d0c9ac62b Add: graphics fb cursor 2024-08-23 14:27:24 +02:00
xamidev
f1a9f84f24 Add: graphics mode terminal scrolling 2024-08-23 13:05:53 +02:00
xamidev
f8eb658c33 WIP: Framebuffer partial support, cursor & scoll TODO 2024-08-20 13:38:44 +02:00
xamidev
52a92a5358 Change: Framebuffer puts/printf graphics mode OK 2024-08-20 13:01:13 +02:00
xamidev
98d3d346c2 Fix: framebuffer draw_char 2024-08-19 21:04:16 +02:00
xamidev
1ebed970c8 Bigger runes? 2024-08-19 13:18:03 +02:00
xamidev
6ce5264b43 Weird runes? 2024-08-19 12:50:17 +02:00
xamidev
a2a7ab52a1 Revert: to more simple ISO generation w/o root privileges 2024-08-18 21:46:21 +02:00
xamidev
ca001598fc Add: multiboot2: entering graphics mode 2024-08-18 21:03:26 +02:00
xamidev
2f562758ad Re-add: ATA PIO driver (w/o paging) 2024-08-18 12:45:24 +02:00
xamidev
cd705589de Add: paging & test 2024-08-18 12:19:16 +02:00
xamidev
7e551dbfae Fix: asm macros for irq, isr 2024-08-18 10:56:27 +02:00
xamidev
7b65e4ed01 Change: Build process, boot instructions 2024-08-15 16:44:56 +02:00
xamidev
ef88100c1f Filesystem part 1: FAT32 image bootstrapping 2024-08-15 16:19:07 +02:00
xamidev
6e162fc365 Add toolchain rule 2024-08-15 15:27:53 +02:00
65 changed files with 1919 additions and 907 deletions

5
.gitignore vendored
View File

@@ -1,8 +1,7 @@
*.o
bochslog.txt
build/
kernel.elf
os.iso
blankos.iso
real/
iso/
i386-elf-7.5.0-Linux-x86_64/
i386-elf-7.5.0-Linux-x86_64.tar.xz

106
README.md
View File

@@ -1,102 +1,50 @@
![showcase](https://github.com/user-attachments/assets/0e3208db-e585-4086-9346-c00414d98646)
![Screenshot_20240826_160940](https://github.com/user-attachments/assets/a4d2af98-7c7e-4a7f-a64c-31b0325d99d7)
> [!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
Rewritten monolithic, ring 0, lower-half, single-threaded kernel for the x86 processor architecture, using GRUB (eltorito) as bootloader. Emulation was tested on Bochs and QEMU using Arch Linux 6.9.7-arch1-1, and on real hardware too.
Rewritten monolithic, ring 0, lower-half, singletasking kernel for the x86 processor architecture, using 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!
## 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!!
### Kernel-space programs
- A brainfuck interpreter
- An arithmetic calculator
- ROT13 and Morse cipher programs
- Conway's Game of Life
- And some more...
## 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 that the ISO images provided in the "Releases" tab are already real-hardware capable; no need to do anything except burning the image on a USB stick and running it on your machine.*
> [!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
### 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
make toolchain
make
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`.
You can try out QEMU too.
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!*
## 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.
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:
The OS is now both UEFI and BIOS compatible! Burn your image file onto a USB stick:
```
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`).
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.
### Next Steps?
Next steps for this project will be:
- User programs
- Completing the kernel libc
- Filesystem support
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)*
### Resources
@@ -106,7 +54,25 @@ Next steps for this project will be:
- 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)
- [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
- [ ] 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

View File

@@ -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

BIN
com1.out

Binary file not shown.

View File

@@ -1,5 +1,11 @@
# Blank OS Developer's Manual
## Table of Contents
- Getting Started
- Writing programs for BlankOS
- Changing the TTY font
## Getting Started
### System description
@@ -14,7 +20,22 @@ The source code is available in folder `src`. You will find subfolders correspon
No system calls are available, as the OS runs in kernel-space.
## Making programs for the OS
## Debugging the kernel (QEMU w/ GDB)
```
make debug
```
In another shell:
```
gdb kernel.elf
(gdb) target remote localhost:1234
```
## 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
@@ -73,4 +94,18 @@ The linking process should be taken care of by the appropriate Linker script `li
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.

View File

@@ -2,6 +2,25 @@
## 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.
@@ -20,17 +39,25 @@ Shows all of the available commands, which are explained here.
#### `panic`
Triggers a kernel panic by trying to divide four by zero.
Triggers a kernel panic by reserved exception.
#### `words`
Prints ten random words using an arbitrary dictionary that you can expand in `src/programs/words.c`.
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 up to `PRIMES_MAX`, defined in `src/programs/primes.c`.
Computes prime numbers.
#### `rainbow`
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.
@@ -50,19 +77,19 @@ A brainfuck interpreter with every instruction and default tape size (30k cells)
Gets system uptime from the timer in ticks. Ticks are incremented at a rate of 18.222Hz (18.222 ticks per second).
#### `echo`
#### `echo <string>`
The classic echo command, that outputs your input.
#### `sysinfo`
#### `sysinfo [option]`
Outputs information about the current system (CPU and RAM).
Options:
- `nothing` will show basic info about the CPUid and lower/upper memory.
- `<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`
#### `conway [option]`
A classic Game of Life implementation with standard rules and 100 generations.
@@ -71,10 +98,18 @@ Options:
- `-g` will spawn a classic glider
- `-l` will spawn a lightweight spaceship
#### `rot13`
#### `rot13 <string>`
Encode a string using the rot13 cipher.
#### `morse`
#### `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.

View File

@@ -1,4 +1,6 @@
menuentry "Blank OS" {
multiboot /boot/kernel.elf
insmod all_video
set gfxpayload=1024x768x32
multiboot2 /boot/kernel.elf
boot
}

Binary file not shown.

View File

@@ -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
View File

@@ -1,30 +1,31 @@
ENTRY(loader)
SECTIONS {
/* Address to load at; 1MB */
/* Address to load at; 2MB */
. = 0x00100000;
/*. = 2M;*/
.__mbHeader : {
*(.__mbHeader)
.multiboot_header ALIGN(4K) : {
*(.multiboot_header)
}
/* Align relevant sections at 4KB */
.text ALIGN (0x1000) :
.text ALIGN (4K) :
{
*(.text)
*(.rodata)
}
.data ALIGN (0x1000) :
.data ALIGN (4K) :
{
*(.data)
}
.bss ALIGN (0x1000) :
.bss ALIGN (4K) :
{
*(COMMON)
*(.bss)
}
end = .; _end = .; __end = .;
}

View File

@@ -1,5 +1,5 @@
CC = i386-elf-7.5.0-Linux-x86_64/bin/i386-elf-gcc
CFLAGS = -Wall -Wextra -Wno-builtin-declaration-mismatch -c -I src/
CFLAGS = -ffreestanding -g -Wall -Wextra -Wno-builtin-declaration-mismatch -c -I src/
LDFLAGS = -T link.ld -melf_i386
AS = nasm
ASFLAGS = -f elf
@@ -9,6 +9,8 @@ KERNEL_DIR = $(SRC_DIR)/kernel
LIBC_DIR = $(SRC_DIR)/libc
PROGRAMS_DIR = $(SRC_DIR)/programs
DRIVERS_DIR = $(SRC_DIR)/drivers
INCLUDE_DIR = include
FONTS_DIR = $(INCLUDE_DIR)/fonts
OBJ_DIR = build
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))
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
$(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)
ld $(LDFLAGS) $(OBJECTS) -o kernel.elf
kernel.elf: $(OBJECTS) $(FONT_OBJ)
ld $(LDFLAGS) $(OBJECTS) $(FONT_OBJ) -o kernel.elf
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $< -o $@
@@ -31,28 +39,28 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
$(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
mkdir -p iso/boot/grub
cp kernel.elf iso/boot/kernel.elf
genisoimage -R \
-b boot/grub/stage2_eltorito \
-no-emul-boot \
-boot-load-size 4 \
-A os \
-input-charset utf8 \
-quiet \
-boot-info-table \
-o os.iso \
iso
cp grub.cfg iso/boot/grub/grub.cfg
grub-mkrescue iso -o blankos.iso
real: kernel.elf
mkdir -p real/boot/grub
cp kernel.elf real/boot/kernel.elf
cp grub.cfg real/boot/grub/grub.cfg
grub-mkrescue real -o blankos.iso
run: iso
qemu-system-i386 -drive file=blankos.iso,format=raw
run: os.iso
bochs -f bochsrc.txt -q
debug:
qemu-system-i386 -s -S -drive file=blankos.iso,format=raw
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
View 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
View 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

91
src/drivers/framebuffer.c Normal file
View File

@@ -0,0 +1,91 @@
// 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)
{
if (bpp == 32) {
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
View 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

View File

@@ -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 "../libc/stdio.h"
#include "../kernel/system.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
#include "kb.h"
unsigned char kbdus[128] =
{
@@ -130,6 +129,7 @@ void keyboard_handler()
void keyboard_install()
{
irq_install_handler(1, keyboard_handler);
printf("[keyboard] installed irq handler\n");
}
char keyboard_getchar()

View File

@@ -1,6 +1,18 @@
// Keyboard driver header
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#ifndef 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();
#endif

64
src/drivers/rtc.c Normal file
View 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
View 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

View File

@@ -1,3 +1,8 @@
// Serial I/O driver
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "../kernel/io.h"
#include "serial.h"
#include "../libc/stdio.h"
@@ -20,6 +25,7 @@ int init_serial()
}
outb(PORT+4, 0x0F);
puts("[serial] initialized i/o on port COM1\n");
return 0;
}
@@ -276,6 +282,5 @@ void serial_printf(int errlevel, const char* fmt, ...)
}
fmt++;
}
serial_puts("\n");
serial_puts("\r\n");
}

View File

@@ -1,5 +1,10 @@
#ifndef INCLUDE_SERIAL_H
#define INCLUDE_SERIAL_H
// Serial I/O driver header
// 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
@@ -9,4 +14,5 @@ void write_serial(const char a);
void serial_puts(const char* str);
void log(const char* str, const int errlevel);
void serial_printf(int errlevel, const char* fmt, ...);
#endif

View File

@@ -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 "../libc/stdio.h"
@@ -6,11 +11,18 @@ volatile unsigned long global_ticks = 0;
void timer_handler()
{
global_ticks++;
if (global_ticks % 20 == 0)
{
draw_cursor(white);
} else if (global_ticks % 20 == 10) {
erase_cursor();
}
}
void timer_install()
{
irq_install_handler(0, timer_handler);
printf("[timer] initialized, starting g_ticks...\n");
}
void delay(int ticks)

View File

@@ -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"
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));
#include "../libc/stdio.h"
struct gdt_entry gdt[3];
struct gdt_ptr gp;
@@ -41,8 +31,14 @@ void gdt_install()
gdt_set_gate(0, 0, 0, 0, 0);
// Ring 0 code + data
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 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();
printf("[kernel] GDT gates set (ring 0 and 3), gdt=0x%x\n", &gdt);
}

View File

@@ -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
#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();
#endif

View File

@@ -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 "system.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));
#include "../libc/stdio.h"
struct idt_entry idt[256];
struct idt_ptr idtp;
@@ -39,4 +30,5 @@ void idt_install()
memset(&idt, 0, sizeof(struct idt_entry)*256);
idt_load();
printf("[kernel] loaded IDT at idt=0x%x\n", &idt);
}

View File

@@ -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
#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();
#endif

View File

@@ -1,7 +1,12 @@
#ifndef INCLUDE_IO_H
#define INCLUDE_IO_H
// Raw CPU port I/O kernel module header
// 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);
unsigned char inb(unsigned short port);

View File

@@ -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
outb:

View File

@@ -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 "io.h"
#include "idt.h"
#include "../libc/stdio.h"
extern void irq0();
extern void irq1();
@@ -69,6 +75,7 @@ void irq_install()
idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E);
idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
printf("[kernel] installed irq 0-15\n");
}
void irq_handler(struct regs *r)

View File

@@ -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 "../libc/stdio.h"
#include "idt.h"
@@ -37,7 +42,6 @@ extern void isr31();
void isr_install()
{
idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E);
idt_set_gate(1, (unsigned)isr1, 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(30, (unsigned)isr30, 0x08, 0x8E);
idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E);
printf("[kernel] set ISRs 0-31\n");
}
char *exception_messages[] =
@@ -115,4 +120,3 @@ void fault_handler(struct regs *r)
for (;;);
}
}

46
src/kernel/kheap.c Normal file
View File

@@ -0,0 +1,46 @@
// Kernel heap management
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "kheap.h"
#include <stdint.h>
extern uint32_t end;
uint32_t placement_address = (uint32_t)&end;
uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys)
{
if (align == 1 && (placement_address & 0x00000FFF))
{
placement_address &= 0xFFFFF000;
placement_address += 0x1000;
}
if (phys)
{
*phys = placement_address;
}
uint32_t tmp = placement_address;
placement_address += sz;
return tmp;
}
uint32_t kmalloc_a(uint32_t sz)
{
return kmalloc_int(sz, 1, 0);
}
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys)
{
return kmalloc_int(sz, 0, phys);
}
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys)
{
return kmalloc_int(sz, 1, phys);
}
uint32_t kmalloc(uint32_t sz)
{
return kmalloc_int(sz, 0, 0);
}

16
src/kernel/kheap.h Normal file
View File

@@ -0,0 +1,16 @@
// 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>
uint32_t kmalloc_a(uint32_t sz);
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
uint32_t kmalloc(uint32_t sz);
#endif

View File

@@ -1,45 +1,70 @@
// Kernel entry point
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "../libc/stdio.h"
#include "../drivers/serial.h"
#include "gdt.h"
#include "idt.h"
#include "system.h"
//#include <stdarg.h>
#include "../drivers/ata.h"
#include <stdint.h>
#include "../drivers/framebuffer.h"
#include "kmain.h"
char* ascii_title =
"\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.55 --------------------------------\n\n";
unsigned int g_multiboot_info_address;
void kmain(unsigned int multiboot_info_address)
void kmain(multiboot2_info *mb_info)
{
g_multiboot_info_address = multiboot_info_address;
multiboot2_tag_framebuffer *fb_info = 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 == 8) {
fb_info = (multiboot2_tag_framebuffer*) tags;
}
tags += ((tag_size + 7) & ~7);
}
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);
if (fb_info) {
framebuffer = (uint32_t *)(uintptr_t) fb_info->framebuffer_addr;
uint32_t width = fb_info->framebuffer_width;
uint32_t height = fb_info->framebuffer_height;
uint32_t bpp = fb_info->framebuffer_bpp;
//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);
}
printf("[kernel] multiboot2 info at 0x%x, size=%u\n", mb_info, mb_info->total_size);
printf("[kernel] framebuffer discovered at 0x%x\n", 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);
init_serial();
log("serial connection established\n", 3);
gdt_install();
log("initialized GDT entries\n", 2);
idt_install();
log("initialized IDT\n", 2);
isr_install();
log("initialized ISRs\n", 2);
irq_install();
__asm__ __volatile__("sti");
log("initialized IRQs\n", 2),
clear();
colorputs(ascii_title, 10);
colorputs(" by @xamidev - star the repo for a cookie!\n\n", 14);
//test_read_sector();
timer_install();
serial_printf(2, "%d\tinitialized timer handler", global_ticks);
keyboard_install();
serial_printf(2, "%d\tinitialized keyboard handler", global_ticks);
printf("[kernel] spawning shell...\n");
shell_install();
serial_printf(2, "%d\tstarted system shell", global_ticks);
}

36
src/kernel/kmain.h Normal file
View File

@@ -0,0 +1,36 @@
// 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
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;
// in characters, not pixels
uint32_t VGA_WIDTH;
uint32_t VGA_HEIGHT;
#endif

View File

@@ -1,25 +1,57 @@
; Kernel loader assembly stub and multiboot2 header
; Author: xamidev
; Licensed under the Unlicense. See the repo below.
; https://github.com/xamidev/blankos
global loader
section .__mbHeader
section .multiboot_header
align 0x4
section .text:
mb_start:
align 8
MAGIC_NUMBER equ 0x1BADB002 ; multiboot magic
FLAGS equ 0x0
CHECKSUM equ -MAGIC_NUMBER
KERNEL_STACK_SIZE equ 4096
; ASM macros
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 HEADER_LEN
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
loader:
cli
; mov eax, 0xCAFEBABE
; push dword 42
push ebx
call kmain
@@ -49,225 +81,55 @@ idt_load:
lidt [idtp]
ret
global isr0
global isr1
global isr2
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:
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
cli
push byte 0
push byte 0
push byte %1
jmp isr_common_stub
%endmacro
isr1:
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli
push byte 0
push byte 1
push byte %1
jmp isr_common_stub
%endmacro
isr2:
cli
push byte 0
push byte 2
jmp isr_common_stub
isr3:
cli
push byte 0
push byte 3
jmp isr_common_stub
isr4:
cli
push byte 0
push byte 4
jmp isr_common_stub
isr5:
cli
push byte 0
push byte 5
jmp isr_common_stub
isr6:
cli
push byte 0
push byte 6
jmp isr_common_stub
isr7:
cli
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
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_NOERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
extern fault_handler
@@ -295,118 +157,31 @@ isr_common_stub:
add esp, 8
iret
global irq0
global irq1
global irq2
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:
%macro IRQ 2
global irq%1
irq%1:
cli
push byte 0
push byte 32
push byte %2
jmp irq_common_stub
%endmacro
irq1:
cli
push byte 0
push byte 33
jmp irq_common_stub
irq2:
cli
push byte 0
push byte 34
jmp irq_common_stub
irq3:
cli
push byte 0
push byte 35
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
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47
extern irq_handler

View File

@@ -1,13 +1,70 @@
// 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 "../libc/stdio.h"
#include "../libc/string.h"
#include "../programs/programs.h"
#include "../libc/stdint.h"
#include "../libc/crypto.h"
#include <stdint.h>
#include "../drivers/rtc.h"
#define BUFFER_SIZE 256
#define MAX_COMMANDS 16
#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);
colorputs(" blankOS 0.3.97-alpha", 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
@@ -54,6 +111,12 @@ int parse_input(char* input, char* argv[], int max_args)
void shell_install()
{
if (do_splash == true)
{
do_splash = false;
splash();
}
register_command("help", program_help);
register_command("panic", program_panic);
register_command("words", program_words);
@@ -68,12 +131,23 @@ void shell_install()
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);
for (;;)
{
char input_buffer[BUFFER_SIZE];
char* argv[MAX_ARGS];
colorputs("blankos> ", 9);
// Prompt
colorputs("root", blue, black);
colorputs("@", white, black);
colorputs("blankos", green, black);
colorputs("~$ ", white, black);
get_input(input_buffer, BUFFER_SIZE);
puts("\n");

View File

@@ -1,3 +1,8 @@
// 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"

View File

@@ -1,3 +1,8 @@
// 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

View File

@@ -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 <stdint.h>
void *memset(void *dest, char val, size_t count)
{
@@ -6,3 +12,29 @@ void *memset(void *dest, char val, size_t count)
for(; count != 0; count--) *temp++ = val;
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 panic()
{
for (;;);
}

View File

@@ -1,9 +1,18 @@
// 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
#define SYSTEM_H
#include <stdint.h>
typedef int size_t;
#define NULL ((void*)0)
void *memset(void *dest, char val, size_t count);
void *memmove(void* dest, const void* src, size_t n);
struct regs
{
@@ -13,6 +22,7 @@ struct regs
unsigned int eip, cs, eflags, useresp, ss;
};
void panic();
void isr_install();
void irq_install();
void irq_install_handler(int irq, void (*handler)(struct regs *r));

View File

@@ -1,5 +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 "../libc/stdint.h"
#include <stdint.h>
int lcg(int seed)
{

View File

@@ -1,9 +1,14 @@
// Cryptography routines for blankos/libc header
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#ifndef CRYPTO_H
#define CRYPTO_H
#define RAND_MAX 1024
#include "../libc/stdint.h"
#include <stdint.h>
int lcg(int seed);
int randint(int seed);

View File

@@ -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)
{
return c >= '0' && c <= '9';
}
bool isspace(char c)
{
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';

View File

@@ -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
#define CTYPE_H
#include "stdint.h"
#include <stdbool.h>
bool isdigit(char c);
bool isspace(char c);

View File

@@ -1,22 +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
#define NULL ((void*)0)
#endif

View File

@@ -1,33 +1,50 @@
// 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 "stdio.h"
#include "string.h"
#include "stdint.h"
#include <stdint.h>
#include "../kernel/system.h"
#include "../drivers/framebuffer.h"
#include "../drivers/serial.h"
char* fb = (char *) 0x000B8000;
const unsigned VGA_WIDTH = 80;
const unsigned VGA_HEIGHT = 25;
const unsigned int COLOR = 0x7;
extern uint32_t* framebuffer;
extern uint32_t VGA_WIDTH;
extern uint32_t VGA_HEIGHT;
unsigned int VGA_X = 0, VGA_Y = 0;
extern int scanline;
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 erase_cursor()
{
draw_cursor(black);
}
void move_cursor(int x, int y)
{
unsigned short pos = y*VGA_WIDTH+x;
outb(FB_CMD_PORT, FB_HIGH_BYTE_CMD);
outb(FB_DATA_PORT, ((pos >> 8) & 0x00FF));
outb(FB_CMD_PORT, FB_LOW_BYTE_CMD);
outb(FB_DATA_PORT, pos & 0x00FF);
erase_cursor();
VGA_X = x;
VGA_Y = y;
draw_cursor(white);
}
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;
}
void putcolor(int x, int y, unsigned int color)
{
fb[2*(y*VGA_WIDTH+x)+1] = color;
draw_char(c, x, y, fg, bg);
}
void clear(void)
@@ -36,55 +53,15 @@ void clear(void)
{
for (unsigned int x=0; x<VGA_WIDTH; x++)
{
putchar(x, y, '\0');
putcolor(x, y, COLOR);
putchar(' ', x, y, black, black);
}
}
VGA_X = 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;
}
move_cursor(0, 0);
}
void putc(char c)
{
erase_cursor();
switch(c)
{
case '\n':
@@ -110,10 +87,10 @@ void putc(char c)
VGA_Y--;
VGA_X = VGA_WIDTH-1;
}
putchar(VGA_X, VGA_Y, ' ');
putchar(' ', VGA_X, VGA_Y, white, black);
break;
default:
putchar(VGA_X, VGA_Y, c);
putchar(c, VGA_X, VGA_Y, white, black);
VGA_X++;
break;
}
@@ -123,13 +100,19 @@ void putc(char c)
VGA_Y++;
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);
}
void colorputc(char c, unsigned int color)
void colorputc(char c, uint32_t fg, uint32_t bg)
{
erase_cursor();
switch(c)
{
case '\n':
@@ -143,8 +126,7 @@ void colorputc(char c, unsigned int color)
VGA_X += 4;
break;
default:
putchar(VGA_X, VGA_Y, c);
putcolor(VGA_X, VGA_Y, color);
putchar(c, VGA_X, VGA_Y, fg, bg);
VGA_X++;
break;
}
@@ -154,7 +136,14 @@ void colorputc(char c, unsigned int color)
VGA_Y++;
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);
}
@@ -167,11 +156,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)
{
colorputc(*str, color);
colorputc(*str, fg, bg);
str++;
}
}
@@ -226,22 +215,39 @@ void printf(const char* fmt, ...)
int length = PRINTF_LENGTH_START;
int radix = 10;
bool sign = false;
int width = 0;
char pad_char = ' ';
argp++;
while (*fmt)
{
switch(state) {
switch (state)
{
case PRINTF_STATE_START:
if (*fmt == '%')
{
state = PRINTF_STATE_LENGTH;
width = 0;
pad_char = ' ';
}
else {
else
{
putc(*fmt);
}
break;
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;
state = PRINTF_STATE_SHORT;
@@ -251,30 +257,47 @@ void printf(const char* fmt, ...)
length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LONG;
}
else {
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 {
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_LONG:
if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC;
}
else {
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_:
switch (*fmt)
@@ -294,33 +317,32 @@ void printf(const char* fmt, ...)
case 'i':
radix = 10;
sign = true;
argp = printf_number(argp, length, sign, radix);
argp = printf_number(argp, length, sign, radix, width, pad_char);
break;
case 'u':
radix = 10;
sign = false;
argp = printf_number(argp, length, sign, radix);
argp = printf_number(argp, length, sign, radix, width, pad_char);
break;
case 'X':
case 'x':
case 'p':
radix = 16;
sign = false;
argp = printf_number(argp, length, sign, radix);
argp = printf_number(argp, length, sign, radix, width, pad_char);
break;
case 'o':
radix = 8;
sign = false;
argp = printf_number(argp, length, sign, radix);
argp = printf_number(argp, length, sign, radix, width, pad_char);
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
dtostrf(d, buffer, 6);
puts(buffer);
argp += 2; // Incrementing by 2 to move past the double argument
argp += 2;
break;
}
default:
@@ -330,6 +352,8 @@ void printf(const char* fmt, ...)
length = PRINTF_LENGTH_START;
radix = 10;
sign = false;
width = 0;
pad_char = ' ';
break;
}
fmt++;
@@ -338,7 +362,7 @@ void printf(const char* fmt, ...)
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];
unsigned long long number;
@@ -360,7 +384,8 @@ int* printf_number(int* argp, int length, bool sign, int radix)
}
number = (unsigned long long)n;
}
else {
else
{
number = *(unsigned int*)argp;
}
argp++;
@@ -376,7 +401,8 @@ int* printf_number(int* argp, int length, bool sign, int radix)
}
number = (unsigned long long)n;
}
else {
else
{
number = *(unsigned long int*)argp;
}
argp += 2;
@@ -392,14 +418,16 @@ int* printf_number(int* argp, int length, bool sign, int radix)
}
number = (unsigned long long)n;
}
else {
else
{
number = *(unsigned long long int*)argp;
}
argp += 4;
break;
}
do {
do
{
uint32_t rem;
x86_div64_32(number, radix, &number, &rem);
buffer[pos++] = charset[rem];
@@ -410,6 +438,13 @@ int* printf_number(int* argp, int length, bool sign, int radix)
buffer[pos++] = '-';
}
int padding = width - pos;
while (padding-- > 0)
{
putc(pad_char);
}
while (--pos >= 0)
{
putc(buffer[pos]);

View File

@@ -1,7 +1,13 @@
#ifndef INCLUDE_STDIO_H
#define INCLUDE_STDIO_H
// Standard input/output implementation for blankos/libc header
// 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_DARK_GREY 8
@@ -11,23 +17,29 @@
#define FB_HIGH_BYTE_CMD 14
#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 putchar(int x, int y, char c);
void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg);
void puts(const char* str);
void colorputs(const char* str, unsigned int color);
void clear(void);
void colorputs(const char* str, uint32_t fg, uint32_t bg);
void putcolor(int x, int y, unsigned int color);
char getchar(int x, int y);
unsigned int getcolor(int x, int y);
void scroll(int lines);
void putc(char c);
void colorputc(char c, unsigned int color);
void colorputc(char c, uint32_t fg, uint32_t bg);
#define PRINTF_STATE_START 0
#define PRINTF_STATE_LENGTH 1
#define PRINTF_STATE_SHORT 2
#define PRINTF_STATE_LONG 3
#define PRINTF_STATE_SPEC 4
#define PRINTF_STATE_WIDTH 5
#define PRINTF_LENGTH_START 0
#define PRINTF_LENGTH_SHORT_SHORT 1
@@ -36,10 +48,43 @@ void colorputc(char c, unsigned int color);
#define PRINTF_LENGTH_LONG_LONG 4
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();
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
};
#endif

View File

@@ -1,4 +1,10 @@
#include "stdint.h"
// 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)
{
@@ -68,3 +74,32 @@ char* strtok(char* str, const char* delimiter)
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';
}

View File

@@ -1,8 +1,16 @@
#ifndef INCLUDE_STRING_H
#define INCLUDE_STRING_H
// String operations implementation for blankos/libc header
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#ifndef STRING_H
#define STRING_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);
#endif

View File

@@ -1,3 +1,7 @@
// Simple brainfuck interpreter program
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "../kernel/system.h"
#include "../libc/stdio.h"

View File

@@ -1,5 +1,12 @@
// 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)
{
@@ -22,18 +29,28 @@ void rot13(char* input, char* output)
output[i] = '\0';
}
void program_rot13()
void program_rot13(int argc, char* argv[])
{
char input_buffer[BUFFER_SIZE];
char output[BUFFER_SIZE];
puts("String? ");
get_input(input_buffer, BUFFER_SIZE);
rot13(input_buffer, output);
printf("\n%s\n", output);
if (argc < 2)
{
printf("Usage: %s <string>\n", argv[0]);
return;
}
#include "../libc/string.h"
#include "../libc/stdint.h"
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
@@ -117,12 +134,27 @@ void to_morse(const char* input, char* output) {
}
}
void program_morse() {
char output[512];
char input_buffer[BUFFER_SIZE];
puts("String? ");
get_input(input_buffer, BUFFER_SIZE);
to_morse(input_buffer, output);
printf("\n%s\n", output);
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);
}

View File

@@ -1,3 +1,8 @@
// Cipher programs header
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#ifndef CIPHERS_H
#define CIPHERS_H

View File

@@ -1,21 +1,25 @@
// 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 "../libc/stdint.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++)
{
//(grid[i][j] == LIVE) ? putc(42) : putc(32);
if (grid[i][j] == LIVE) {
serial_printf(3, "alive");
colorputc(32, 120);
putc(35);
} else {
putc(32);
}

View File

@@ -1,8 +1,13 @@
// 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 25
#define Y 80
#define X 66
#define Y 240
#define GENERATIONS 100
#define DEAD 0

72
src/programs/cowsay.c Normal file
View 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);
}

View File

@@ -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 "../libc/stdio.h"
#include "../libc/ctype.h"

View File

@@ -1,24 +1,52 @@
// Miscellaneous small programs
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "../libc/stdio.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"
// Print a rainbow colorful text for testing
#define BUF_SIZE 256
#define COLORS 20
void program_rainbow()
void program_rainbow(int argc, char* argv[])
{
char input_buffer[BUF_SIZE];
puts("What to print? ");
get_input(input_buffer, BUF_SIZE);
puts("\n");
if (argc < 2)
{
printf("Usage: %s <string>\n", argv[0]);
return;
}
for (int i=0; i<COLORS; i++)
char input_buffer[BUF_SIZE] = {0};
for (int i=1; i<argc; i++)
{
colorputs(input_buffer, 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");
}
}
@@ -29,7 +57,7 @@ void program_rainbow()
void program_clear()
{
for (int i=0; i<ROWS; i++) scroll(1);
clear();
}
// Get uptime in ticks
@@ -37,7 +65,7 @@ void program_clear()
void program_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);
}
@@ -45,7 +73,7 @@ void program_uptime()
void program_help()
{
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\t uptime echo\t sysinfo\tconway\nrot13 morse\n");
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\t uptime echo\t sysinfo\tconway\nrot13 morse\tcowsay time\t read\t reboot\npi\n");
}
// Panic
@@ -68,3 +96,50 @@ void program_echo(int argc, char* argv[])
}
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");
}

34
src/programs/pi.c Normal file
View 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);
}

View File

@@ -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 "../kernel/system.h"
#include "../libc/string.h"
#define PRIMES_MAX 1000000
@@ -11,15 +17,28 @@ bool isPrime(int n)
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)
{
primes_max = atoi(argv[1]);
}
for (long long x=0; x<primes_max; x++)
{
if (isPrime(x) && x != 3301)
{
printf("%d ", x);
} else if(x == 3301)
{
colorputs("3301 ", red, black);
}
delay(2);
delay(1);
}
puts("\n");
}

View File

@@ -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
#define PROGRAMS_H
@@ -10,6 +15,9 @@ void program_sysinfo();
void get_cpuid();
void get_meminfo(unsigned int multiboot_info_address);
void program_conway();
void program_cowsay();
void cowsay(); // Splash screen
void program_pi();
// Ciphers
void program_rot13();
@@ -22,4 +30,8 @@ void program_uptime();
void program_panic();
void program_help();
void program_echo();
void program_time();
void program_read();
void program_reboot();
#endif

View File

@@ -1,3 +1,7 @@
// 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"
@@ -36,6 +40,7 @@ void get_cpuid()
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
@@ -52,13 +57,15 @@ void get_meminfo(unsigned int multiboot_info_address, int verbose)
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));
}
}

View File

@@ -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/crypto.h"
#include "../kernel/system.h"
#include "../libc/string.h"
// Small dictionary
char* words[] =
{
// A
"I", "us", "they", "my",
"a", "an", "is", "are", "for", "while", "not", "none", "yes", "no",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"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",
"xenon", "xenophobia", "xerox", "xmas", "x-ray", "xylophone", "xylem",
// Y
"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",
"zero", "zone", "zoo", "zoom", "zeal", "zip", "zigzag",
"zenith", "zest", "zipper", "zombie", "zonal", "zinc", "zephyr"
};
int words_size = sizeof(words)/sizeof(words[0]);
// Generates 5 random words
void program_words()
// Generates random 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);
char* word = words[random%words_size];

Binary file not shown.