47 Commits

Author SHA1 Message Date
8ff6e4fdb8 Update README.md 2025-12-29 10:16:07 +01:00
8332af1370 Upload image to get away from GitHub 2025-12-29 10:15:33 +01:00
xamidev
14a9bdad7d fix: cc warns 2024-09-27 21:31:27 +02:00
xamidev
756dc638e8 fix: font changing made easier 2024-09-27 20:31:27 +02:00
xamidev
903188a543 Change: font 2024-09-27 20:21:24 +02:00
xamidev
8a68cf3b30 Add: calloc 2024-09-27 20:03:24 +02:00
xamidev
1085222d98 Port: uhex (RO) 2024-09-23 17:39:39 +02:00
xamidev
68a4be55ce Update DEVELOPERS.md 2024-09-23 16:42:45 +02:00
xamidev
cee509f6a1 Merge pull request #12 from xamidev/programs
Programs: loading, 1 fake syscall.. (bad)
2024-09-23 16:41:44 +02:00
xamidev
c104657d52 WIP: uhex RO port 2024-09-23 16:40:51 +02:00
xamidev
1fa4b5c70a Add: exec feature for binaries 2024-09-23 15:46:58 +02:00
xamidev
7071b4788b Minor fix in initrd ls 2024-09-23 15:30:20 +02:00
xamidev
5ad32d3ee1 remove: useless lib rule 2024-09-16 17:40:39 +02:00
xamidev
d02b3d62cb err: invalid syscall no 2024-09-16 16:43:59 +02:00
xamidev
af716cb2ec minor fixes 2024-09-16 14:38:39 +02:00
xamidev
e6f119236b Fix: kernel stack 2024-09-15 11:30:56 +02:00
xamidev
c885e69be4 Loaded program cannot do stuff. Answer=syscalls? 2024-09-14 22:55:02 +02:00
xamidev
03b712ace0 Program loading, build system for apps, and badly-made lib linking. 2024-09-14 22:39:06 +02:00
xamidev
87bb1d96fd Change: programs->utils 2024-09-14 20:31:35 +02:00
xamidev
8bac95890a Merge pull request #11 from xamidev/fixes
Fix: compatibility, kernel stack, + docs
2024-09-14 20:09:02 +02:00
xamidev
d89a1c4071 Fix: compatibility, kernel stack, + docs 2024-09-14 20:08:30 +02:00
xamidev
becfc2bc3b Update kmain.h (version) 2024-09-13 14:27:01 +02:00
xamidev
9d665c9648 Merge pull request #10 from xamidev/games
Games
2024-09-13 14:25:13 +02:00
xamidev
6f3c23e088 Fix: snake 2024-09-13 14:24:39 +02:00
xamidev
ef2de556e3 Upgrade: snake 2024-09-13 14:08:00 +02:00
xamidev
40561a6537 Add: snake game! (basics) 2024-09-12 17:54:30 +02:00
xamidev
8093880eaa Merge pull request #8 from xamidev/security
Improved security (a bit)
2024-09-10 21:13:14 +02:00
xamidev
64ccec0866 Fix: explicit typecasting 2024-09-10 21:11:41 +02:00
xamidev
bf0228d3ac Add: strnlen, strncat, safer string functions 2024-09-10 20:48:12 +02:00
xamidev
5e4e6d2db8 Fix: safety: malloc and free BMP image; memcpy sanitizing 2024-09-10 20:14:24 +02:00
xamidev
fa879acd8a Update DEVELOPERS.md 2024-09-10 09:24:50 +02:00
xamidev
e14e5db15a Fix: memory leak in naval 2024-09-10 09:11:08 +02:00
xamidev
d90682c40e Add: colorprintf, kernel panic coloring 2024-09-10 08:40:17 +02:00
xamidev
a9a4b89c85 Merge pull request #7 from xamidev/dev
Add: new homepage pic, naval battle game, PCI driver
2024-09-09 22:29:29 +02:00
xamidev
841e72b431 Update README.md 2024-09-09 22:26:02 +02:00
xamidev
2fa918bc87 Add: naval battle game! 2024-09-09 22:09:14 +02:00
xamidev
df7187ca75 Add: PCI driver, lspci 2024-09-08 13:45:15 +02:00
xamidev
8826a7d873 Minor fixes 2024-09-07 20:27:03 +02:00
xamidev
b0668b1fd7 Merge pull request #6 from xamidev/dev
verbose ls + docs
2024-09-06 21:35:34 +02:00
xamidev
cacc042a5c Minor fixes + docs 2024-09-06 21:16:23 +02:00
xamidev
247558669e Add: BMP working renderer (24b) + minor bug fixes 2024-09-06 21:01:31 +02:00
xamidev
f55723c227 minor bug fixes + bmp first try (not working) 2024-09-06 16:32:11 +02:00
xamidev
acbcc54e51 Modify: bf: add file optional argument 2024-09-05 16:10:01 +02:00
xamidev
d2034cd68b Add: initrd filesystem utilities (ls, cat) + docs 2024-09-05 14:59:51 +02:00
xamidev
b59af22897 Add: TAR init ramdisk via GRUB2 module 2024-09-05 13:06:54 +02:00
xamidev
4d05e0d620 Re-make: kernel heap (malloc, free) via free list alloc + add UEFI emulation doc 2024-09-04 21:49:26 +02:00
xamidev
3b39a0a1f4 add: multiboot2 memory map debug print 2024-09-04 20:17:01 +02:00
67 changed files with 2556 additions and 110 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ blankos.iso
iso/ 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 i386-elf-7.5.0-Linux-x86_64.tar.xz
src/initrd/*.bin

View File

@@ -1,12 +1,12 @@
![Screenshot_20240826_160940](https://github.com/user-attachments/assets/a4d2af98-7c7e-4a7f-a64c-31b0325d99d7) ![BlankOSshowcase](blankos.png)
> [!WARNING] > [!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 free and unencumbered software released into the public domain. Many things might be (are) broken.
> 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. > The project 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, 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). 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!
## Usage ## Usage
@@ -65,7 +65,7 @@ Two other documents are available to help you understand the project better. One
- [X] Kernel-space utilities (shell, simple programs) - [X] Kernel-space utilities (shell, simple programs)
- [ ] Filesystem (FAT32 or VFS ramdisk) - [ ] Filesystem (FAT32 or VFS ramdisk)
- [ ] Changing the default VGA font - [ ] Changing the default VGA font
- [ ] Dynamic memory allocator (get memmap from GRUB?) - [X] Dynamic memory allocator (get memmap from GRUB?)
- [ ] Paging/Page Frame Allocation - [ ] Paging/Page Frame Allocation
- [ ] TCP/IP Network stack - [ ] TCP/IP Network stack
- [ ] Getting to Ring-3 (userspace) - [ ] Getting to Ring-3 (userspace)

BIN
blankos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

5
debug.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
qemu-system-i386 -s -S -drive file=blankos.iso,format=raw &
sleep 1
gdb -x gdbinit

View File

@@ -3,18 +3,22 @@
## Table of Contents ## Table of Contents
- Getting Started - Getting Started
- Debugging the kernel
- Emulated booting in UEFI mode
- Writing programs for BlankOS - Writing programs for BlankOS
- Changing the TTY font - Changing the TTY font
- Changing the initial ramdisk content
- Changing the framebuffer resolution
## Getting Started ## Getting Started
### System description ### 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). 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 ### 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. 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 ### System calls
@@ -26,20 +30,23 @@ No system calls are available, as the OS runs in kernel-space.
make debug make debug
``` ```
In another shell: ## 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:
``` ```
gdb kernel.elf 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
(gdb) target remote localhost:1234
``` ```
## Writing programs for BlankOS ## 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. 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.
(Now, there is a 'beginning' of something that we could call real programs, but I still suck at making the syscalls work. One day, one day...)
### Step 1 - Making the program and the entry point ### 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`. To make a program for the OS, first create the appropriate C source file and header file in the `src/utils` 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. 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.
@@ -60,7 +67,7 @@ Now that your program is done, you will need to make it a part of the OS.
#### General program header file registering #### 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`. 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/utils/programs.h`.
Put the entry point function prototype in that file. A valid example might be: Put the entry point function prototype in that file. A valid example might be:
@@ -82,7 +89,7 @@ Don't make your command name too long, preferably a few characters, like the oth
#### Help utility registering (optional) #### 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()`. Finally, you can add your command to the list of available commands by adding it to the `printf` call in the `src/utils/misc.c` source file, in the function `program_help()`.
If possible make sure that the new command name is aligned with the other ones. If possible make sure that the new command name is aligned with the other ones.
@@ -109,3 +116,26 @@ 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. 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. 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.

View File

@@ -69,9 +69,9 @@ Clears the screen by scrolling (screen height) times.
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) 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` #### `bf <optional: file>`
A brainfuck interpreter with every instruction and default tape size (30k cells). A brainfuck interpreter with every instruction and default tape size (30k cells). Takes an optional argument, the filename for a Brainfuck source file.
#### `uptime` #### `uptime`
@@ -113,3 +113,41 @@ Makes a cow speak!
#### `pi <terms>` #### `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. 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
#### `exec <binary>`
Executes a binary file. Warning: this is highly broken and syscalls aren't working. It's written in a childish manner. Help is always appreciated (lol).
#### `uhex <file>`
Prints the hex and ASCII contents of a file.

2
gdbinit Normal file
View File

@@ -0,0 +1,2 @@
target remote localhost:1234
symbol-file kernel.elf

View File

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

Binary file not shown.

Binary file not shown.

View File

@@ -3,7 +3,7 @@ ENTRY(loader)
SECTIONS { SECTIONS {
/* Address to load at; 2MB */ /* Address to load at; 2MB */
/*. = 2M;*/ . = 2M;
.multiboot_header ALIGN(4K) : { .multiboot_header ALIGN(4K) : {
*(.multiboot_header) *(.multiboot_header)

View File

@@ -1,37 +1,49 @@
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 = -ffreestanding -g -Wall -Wextra -Wno-builtin-declaration-mismatch -c -I src/ CFLAGS = -ffreestanding -g -Wall -Wextra -mno-sse -mno-mmx -mno-avx -march=i386 -c -I src/
LD = ld
LDFLAGS = -T link.ld -melf_i386 LDFLAGS = -T link.ld -melf_i386
AS = nasm AS = nasm
ASFLAGS = -f elf ASFLAGS = -f elf
AR = i386-elf-7.5.0-Linux-x86_64/bin/i386-elf-ar
SRC_DIR = src SRC_DIR = src
KERNEL_DIR = $(SRC_DIR)/kernel KERNEL_DIR = $(SRC_DIR)/kernel
LIBC_DIR = $(SRC_DIR)/libc LIBC_DIR = $(SRC_DIR)/libc
PROGRAMS_DIR = $(SRC_DIR)/programs UTILS_DIR = $(SRC_DIR)/utils
DRIVERS_DIR = $(SRC_DIR)/drivers DRIVERS_DIR = $(SRC_DIR)/drivers
PROGRAMS_DIR = $(SRC_DIR)/programs
INCLUDE_DIR = include INCLUDE_DIR = include
FONTS_DIR = $(INCLUDE_DIR)/fonts 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 $(UTILS_DIR)/*.c) $(wildcard $(DRIVERS_DIR)/*.c)
ASM_SOURCES = $(wildcard $(KERNEL_DIR)/*.s) $(wildcard $(LIBC_DIR)/*.s) $(wildcard $(PROGRAMS_DIR)/*.s) $(wildcard $(DRIVERS_DIR)/*.s) ASM_SOURCES = $(wildcard $(KERNEL_DIR)/*.s) $(wildcard $(LIBC_DIR)/*.s) $(wildcard $(UTILS_DIR)/*.s) $(wildcard $(DRIVERS_DIR)/*.s)
PROGRAM_SOURCES = $(wildcard $(PROGRAMS_DIR)/*.c)
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))
PROGRAM_OBJECTS = $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(PROGRAM_SOURCES:.c=.o))
TOOLCHAIN_SRC = https://newos.org/toolchains/i386-elf-7.5.0-Linux-x86_64.tar.xz 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 TOOLCHAIN_FILE = i386-elf-7.5.0-Linux-x86_64.tar.xz
FONT_OBJ = $(OBJ_DIR)/fonts/UniCyr_8x16.o FONT_OBJ = $(OBJ_DIR)/fonts/viscii10-8x16.o
FONT_SRC = $(FONTS_DIR)/UniCyr_8x16.psf FONT_SRC = $(FONTS_DIR)/viscii10-8x16.psfu
all: $(OBJ_DIR) kernel.elf all: $(OBJ_DIR) kernel.elf programs
$(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 $(OBJ_DIR)/fonts mkdir -p $(OBJ_DIR)/kernel $(OBJ_DIR)/libc $(OBJ_DIR)/utils $(OBJ_DIR)/drivers $(OBJ_DIR)/fonts $(OBJ_DIR)/programs
kernel.elf: $(OBJECTS) $(FONT_OBJ) kernel.elf: $(OBJECTS) $(FONT_OBJ)
ld $(LDFLAGS) $(OBJECTS) $(FONT_OBJ) -o kernel.elf $(LD) $(LDFLAGS) $(OBJECTS) $(FONT_OBJ) -o kernel.elf
programs: $(PROGRAM_OBJECTS)
@mkdir -p $(SRC_DIR)/initrd
@for prog in $(PROGRAM_OBJECTS); do \
base=$$(basename $$prog .o); \
$(LD) -melf_i386 -T program.ld $$prog -o $(SRC_DIR)/initrd/$$base.bin; \
done
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $< -o $@ $(CC) $(CFLAGS) $< -o $@
@@ -49,18 +61,22 @@ toolchain:
wget $(TOOLCHAIN_SRC) wget $(TOOLCHAIN_SRC)
tar xf $(TOOLCHAIN_FILE) tar xf $(TOOLCHAIN_FILE)
iso: kernel.elf iso: kernel.elf initrd
mkdir -p iso/boot/grub
cp kernel.elf iso/boot/kernel.elf cp kernel.elf iso/boot/kernel.elf
cp grub.cfg iso/boot/grub/grub.cfg cp grub.cfg iso/boot/grub/grub.cfg
grub-mkrescue iso -o blankos.iso grub-mkrescue iso -o blankos.iso
initrd:
mkdir -p iso/boot/grub
tar -cf $(OBJ_DIR)/initrd.tar -C $(SRC_DIR)/initrd .
cp $(OBJ_DIR)/initrd.tar iso/boot
run: iso run: iso
qemu-system-i386 -drive file=blankos.iso,format=raw qemu-system-i386 -drive file=blankos.iso,format=raw
debug: debug:
qemu-system-i386 -s -S -drive file=blankos.iso,format=raw ./debug.sh
clean: clean:
rm -rf $(OBJ_DIR) kernel.elf blankos.iso $(TOOLCHAIN_FILE) rm -rf $(OBJ_DIR) kernel.elf blankos.iso $(TOOLCHAIN_FILE) $(SRC_DIR)/initrd/*.bin

10
program.ld Normal file
View File

@@ -0,0 +1,10 @@
OUTPUT_FORMAT(binary)
ENTRY(main)
SECTIONS
{
. = 0x1000;
.text : { *(.text*) }
.data : { *(.data*) }
.bss : { *(.bss*) }
}

View File

@@ -7,26 +7,66 @@
#include "framebuffer.h" #include "framebuffer.h"
#include "serial.h" #include "serial.h"
#include "../kernel/system.h" #include "../kernel/system.h"
#include "../kernel/kheap.h"
extern char* framebuffer; extern char* framebuffer;
void psf_init()
{
uint16_t glyph = 0;
PSF_font *font = (PSF_font*)&FONT_START;
if (font->flags)
{
unicode = NULL;
return;
}
char* s = (char*)((unsigned char*)&FONT_START + font->headersize + font->numglyph * font->bytesperglyph);
unicode = calloc(USHRT_MAX, 2);
while((uintptr_t)s>(uintptr_t)FONT_END){
uint16_t uc = (uint16_t)((unsigned char)s[0]);
if(uc == 0xFF) {
glyph++;
s++;
continue;
} else if(uc & 128) {
/* UTF-8 to unicode */
if((uc & 32) == 0 ) {
uc = ((s[0] & 0x1F)<<6)+(s[1] & 0x3F);
s++;
} else
if((uc & 16) == 0 ) {
uc = ((((s[0] & 0xF)<<6)+(s[1] & 0x3F))<<6)+(s[2] & 0x3F);
s+=2;
} else
if((uc & 8) == 0 ) {
uc = ((((((s[0] & 0x7)<<6)+(s[1] & 0x3F))<<6)+(s[2] & 0x3F))<<6)+(s[3] & 0x3F);
s+=3;
} else
uc = 0;
}
/* save translation */
unicode[uc] = glyph;
s++;
}
}
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color) 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));
uint32_t* pixel_addr = (uint32_t*)((uint8_t*)fb + y * pitch + x *(bpp / 8)); *pixel_addr = color;
*pixel_addr = color;
}
} }
void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg) 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; PSF_font *font = (PSF_font*)&FONT_START;
int bytesperline=(font->width+7)/8; int bytesperline=(font->width+7)/8;
if (unicode != NULL) { if (unicode != NULL) {
c = unicode[c]; 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; unsigned char* glyph = (unsigned char*)&FONT_START + font->headersize + (c>0&&c<font->numglyph?c:0)*font->bytesperglyph;
int offs = int offs =
(cy * font->height * scanline) + (cy * font->height * scanline) +
@@ -56,7 +96,7 @@ void scroll()
{ {
serial_printf(3, "Scrolling...\r"); serial_printf(3, "Scrolling...\r");
uint32_t bg_color = 0x00000000; uint32_t bg_color = 0x00000000;
PSF_font *font = (PSF_font*)&_binary_include_fonts_UniCyr_8x16_psf_start; PSF_font *font = (PSF_font*)&FONT_START;
int line_size = font->height * scanline; int line_size = font->height * scanline;
int framebuffer_size = scanline * font->height * (1080/font->height); int framebuffer_size = scanline * font->height * (1080/font->height);

View File

@@ -9,11 +9,16 @@
#include <stdint.h> #include <stdint.h>
extern int scanline; extern int scanline;
extern char _binary_include_fonts_UniCyr_8x16_psf_start;
uint16_t* unicode;
#define FONT_START _binary_include_fonts_viscii10_8x16_psfu_start
#define FONT_END _binary_include_fonts_viscii10_8x16_psfu_start
extern char FONT_START;
extern char FONT_END;
uint16_t* unicode;
#define PIXEL uint32_t #define PIXEL uint32_t
#define USHRT_MAX 10000
#define PSF1_FONT_MAGIC 0x0436 #define PSF1_FONT_MAGIC 0x0436
typedef struct { typedef struct {
@@ -38,5 +43,6 @@ typedef struct {
void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color); 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 draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg);
void scroll(); void scroll();
void psf_init();
#endif #endif

View File

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

View File

@@ -14,5 +14,7 @@
#define RIGHT_SHIFT_RELEASED 0xB6 #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
View 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
View 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

BIN
src/initrd/flower.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

1
src/initrd/hello.bf Normal file
View File

@@ -0,0 +1 @@
-[------->+<]>-.-[->+++++<]>++.+++++++..+++.[--->+<]>-----.---[->+++<]>.-[--->+<]>---.+++.------.--------.

1
src/initrd/hello.txt Normal file
View File

@@ -0,0 +1 @@
hello, ramdisk world!

BIN
src/initrd/hibou.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
src/initrd/red.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
src/initrd/smiley.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View 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
View 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...

View File

@@ -36,9 +36,9 @@ void gdt_install()
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
// Ring 3 // Ring 3
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
gdt_flush(); gdt_flush();
printf("[kernel] GDT gates set (ring 0 and 3), gdt=0x%x\n", &gdt); printf("[kernel] GDT gates set (ring 0), gdt=0x%x\n", (unsigned int)&gdt);
} }

View File

@@ -30,5 +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", &idt); printf("[kernel] loaded IDT at idt=0x%x\n", (unsigned int)&idt);
} }

250
src/kernel/initrd.c Normal file
View File

@@ -0,0 +1,250 @@
// 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"
#include "kheap.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;
}
uint32_t tar_get_size(tar_header_t* header)
{
uint32_t size = 0;
char* size_str = header->size;
for (int i=0; i<11 && size_str[i] != '\0'; i++)
{
size = size*8 + (size_str[i]-'0');
}
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)
{
if (header->typeflag == '5')
{
colorprintf(cyan, black, "%s\n", header->filename);
} else {
printf("%s\n", header->filename);
}
} else {
if (header->typeflag == '5')
{
printf("%7d\t%c\t", (int)header->size, header->typeflag);
colorprintf(cyan, black, " %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;
}
tar_header_t* tar_find(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)
{
return header;
}
uint32_t file_size = tar_get_size(header);
uint32_t file_blocks = (file_size + 511)/512;
header = (tar_header_t*) ((uintptr_t)header+(file_blocks+1)*512);
}
return NULL;
}
void* tar_get_file_content(tar_header_t* header)
{
return (void*) ((uintptr_t)header+512);
}
void* load_file_from_initrd(uint8_t* initrd, const char* filename)
{
tar_header_t* file = tar_find(initrd, filename);
if (file == NULL)
{
printf("'%s' not found\n", filename);
return NULL;
}
uint32_t file_size = tar_get_size(file);
void* file_data = malloc(file_size);
if (file_data == NULL)
{
printf("Malloc error for file '%s'\n", filename);
return NULL;
}
void* file_content = tar_get_file_content(file);
memcpy(file_data, file_content, file_size);
printf("[initrd] Loaded '%s' at 0x%x, size=%u\n", filename, (unsigned int)file_data, file_size);
return file_data;
}

40
src/kernel/initrd.h Normal file
View File

@@ -0,0 +1,40 @@
// 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);
void* load_file_from_initrd(uint8_t* initrd, const char* filename);
#endif

View File

@@ -25,6 +25,8 @@ extern void irq13();
extern void irq14(); extern void irq14();
extern void irq15(); extern void irq15();
extern void syscall_common_stub();
void *irq_routines[16] = void *irq_routines[16] =
{ {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -76,6 +78,8 @@ void irq_install()
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"); printf("[kernel] installed irq 0-15\n");
idt_set_gate(0x80, (unsigned long)syscall_common_stub, 0x08, 0x8E);
} }
void irq_handler(struct regs *r) void irq_handler(struct regs *r)

View File

@@ -116,7 +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 (;;);
} }
} }

View File

@@ -5,42 +5,79 @@
#include "kheap.h" #include "kheap.h"
#include <stdint.h> #include <stdint.h>
#include "system.h"
#include "../libc/stdio.h"
extern uint32_t end; // Free list allocator
uint32_t placement_address = (uint32_t)&end;
uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys) static uint8_t heap[HEAP_SIZE];
static block_t* free_list = NULL;
void init_alloc()
{ {
if (align == 1 && (placement_address & 0x00000FFF)) free_list = (block_t*)heap;
free_list->size = HEAP_SIZE-sizeof(block_t);
free_list->next = NULL;
printf("[kernel] initialized heap and allocator, start=0x%x\n", heap);
}
void* malloc(size_t size)
{
block_t* prev = NULL;
block_t* curr = free_list;
while (curr != NULL)
{ {
placement_address &= 0xFFFFF000; if (curr->size >= size)
placement_address += 0x1000; {
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;
} }
if (phys)
return NULL;
}
void* calloc(size_t num, size_t size)
{
size_t total_size = num*size;
void* ptr = malloc(total_size);
if (ptr != NULL)
{ {
*phys = placement_address; uint8_t* byte_ptr = (uint8_t*)ptr;
for (size_t i=0; i<total_size; i++)
{
byte_ptr[i] = 0;
}
} }
uint32_t tmp = placement_address;
placement_address += sz; return ptr;
return tmp;
} }
uint32_t kmalloc_a(uint32_t sz) void free(void* ptr)
{ {
return kmalloc_int(sz, 1, 0); if (ptr == NULL) return;
}
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) block_t* block_to_free = (block_t*)((uint8_t*)ptr - sizeof(block_t));
{ block_to_free->next = free_list;
return kmalloc_int(sz, 0, phys); free_list = block_to_free;
}
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);
} }

View File

@@ -7,10 +7,19 @@
#define KHEAP_H #define KHEAP_H
#include <stdint.h> #include <stdint.h>
#include "system.h"
uint32_t kmalloc_a(uint32_t sz); typedef struct block
uint32_t kmalloc_p(uint32_t sz, uint32_t *phys); {
uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys); size_t size;
uint32_t kmalloc(uint32_t sz); 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);
void* calloc(size_t num, size_t size);
#endif #endif

View File

@@ -12,10 +12,17 @@
#include <stdint.h> #include <stdint.h>
#include "../drivers/framebuffer.h" #include "../drivers/framebuffer.h"
#include "kmain.h" #include "kmain.h"
#include "multiboot2.h"
#include "kheap.h"
#include "initrd.h"
#include "../utils/utils.h"
#include "../libc/crypto.h"
void kmain(multiboot2_info *mb_info) void kmain(multiboot2_info *mb_info)
{ {
multiboot2_tag_framebuffer *fb_info = NULL; 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; uint8_t *tags = mb_info->tags;
while (1) { while (1) {
@@ -23,36 +30,80 @@ void kmain(multiboot2_info *mb_info)
uint32_t tag_size = *((uint32_t*) (tags + 4)); uint32_t tag_size = *((uint32_t*) (tags + 4));
if (tag_type == 0) break; if (tag_type == 0) break;
if (tag_type == 8) { if (tag_type == MULTIBOOT_TAG_TYPE_FRAMEBUFFER) {
fb_info = (multiboot2_tag_framebuffer*) tags; 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); tags += ((tag_size + 7) & ~7);
} }
serial_printf(3, "Framebuffer Address: 0x%x", fb_info->framebuffer_addr); if (fb_info) { // fb setup
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; framebuffer = (uint32_t *)(uintptr_t) fb_info->framebuffer_addr;
uint32_t width = fb_info->framebuffer_width; uint32_t width = fb_info->framebuffer_width;
uint32_t height = fb_info->framebuffer_height; uint32_t height = fb_info->framebuffer_height;
uint32_t bpp = fb_info->framebuffer_bpp; bpp = fb_info->framebuffer_bpp;
pitch = fb_info->framebuffer_pitch;
//8x16 font, not padded //8x16 font, not padded
VGA_WIDTH = width/8; VGA_WIDTH = width/8;
VGA_HEIGHT = height/16; VGA_HEIGHT = height/16;
serial_printf(3, "VGA_WIDTH=%d, VGA_HEIGHT=%d", VGA_WIDTH, VGA_HEIGHT); serial_printf(3, "VGA_WIDTH=%d, VGA_HEIGHT=%d", VGA_WIDTH, VGA_HEIGHT);
scanline = width * (bpp/8); 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);
}
psf_init();
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);
}
} }
printf("[kernel] multiboot2 info at 0x%x, size=%u\n", mb_info, mb_info->total_size); if (initrd_module) {
printf("[kernel] framebuffer discovered at 0x%x\n", fb_info->framebuffer_addr); initrd_addr = initrd_module->mod_start;
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);
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();
gdt_install(); gdt_install();
@@ -61,7 +112,17 @@ void kmain(multiboot2_info *mb_info)
irq_install(); irq_install();
__asm__ __volatile__("sti"); __asm__ __volatile__("sti");
//test_read_sector(); init_alloc();
void* ptr1 = malloc(256);
void* ptr2 = malloc(512);
printf("[debug] malloc test ptr1=0x%x, ptr2=0x%x\n", (unsigned int)ptr1, (unsigned int)ptr2);
free(ptr1); free(ptr2);
void* ptr3 = calloc(1024, 2);
printf("[debug] calloc test ptr3=0x%x\n", (unsigned int)ptr3);
free (ptr3);
// usually the place where i do testing
timer_install(); timer_install();
keyboard_install(); keyboard_install();

View File

@@ -6,6 +6,10 @@
#ifndef KMAIN_H #ifndef KMAIN_H
#define KMAIN_H #define KMAIN_H
#define BLANK_VERSION "0.3.123-alpha"
#include <stdint.h>
typedef struct { typedef struct {
uint32_t type; uint32_t type;
uint32_t size; uint32_t size;
@@ -28,9 +32,13 @@ unsigned int g_multiboot_info_address;
uint32_t* framebuffer; uint32_t* framebuffer;
int scanline; int scanline;
uint32_t initrd_addr;
// in characters, not pixels // in characters, not pixels
uint32_t VGA_WIDTH; uint32_t VGA_WIDTH;
uint32_t VGA_HEIGHT; uint32_t VGA_HEIGHT;
uint32_t bpp;
uint32_t pitch;
#endif #endif

View File

@@ -51,6 +51,7 @@ KERNEL_STACK_SIZE equ 4096
extern kmain extern kmain
loader: loader:
mov esp, kernel_stack + KERNEL_STACK_SIZE
cli cli
push ebx push ebx
call kmain call kmain
@@ -209,8 +210,39 @@ irq_common_stub:
add esp, 8 add esp, 8
iret iret
; we'll be placing the syscall_common_stub here.
; push everything, then call syscall_handler (be sure to define it extern)
; then pop back everything and iret
extern syscall_handler
global syscall_common_stub
syscall_common_stub:
pusha
push ds
push es
push fs
push gs
mov eax, ds
push eax ; save ds
mov ax, 0x01 ; kernel segment YES I CHEATED I KNOW THIS SUCKS
mov ds, ax
mov es, ax
call syscall_handler
pop eax
mov ds, eax ; restore ds
pop gs
pop fs
pop es
pop ds
popa
iret
section .bss section .bss
align 4 align 4
kernel_stack: kernel_stack:
resb KERNEL_STACK_SIZE resb KERNEL_STACK_SIZE
mov esp, kernel_stack + KERNEL_STACK_SIZE

417
src/kernel/multiboot2.h Normal file
View 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 */

View File

@@ -6,10 +6,11 @@
#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 "../utils/utils.h"
#include "../libc/crypto.h" #include "../libc/crypto.h"
#include <stdint.h> #include <stdint.h>
#include "../drivers/rtc.h" #include "../drivers/rtc.h"
#include "kmain.h"
#define BUFFER_SIZE 256 #define BUFFER_SIZE 256
#define MAX_COMMANDS 64 #define MAX_COMMANDS 64
@@ -54,7 +55,10 @@ void splash()
int random = randint(time_seed()); int random = randint(time_seed());
char* motd_pick = motd[random%motd_size]; char* motd_pick = motd[random%motd_size];
cowsay(motd_pick, red, black); cowsay(motd_pick, red, black);
colorputs(" blankOS 0.3.97-alpha", red, black); puts(" ");
colorputs("blankOS", black, white);
puts(" ");
colorputs(BLANK_VERSION, red, black);
puts("\n"); puts("\n");
@@ -136,6 +140,14 @@ void shell_install()
register_command("read", program_read); register_command("read", program_read);
register_command("reboot", program_reboot); register_command("reboot", program_reboot);
register_command("pi", program_pi); 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);
register_command("exec", program_exec);
register_command("uhex", program_uhex);
for (;;) for (;;)
{ {

33
src/kernel/syscalls.c Normal file
View File

@@ -0,0 +1,33 @@
// System calls
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "../libc/stdio.h"
void handle_syscall(int syscall_number)
{
switch(syscall_number)
{
case 1:
puts("Here's the syscall 1\n");
break;
default:
printf("[error] Invalid syscall number '%d'!\n", syscall_number);
break;
}
}
void syscall_handler()
{
int syscall_number;
void* arg;
// mov eax, syscall_number
// mov ebx, arg
asm volatile("mov %%eax, %0" : "=r"(syscall_number));
asm volatile("mov %%ebx, %0" : "=r"(arg));
printf("[syscall] syscall_number=%d, arg=%p\n", syscall_number, arg);
handle_syscall(syscall_number);
}

View File

@@ -34,7 +34,20 @@ void *memmove(void* dest, const void* src, size_t n)
return dest; 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() void panic()
{ {
for (;;); for (;;);
} }

View File

@@ -13,6 +13,7 @@ typedef int size_t;
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 *memmove(void* dest, const void* src, size_t n);
void *memcpy(void* dest, const void* src, uint32_t n);
struct regs struct regs
{ {
@@ -38,5 +39,7 @@ extern volatile unsigned long global_ticks;
extern unsigned int g_multiboot_info_address; extern unsigned int g_multiboot_info_address;
void syscall_handler();
#endif #endif

View File

@@ -15,8 +15,19 @@ extern uint32_t* framebuffer;
extern uint32_t VGA_WIDTH; extern uint32_t VGA_WIDTH;
extern uint32_t VGA_HEIGHT; extern uint32_t VGA_HEIGHT;
unsigned int VGA_X = 0, VGA_Y = 0; unsigned int VGA_X = 0, VGA_Y = 0;
extern int scanline; extern int scanline;
int get_cursor_x()
{
return VGA_X;
}
int get_cursor_y()
{
return VGA_Y;
}
void draw_cursor(uint32_t color) void draw_cursor(uint32_t color)
{ {
for (int y=12; y<CURSOR_HEIGHT; y++) for (int y=12; y<CURSOR_HEIGHT; y++)
@@ -28,6 +39,25 @@ void draw_cursor(uint32_t 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() void erase_cursor()
{ {
draw_cursor(black); draw_cursor(black);
@@ -481,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;
}

View File

@@ -22,8 +22,10 @@
void draw_cursor(uint32_t color); void draw_cursor(uint32_t color);
void erase_cursor(); void erase_cursor();
void move_cursor(int x, int y); void move_cursor(int x, int y);
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 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 clear(void); void clear(void);
@@ -33,6 +35,8 @@ char getchar(int x, int y);
unsigned int getcolor(int x, int y); unsigned int getcolor(int x, int y);
void putc(char c); void putc(char c);
void colorputc(char c, uint32_t fg, uint32_t bg); 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
@@ -87,4 +91,7 @@ enum Colors
beige = 0x00F5F5DC beige = 0x00F5F5DC
}; };
int get_cursor_x();
int get_cursor_y();
#endif #endif

View File

@@ -103,3 +103,32 @@ void strcat(char* dest, const char* src)
*dest = '\0'; *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';
}

View File

@@ -6,11 +6,16 @@
#ifndef STRING_H #ifndef STRING_H
#define STRING_H #define STRING_H
#include "../kernel/system.h"
int strlen(const char* str); int strlen(const char* str);
int strcmp(const char* str1, const char* str2); int strcmp(const char* str1, const char* str2);
char* strtok(char* str, const char* delimiter); char* strtok(char* str, const char* delimiter);
int atoi(char* str); int atoi(char* str);
void strcat(char* dest, const char* src); 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

10
src/programs/hello.c Normal file
View File

@@ -0,0 +1,10 @@
void user_syscall(int syscall_no) {
asm volatile ("mov %0, %%eax" : : "r"(syscall_no));
asm volatile ("int $0x80");
}
void main()
{
user_syscall(1);
return;
}

View File

@@ -5,6 +5,8 @@
#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
@@ -48,12 +50,25 @@ void brainfuck(char* input)
} }
} }
void program_bf() void program_bf(int argc, char* argv[])
{ {
char input_buffer[BUF_SIZE]; if (argc == 1)
puts("Brainfuck code? "); {
get_input(input_buffer, BUF_SIZE); char input_buffer[BUF_SIZE];
brainfuck(input_buffer); puts("Brainfuck code? ");
//brainfuck(",[.[-],]"); get_input(input_buffer, BUF_SIZE);
puts("\n"); brainfuck(input_buffer);
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/utils/bmp.c Normal file
View 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]);
}

30
src/utils/fs.c Normal file
View 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]);
}

View File

@@ -10,6 +10,9 @@
#include "../drivers/ata.h" #include "../drivers/ata.h"
#include "../drivers/rtc.h" #include "../drivers/rtc.h"
#include "../kernel/io.h" #include "../kernel/io.h"
#include "../drivers/pci.h"
#include "../kernel/initrd.h"
#include "../kernel/kmain.h"
// Print a rainbow colorful text for testing // Print a rainbow colorful text for testing
@@ -73,7 +76,7 @@ void program_uptime()
void program_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\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\t ls\t cat\t bmp\t lspci\t naval\nsnake exec\t uhex\n");
} }
// Panic // Panic
@@ -132,7 +135,7 @@ void program_read(int argc, char* argv[])
} }
} }
// Reboots the machine (might just shutdown) // Reboots the machine (might just shutdown) (or do nothing if youre lucky)
void program_reboot() void program_reboot()
{ {
@@ -143,3 +146,31 @@ void program_reboot()
while (1) asm volatile("hlt"); while (1) asm volatile("hlt");
} }
// List PCI buses and devices
void program_lspci()
{
scan_pci_bus();
}
// Executes binary file
void program_exec(int argc, char* argv[])
{
if (argc < 2)
{
puts("Usage: exec <binary>\n");
return;
}
void* binary_file = load_file_from_initrd((uint8_t*)initrd_addr, argv[1]);
if (binary_file == NULL)
{
printf("[exec] Failed to load program '%s'.\n", argv[1]);
return;
}
void (*program_entry)() = (void (*)())binary_file;
program_entry();
}

348
src/utils/navalbattle.c Normal file
View 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/utils/navalbattle.h Normal file
View 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

View File

@@ -33,7 +33,7 @@ void program_primes(int argc, char* argv[])
{ {
if (isPrime(x) && x != 3301) if (isPrime(x) && x != 3301)
{ {
printf("%d ", x); printf("%d ", (int)x);
} else if(x == 3301) } else if(x == 3301)
{ {
colorputs("3301 ", red, black); colorputs("3301 ", red, black);

200
src/utils/snake.c Normal file
View 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);
}
}

82
src/utils/uhex.c Normal file
View File

@@ -0,0 +1,82 @@
// uhex (microhex) port for BlankOS; read-only version
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
// This version is the port of a hex viewer which already was not great,
// and now by being here it is even worse because it is RO and will have
// hardcoded stuff in it (no ioctl, STDOUT, or other stuff here...)
#define BYTES 1024
#define round(x) (int)(x < 0 ? (x -0.5) : x + 0.5)
#include "../libc/stdio.h"
#include "../kernel/kmain.h"
#include "../kernel/initrd.h"
#include "../libc/string.h"
#include "../kernel/kheap.h"
int isprint(int c)
{
return (c >= 32 && c <= 126);
}
void print_hex(unsigned char* buf, int byteno, int pos, int BYTES_PER_LINE)
{
for (int i=0; i<byteno; i++)
{
if (i%BYTES_PER_LINE == 0)
{
if (i != 0)
{
printf(" ");
for (int j=i-BYTES_PER_LINE; j<i; j++)
{
if (isprint(buf[j])) colorprintf(salmon, black, "%c", buf[j]);
else printf(".");
}
}
puts("\n");
if (pos == 0) printf("%06d: ", i);
else printf("%06d: ", pos);
}
printf("%2x ", buf[i]);
}
int padding = BYTES_PER_LINE - (byteno % BYTES_PER_LINE);
if (padding < BYTES_PER_LINE)
{
for (int i=0; i<padding; i++) printf(" ");
printf(" ");
}
int start = byteno-(byteno%BYTES_PER_LINE);
for (int j=start; j<byteno; j++)
{
if (isprint(buf[j])) {
colorprintf(salmon, black, "%c", buf[j]);
} else {
printf(".");
}
}
puts("\n");
}
void program_uhex(int argc, char* argv[])
{
if (argc < 2)
{
puts("Usage: uhex <file>\n");
return;
}
int BYTES_PER_LINE = 20;
//unsigned char buf[BYTES]; // malloc with file_size next?
uint32_t file_size = tar_get_file_size((uint8_t*)initrd_addr, argv[1]);
unsigned char* buf = (unsigned char*)malloc(file_size);
tar_file_to_buffer((uint8_t*)initrd_addr, argv[1], (char*)buf);
print_hex(buf, file_size, 0, BYTES_PER_LINE);
free(buf);
}

View File

@@ -3,8 +3,8 @@
// Licensed under the Unlicense. See the repo below. // Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos // https://github.com/xamidev/blankos
#ifndef PROGRAMS_H #ifndef UTILS_H
#define PROGRAMS_H #define UTILS_H
void program_words(); void program_words();
void program_primes(); void program_primes();
@@ -13,8 +13,7 @@ void program_bf();
void program_sysinfo(); void program_sysinfo();
void get_cpuid(); void get_cpuid();
void get_meminfo(unsigned int multiboot_info_address); void get_meminfo(unsigned int multiboot_info_address); // to be fixed: cannot get full memory map (sysinfo -v)
void program_conway();
void program_cowsay(); void program_cowsay();
void cowsay(); // Splash screen void cowsay(); // Splash screen
void program_pi(); void program_pi();
@@ -34,4 +33,21 @@ void program_time();
void program_read(); void program_read();
void program_reboot(); 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();
// Binaries loading and execution
void program_exec();
void program_uhex();
#endif #endif