Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c104657d52 | ||
|
|
1fa4b5c70a | ||
|
|
5ad32d3ee1 | ||
|
|
d02b3d62cb | ||
|
|
af716cb2ec | ||
|
|
e6f119236b | ||
|
|
c885e69be4 | ||
|
|
03b712ace0 | ||
|
|
87bb1d96fd | ||
|
|
d89a1c4071 | ||
|
|
becfc2bc3b | ||
|
|
9d665c9648 | ||
|
|
6f3c23e088 | ||
|
|
ef2de556e3 | ||
|
|
40561a6537 | ||
|
|
8093880eaa | ||
|
|
64ccec0866 | ||
|
|
bf0228d3ac | ||
|
|
5e4e6d2db8 | ||
|
|
fa879acd8a | ||
|
|
e14e5db15a | ||
|
|
d90682c40e | ||
|
|
a9a4b89c85 | ||
|
|
841e72b431 | ||
|
|
2fa918bc87 | ||
|
|
df7187ca75 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||

|

|
||||||
|
|
||||||
> [!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.
|
> 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.
|
||||||
|
|||||||
@@ -8,16 +8,17 @@
|
|||||||
- Writing programs for BlankOS
|
- Writing programs for BlankOS
|
||||||
- Changing the TTY font
|
- Changing the TTY font
|
||||||
- Changing the initial ramdisk content
|
- 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
|
||||||
|
|
||||||
@@ -29,13 +30,6 @@ No system calls are available, as the OS runs in kernel-space.
|
|||||||
make debug
|
make debug
|
||||||
```
|
```
|
||||||
|
|
||||||
In another shell:
|
|
||||||
|
|
||||||
```
|
|
||||||
gdb kernel.elf
|
|
||||||
(gdb) target remote localhost:1234
|
|
||||||
```
|
|
||||||
|
|
||||||
## Emulated booting in UEFI mode (QEMU w/ OVMF)
|
## 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:
|
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:
|
||||||
@@ -48,6 +42,8 @@ sudo qemu-system-i386 -drive if=pflash,format=raw,readonly=on,file=/usr/share/OV
|
|||||||
|
|
||||||
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/programs` subfolder. Name it appropriately, for example `myprogram.c`.
|
||||||
@@ -127,3 +123,19 @@ The system loads an initial ramdisk as a simple TAR file located in `iso/boot/in
|
|||||||
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.
|
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.
|
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.
|
||||||
|
|||||||
@@ -129,3 +129,21 @@ Lists all files present in `initrd.tar`.
|
|||||||
#### `cat <file>`
|
#### `cat <file>`
|
||||||
|
|
||||||
Prints file content to terminal. Filename must be specified the same way as it is outputted when using `ls`.
|
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).
|
||||||
|
|||||||
1
grub.cfg
1
grub.cfg
@@ -1,6 +1,5 @@
|
|||||||
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
|
module2 /boot/initrd.tar
|
||||||
boot
|
boot
|
||||||
|
|||||||
2
link.ld
2
link.ld
@@ -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)
|
||||||
|
|||||||
28
makefile
28
makefile
@@ -1,22 +1,27 @@
|
|||||||
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
|
||||||
@@ -24,14 +29,21 @@ 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/UniCyr_8x16.o
|
||||||
FONT_SRC = $(FONTS_DIR)/UniCyr_8x16.psf
|
FONT_SRC = $(FONTS_DIR)/UniCyr_8x16.psf
|
||||||
|
|
||||||
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 $@
|
||||||
@@ -66,5 +78,5 @@ debug:
|
|||||||
./debug.sh
|
./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
10
program.ld
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
OUTPUT_FORMAT(binary)
|
||||||
|
ENTRY(main)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x1000;
|
||||||
|
.text : { *(.text*) }
|
||||||
|
.data : { *(.data*) }
|
||||||
|
.bss : { *(.bss*) }
|
||||||
|
}
|
||||||
@@ -12,11 +12,9 @@ extern char* framebuffer;
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
103
src/drivers/pci.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// PCI bus driver implementation
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "pci.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
|
static inline void outl(uint16_t port, uint32_t value)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t inl(uint16_t port)
|
||||||
|
{
|
||||||
|
uint32_t ret;
|
||||||
|
__asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pci_write_config_address(uint32_t address)
|
||||||
|
{
|
||||||
|
outl(PCI_CONFIG_ADDRESS, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pci_read_config_data()
|
||||||
|
{
|
||||||
|
return inl(PCI_CONFIG_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pci_config_address(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||||
|
{
|
||||||
|
return (1 << 31) | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pci_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset)
|
||||||
|
{
|
||||||
|
uint32_t address = pci_config_address(bus, device, function, offset);
|
||||||
|
pci_write_config_address(address);
|
||||||
|
return pci_read_config_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_device_t pci_get_device(uint8_t bus, uint8_t device, uint8_t function)
|
||||||
|
{
|
||||||
|
pci_device_t dev;
|
||||||
|
|
||||||
|
uint32_t reg0 = pci_read(bus, device, function, 0x00); // Vendor ID, Device ID
|
||||||
|
uint32_t reg2 = pci_read(bus, device, function, 0x08); // Class, Subclass, Prog IF, Revision
|
||||||
|
|
||||||
|
dev.vendor_id = reg0 & 0xFFFF;
|
||||||
|
dev.device_id = (reg0 >> 16) & 0xFFFF;
|
||||||
|
dev.class_code = (reg2 >> 24) & 0xFF;
|
||||||
|
dev.subclass = (reg2 >> 16) & 0xFF;
|
||||||
|
dev.prog_if = (reg2 >> 8) & 0xFF;
|
||||||
|
dev.revision_id = reg2 & 0xFF;
|
||||||
|
dev.bus = bus;
|
||||||
|
dev.device = device;
|
||||||
|
dev.function = function;
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan_pci_bus()
|
||||||
|
{
|
||||||
|
for (uint16_t bus = 0; bus < 256; bus++) {
|
||||||
|
for (uint8_t device = 0; device < 32; device++) {
|
||||||
|
for (uint8_t function = 0; function < 8; function++) {
|
||||||
|
pci_device_t dev = pci_get_device(bus, device, function);
|
||||||
|
|
||||||
|
if (dev.vendor_id != 0xFFFF) {
|
||||||
|
|
||||||
|
// Maybe put that in a database in initrd.tar?
|
||||||
|
char* vendor_string;
|
||||||
|
switch(dev.vendor_id)
|
||||||
|
{
|
||||||
|
case 0x8086:
|
||||||
|
vendor_string = "Intel Corporation";
|
||||||
|
break;
|
||||||
|
case 0x1234:
|
||||||
|
vendor_string = "Brain Actuated Technologies";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vendor_string = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* device_string;
|
||||||
|
switch(dev.device_id)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
device_string = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("PCI Device found: Bus %u, Device %u, Function %u, Vendor ID: 0x%x (%s), Device ID: 0x%x (%s), Class: 0x%x\n",
|
||||||
|
dev.bus, dev.device, dev.function, dev.vendor_id, vendor_string, dev.device_id, device_string, dev.class_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
29
src/drivers/pci.h
Normal file
29
src/drivers/pci.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// PCI bus driver implementation header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef PCI_H
|
||||||
|
#define PCI_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||||
|
#define PCI_CONFIG_DATA 0xCFC
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t vendor_id;
|
||||||
|
uint16_t device_id;
|
||||||
|
uint8_t class_code;
|
||||||
|
uint8_t subclass;
|
||||||
|
uint8_t prog_if;
|
||||||
|
uint8_t revision_id;
|
||||||
|
uint8_t bus;
|
||||||
|
uint8_t device;
|
||||||
|
uint8_t function;
|
||||||
|
} pci_device_t;
|
||||||
|
|
||||||
|
void scan_pci_bus();
|
||||||
|
|
||||||
|
#endif
|
||||||
8
src/initrd/stuff/nice.txt
Normal file
8
src/initrd/stuff/nice.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Subfolder support!
|
||||||
|
|
||||||
|
I am making a bit of scurity improvements but clearly it has no meaing here.
|
||||||
|
The real meanng is the tellin of the Genesis; a true work of art. So many
|
||||||
|
cool stuff here!! Look, there are functions, comands, bits and bytes, conditions,
|
||||||
|
and lgorithms. What a fantastic world! But after all it stays formless and empty.
|
||||||
|
|
||||||
|
1:5:1 1:1:1 7:8:1 1:7:3 1:4:3 2:1:2
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "../libc/string.h"
|
#include "../libc/string.h"
|
||||||
#include "initrd.h"
|
#include "initrd.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include "kheap.h"
|
||||||
|
|
||||||
static unsigned int octal_to_int(const char* str, size_t size)
|
static unsigned int octal_to_int(const char* str, size_t size)
|
||||||
{
|
{
|
||||||
@@ -31,6 +32,18 @@ uint32_t tar_parse_size(const char* in)
|
|||||||
return size;
|
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)
|
void tar_find_file(uint8_t *tar_start, const char* filename)
|
||||||
{
|
{
|
||||||
uint8_t *ptr = tar_start;
|
uint8_t *ptr = tar_start;
|
||||||
@@ -82,7 +95,7 @@ void ls_initrd(uint8_t* initrd, int verbose)
|
|||||||
{
|
{
|
||||||
printf("%s\n", header->filename);
|
printf("%s\n", header->filename);
|
||||||
} else {
|
} else {
|
||||||
printf("%7d\t%c\t %s\n", header->size, header->typeflag, header->filename);
|
printf("%7d\t%c\t %s\n", (int)header->size, header->typeflag, header->filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t size = tar_parse_size(header->size);
|
uint32_t size = tar_parse_size(header->size);
|
||||||
@@ -131,9 +144,16 @@ int tar_file_to_buffer(uint8_t* initrd, const char* filename, char* buffer)
|
|||||||
if (strcmp(file_name, filename) == 0)
|
if (strcmp(file_name, filename) == 0)
|
||||||
{
|
{
|
||||||
uint8_t* file_data = current_block + TAR_BLOCK_SIZE;
|
uint8_t* file_data = current_block + TAR_BLOCK_SIZE;
|
||||||
|
if (sizeof(buffer) >= sizeof(file_data))
|
||||||
|
{
|
||||||
memcpy(buffer, file_data, file_size);
|
memcpy(buffer, file_data, file_size);
|
||||||
buffer[file_size] = '\0';
|
buffer[file_size] = '\0';
|
||||||
return 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;
|
uint32_t total_size = ((file_size + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE) * TAR_BLOCK_SIZE;
|
||||||
@@ -142,3 +162,77 @@ int tar_file_to_buffer(uint8_t* initrd, const char* filename, char* buffer)
|
|||||||
printf("[tar] file '%s' not found\n", filename);
|
printf("[tar] file '%s' not found\n", filename);
|
||||||
return -1;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,5 +34,7 @@ void tar_find_file(uint8_t *tar_start, const char* filename);
|
|||||||
void ls_initrd(uint8_t* initrd, int verbose);
|
void ls_initrd(uint8_t* initrd, int verbose);
|
||||||
void cat_initrd(uint8_t* initrd, const char* filename);
|
void cat_initrd(uint8_t* initrd, const char* filename);
|
||||||
int tar_file_to_buffer(uint8_t* initrd, const char* filename, char* buffer);
|
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
|
#endif
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 (;;);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "kheap.h"
|
#include "kheap.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
// Free list allocator
|
// Free list allocator
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ void init_alloc()
|
|||||||
free_list = (block_t*)heap;
|
free_list = (block_t*)heap;
|
||||||
free_list->size = HEAP_SIZE-sizeof(block_t);
|
free_list->size = HEAP_SIZE-sizeof(block_t);
|
||||||
free_list->next = NULL;
|
free_list->next = NULL;
|
||||||
|
printf("[kernel] initialized heap and allocator, start=0x%x\n", heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* malloc(size_t size)
|
void* malloc(size_t size)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ typedef struct block
|
|||||||
|
|
||||||
#define HEAP_SIZE 1024*1024 // 1MB malloc-able
|
#define HEAP_SIZE 1024*1024 // 1MB malloc-able
|
||||||
|
|
||||||
|
|
||||||
void init_alloc();
|
void init_alloc();
|
||||||
void* malloc(size_t size);
|
void* malloc(size_t size);
|
||||||
void free(void* ptr);
|
void free(void* ptr);
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
#include "multiboot2.h"
|
#include "multiboot2.h"
|
||||||
#include "kheap.h"
|
#include "kheap.h"
|
||||||
#include "initrd.h"
|
#include "initrd.h"
|
||||||
#include "../programs/programs.h"
|
#include "../utils/utils.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
|
||||||
void kmain(multiboot2_info *mb_info)
|
void kmain(multiboot2_info *mb_info)
|
||||||
{
|
{
|
||||||
@@ -64,12 +65,12 @@ void kmain(multiboot2_info *mb_info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("[kernel] multiboot2 info at 0x%x, size=%u\n", mb_info, mb_info->total_size);
|
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] 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);
|
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
|
if (mmap_tag) // memmap debug print
|
||||||
{
|
{
|
||||||
printf("[kernel] found memory map tag by multiboot2\n");
|
puts("[kernel] found memory map tag by multiboot2\n");
|
||||||
struct multiboot_mmap_entry *mmap = mmap_tag->entries;
|
struct multiboot_mmap_entry *mmap = mmap_tag->entries;
|
||||||
|
|
||||||
while ((uint8_t*) mmap < tags + mmap_tag->size)
|
while ((uint8_t*) mmap < tags + mmap_tag->size)
|
||||||
@@ -77,14 +78,14 @@ void kmain(multiboot2_info *mb_info)
|
|||||||
|
|
||||||
if (mmap->addr != 0)
|
if (mmap->addr != 0)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
serial_printf(3, "base addr=0x%x%x, length=0x%x%x, type=%u\n",
|
serial_printf(3, "base addr=0x%x%x, length=0x%x%x, type=%u",
|
||||||
(uint32_t) (mmap->addr >> 32),
|
(uint32_t) (mmap->addr >> 32),
|
||||||
(uint32_t) (mmap->addr & 0xFFFFFFFF),
|
(uint32_t) (mmap->addr & 0xFFFFFFFF),
|
||||||
(uint32_t) (mmap->len >> 32),
|
(uint32_t) (mmap->len >> 32),
|
||||||
(uint32_t) (mmap->len & 0xFFFFFFFF),
|
(uint32_t) (mmap->len & 0xFFFFFFFF),
|
||||||
mmap->type);
|
mmap->type);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
mmap = (struct multiboot_mmap_entry*) ((uint8_t*)mmap + mmap_tag->entry_size);
|
mmap = (struct multiboot_mmap_entry*) ((uint8_t*)mmap + mmap_tag->entry_size);
|
||||||
@@ -114,9 +115,11 @@ void kmain(multiboot2_info *mb_info)
|
|||||||
init_alloc();
|
init_alloc();
|
||||||
void* ptr1 = malloc(256);
|
void* ptr1 = malloc(256);
|
||||||
void* ptr2 = malloc(512);
|
void* ptr2 = malloc(512);
|
||||||
printf("[debug] malloc test ptr1=0x%x, ptr2=0x%x\n", ptr1, ptr2);
|
printf("[debug] malloc test ptr1=0x%x, ptr2=0x%x\n", (unsigned int)ptr1, (unsigned int)ptr2);
|
||||||
free(ptr1); free(ptr2);
|
free(ptr1); free(ptr2);
|
||||||
|
|
||||||
|
// usually the place where i do testing
|
||||||
|
|
||||||
timer_install();
|
timer_install();
|
||||||
keyboard_install();
|
keyboard_install();
|
||||||
printf("[kernel] spawning shell...\n");
|
printf("[kernel] spawning shell...\n");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#ifndef KMAIN_H
|
#ifndef KMAIN_H
|
||||||
#define KMAIN_H
|
#define KMAIN_H
|
||||||
|
|
||||||
#define BLANK_VERSION "0.3.107-alpha"
|
#define BLANK_VERSION "0.3.123-alpha"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#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"
|
||||||
@@ -143,6 +143,10 @@ void shell_install()
|
|||||||
register_command("ls", program_ls);
|
register_command("ls", program_ls);
|
||||||
register_command("cat", program_cat);
|
register_command("cat", program_cat);
|
||||||
register_command("bmp", program_bmp);
|
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);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|||||||
33
src/kernel/syscalls.c
Normal file
33
src/kernel/syscalls.c
Normal 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);
|
||||||
|
}
|
||||||
@@ -50,3 +50,4 @@ void panic()
|
|||||||
{
|
{
|
||||||
for (;;);
|
for (;;);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,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
|
||||||
|
|
||||||
|
|||||||
262
src/libc/stdio.c
262
src/libc/stdio.c
@@ -39,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);
|
||||||
@@ -492,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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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';
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
10
src/programs/hello.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "../drivers/framebuffer.h"
|
#include "../drivers/framebuffer.h"
|
||||||
#include "../libc/stdio.h"
|
#include "../libc/stdio.h"
|
||||||
#include "../drivers/serial.h"
|
#include "../drivers/serial.h"
|
||||||
|
#include "../kernel/kheap.h"
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -38,11 +39,8 @@ typedef struct
|
|||||||
|
|
||||||
void display_bmp(uint32_t* fb, int pitch, int bpp, uint8_t* initrd, const char* filename)
|
void display_bmp(uint32_t* fb, int pitch, int bpp, uint8_t* initrd, const char* filename)
|
||||||
{
|
{
|
||||||
// Should use dynamic allocation when heap works
|
uint32_t buf_size = tar_get_file_size(initrd, filename);
|
||||||
// Cannot go more than ~500k size for buffer
|
char* buffer = (char*)malloc(buf_size);
|
||||||
// Fail zone 450k->470k
|
|
||||||
// So right now the max should be 400kb img size
|
|
||||||
char buffer[400*1000];
|
|
||||||
int file_status = tar_file_to_buffer(initrd, filename, buffer);
|
int file_status = tar_file_to_buffer(initrd, filename, buffer);
|
||||||
|
|
||||||
if (file_status != 0)
|
if (file_status != 0)
|
||||||
@@ -64,7 +62,7 @@ void display_bmp(uint32_t* fb, int pitch, int bpp, uint8_t* initrd, const char*
|
|||||||
int height = bmp_info->biHeight;
|
int height = bmp_info->biHeight;
|
||||||
int pixel_offset = bmp_header->bfOffBits;
|
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, 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();
|
erase_cursor();
|
||||||
uint8_t* pixel_data = (uint8_t*)(buffer + pixel_offset);
|
uint8_t* pixel_data = (uint8_t*)(buffer + pixel_offset);
|
||||||
|
|
||||||
@@ -87,6 +85,7 @@ void display_bmp(uint32_t* fb, int pitch, int bpp, uint8_t* initrd, const char*
|
|||||||
|
|
||||||
// Update cursor pos after image drawing
|
// Update cursor pos after image drawing
|
||||||
move_cursor(get_cursor_x(), get_cursor_y()+(height/16)+2);
|
move_cursor(get_cursor_x(), get_cursor_y()+(height/16)+2);
|
||||||
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void program_bmp(int argc, char* argv[])
|
void program_bmp(int argc, char* argv[])
|
||||||
@@ -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\t ls\t cat\t bmp\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\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
348
src/utils/navalbattle.c
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
// Simplified naval battle game
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "navalbattle.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
#include "../kernel/kheap.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
#include "../drivers/serial.h"
|
||||||
|
|
||||||
|
// Porting problems:
|
||||||
|
// - Color printf? (Need to implement ANSI escape sequences).
|
||||||
|
// - Scanf?
|
||||||
|
// - Malloc? (proof of concept)
|
||||||
|
|
||||||
|
void program_navalbattle()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
grid_t* grid[SIZE][SIZE];
|
||||||
|
grid_t* enemyGrid[SIZE][SIZE];
|
||||||
|
|
||||||
|
init_battlefield(grid);
|
||||||
|
init_battlefield(enemyGrid);
|
||||||
|
|
||||||
|
placing_ally_ships(grid);
|
||||||
|
puts("Now, time for the enemies to prepare...\n");
|
||||||
|
placing_enemy_ships(enemyGrid);
|
||||||
|
|
||||||
|
delay((rand()%MAX_WAIT_TIME)+10);
|
||||||
|
|
||||||
|
puts("Here we go!\n");
|
||||||
|
show_game_stats(grid, enemyGrid);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ally_do_attack(enemyGrid);
|
||||||
|
enemy_do_attack(grid);
|
||||||
|
show_game_stats(grid, enemyGrid);
|
||||||
|
} while (check_victory(grid, enemyGrid) == 0);
|
||||||
|
|
||||||
|
free_grid(grid);
|
||||||
|
free_grid(enemyGrid);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_battlefield(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
grid[i][j] = (grid_t*)malloc(sizeof(grid_t));
|
||||||
|
grid[i][j]->x = i;
|
||||||
|
grid[i][j]->y = j;
|
||||||
|
grid[i][j]->role = 0;
|
||||||
|
grid[i][j]->state = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid memory leaks..
|
||||||
|
void free_grid(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
free(grid[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_ally_battlefield(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
puts("\n*** Ally grid ***\n");
|
||||||
|
puts(" 0 1 2 3 4 5\n");
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
printf("%d ", i);
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
char roleChar = 0;
|
||||||
|
switch(grid[i][j]->state)
|
||||||
|
{
|
||||||
|
case -2:
|
||||||
|
roleChar = 32; // space
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
roleChar = 120;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
roleChar = 79;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
roleChar = 88;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Error: bad value in grid at x=%d y=%d\n", grid[i][j]->x, grid[i][j]->y);
|
||||||
|
shell_install();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == SIZE-1)
|
||||||
|
{
|
||||||
|
printf("%c]", roleChar);
|
||||||
|
} else if (j == 0) {
|
||||||
|
printf("[%c|", roleChar);
|
||||||
|
} else {
|
||||||
|
printf("%c|", roleChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void placing_ally_ships(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
puts("==== Allied preparation phase =====\nPlease enter the positions for your ships, sir.\n");
|
||||||
|
|
||||||
|
for (size_t i=0; i<BOATS; i++)
|
||||||
|
{
|
||||||
|
int posX = 0, posY = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
printf("Ship %d\n------\n", (int)i);
|
||||||
|
puts("X coord: ");
|
||||||
|
char input_buffer[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer, BUFFER_SIZE);
|
||||||
|
posY = atoi(input_buffer);
|
||||||
|
|
||||||
|
puts("\nY coord: ");
|
||||||
|
char input_buffer2[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer2, BUFFER_SIZE);
|
||||||
|
posX = atoi(input_buffer2);
|
||||||
|
|
||||||
|
puts("\n");
|
||||||
|
if (posX < 0 || posX >= SIZE || posY < 0 || posY >= SIZE)
|
||||||
|
{
|
||||||
|
printf("Invalid position x=%d y=%d, please retry.\n", posX, posY);
|
||||||
|
}
|
||||||
|
if (grid[posX][posY]->role == 1)
|
||||||
|
{
|
||||||
|
printf("A ship is already in x=%d y=%d, please retry.\n", posX, posY);
|
||||||
|
}
|
||||||
|
} while (posX < 0 || posX >= SIZE || posY < 0 || posY >= SIZE || grid[posX][posY]->role == 1);
|
||||||
|
|
||||||
|
grid[posX][posY]->role = 1;
|
||||||
|
grid[posX][posY]->state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void placing_enemy_ships(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<BOATS; i++)
|
||||||
|
{
|
||||||
|
int posX = 0, posY = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
posX = rand() % SIZE;
|
||||||
|
posY = rand() % SIZE;
|
||||||
|
} while (grid[posX][posY]->role != 0);
|
||||||
|
|
||||||
|
grid[posX][posY]->role = 1;
|
||||||
|
grid[posX][posY]->state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_enemy_battlefield(grid_t* grid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
puts("\n*** Enemy grid ***\n");
|
||||||
|
puts(" 0 1 2 3 4 5\n");
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
printf("%d ", (int)i);
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
char roleChar = 0;
|
||||||
|
switch(grid[i][j]->state)
|
||||||
|
{
|
||||||
|
case -2:
|
||||||
|
case 0:
|
||||||
|
roleChar = 32;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
roleChar = 120;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
roleChar = 88;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Error: bad value in battlefield at x=%d y=%d\n", grid[i][j]->x, grid[i][j]->y);
|
||||||
|
shell_install();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j == SIZE-1)
|
||||||
|
{
|
||||||
|
printf("%c]", roleChar);
|
||||||
|
} else if (j == 0) {
|
||||||
|
printf("[%c|", roleChar);
|
||||||
|
} else {
|
||||||
|
printf("%c|", roleChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_remaining_boats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int allyShips = 0;
|
||||||
|
int enemyShips = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
if (allyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
allyShips++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
enemyShips++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%d ally ships and %d enemy ships remaining.\n", allyShips, enemyShips);
|
||||||
|
allyShips >= enemyShips ? colorputs("The allies are in a good posture.\n", yellow, black) : colorputs("The allies are losing terrain...\n", salmon, black);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_game_stats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
colorputs("\n\n\nShowing known information:\n\n", cyan, black);
|
||||||
|
show_ally_battlefield(allyGrid);
|
||||||
|
show_enemy_battlefield(enemyGrid);
|
||||||
|
show_remaining_boats(allyGrid, enemyGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_attack(grid_t* grid[SIZE][SIZE], int x, int y)
|
||||||
|
{
|
||||||
|
switch(grid[x][y]->state)
|
||||||
|
{
|
||||||
|
case -2: // Untouched ocean
|
||||||
|
colorputs("The torpedo explodes in water. Missed.\n", orange, black);
|
||||||
|
grid[x][y]->state = -1;
|
||||||
|
delay(30);
|
||||||
|
break;
|
||||||
|
case -1: // Already hit ocean
|
||||||
|
colorputs("We already striked here, sir... Too late.\n", orange, black);
|
||||||
|
break;
|
||||||
|
case 0: // Ship
|
||||||
|
colorputs("Hit! Well done!\n", green, black);
|
||||||
|
grid[x][y]->state = 1;
|
||||||
|
delay(30);
|
||||||
|
break;
|
||||||
|
case 1: // Already hit ship
|
||||||
|
colorputs("Sir, we already sunk that ship... (looser)\n", orange, black);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ally_do_attack(grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int x = 0, y = 0;
|
||||||
|
colorputs("\n* Ally attack preparation *\n", blue, black);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// yes, x and y are inverted.
|
||||||
|
puts("X coord: ");
|
||||||
|
char input_buffer[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer, BUFFER_SIZE);
|
||||||
|
y = atoi(input_buffer);
|
||||||
|
|
||||||
|
puts("\nY coord: ");
|
||||||
|
char input_buffer2[BUFFER_SIZE];
|
||||||
|
get_input(input_buffer2, BUFFER_SIZE);
|
||||||
|
x = atoi(input_buffer2);
|
||||||
|
|
||||||
|
puts("\n");
|
||||||
|
|
||||||
|
if (x < 0 || x >= SIZE || y < 0 || y >= SIZE)
|
||||||
|
{
|
||||||
|
puts("Sir, this zone is not in our operation area! Please retry.\n");
|
||||||
|
}
|
||||||
|
} while (x < 0 || x >= SIZE || y < 0 || y >= SIZE);
|
||||||
|
|
||||||
|
do_attack(enemyGrid, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enemy_do_attack(grid_t* allyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int x = 0, y = 0;
|
||||||
|
colorputs("\n* Enemies are preparing for attack, everyone take shelter! *\n", blue, black);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
x = rand() % SIZE;
|
||||||
|
y = rand() % SIZE;
|
||||||
|
} while (allyGrid[x][y]->state == -1 || allyGrid[x][y]->state == 1);
|
||||||
|
|
||||||
|
delay((rand()%MAX_WAIT_TIME)+10);
|
||||||
|
do_attack(allyGrid, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_victory(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE])
|
||||||
|
{
|
||||||
|
int allyShips = 0;
|
||||||
|
int enemyShips = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<SIZE; i++)
|
||||||
|
{
|
||||||
|
for (size_t j=0; j<SIZE; j++)
|
||||||
|
{
|
||||||
|
if (allyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
allyShips++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemyGrid[i][j]->state == 0)
|
||||||
|
{
|
||||||
|
enemyShips++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allyShips > 0 && enemyShips == 0)
|
||||||
|
{
|
||||||
|
colorputs("The allies have won! Congratulations, chief!\n", green, black);
|
||||||
|
return 1;
|
||||||
|
} else if (enemyShips > 0 && allyShips == 0)
|
||||||
|
{
|
||||||
|
colorputs("The ennemies have won.. We must retreat.\n", red, black);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
37
src/utils/navalbattle.h
Normal file
37
src/utils/navalbattle.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Simplified naval battle game header
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#ifndef NAVALBATTLE_H
|
||||||
|
#define NAVALBATTLE_H
|
||||||
|
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int role;
|
||||||
|
int state;
|
||||||
|
} grid_t;
|
||||||
|
|
||||||
|
#define SIZE 6
|
||||||
|
#define BOATS 5
|
||||||
|
#define MAX_WAIT_TIME 20
|
||||||
|
#define BUFFER_SIZE 16
|
||||||
|
|
||||||
|
void init_battlefield(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void free_grid(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void show_ally_battlefield(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void placing_ally_ships(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void placing_enemy_ships(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void show_enemy_battlefield(grid_t* grid[SIZE][SIZE]);
|
||||||
|
void show_remaining_boats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
void show_game_stats(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
void do_attack(grid_t* grid[SIZE][SIZE], int x, int y);
|
||||||
|
void ally_do_attack(grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
void enemy_do_attack(grid_t* allyGrid[SIZE][SIZE]);
|
||||||
|
int check_victory(grid_t* allyGrid[SIZE][SIZE], grid_t* enemyGrid[SIZE][SIZE]);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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
200
src/utils/snake.c
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
// Snake game
|
||||||
|
// Author: xamidev
|
||||||
|
// Licensed under the Unlicense. See the repo below.
|
||||||
|
// https://github.com/xamidev/blankos
|
||||||
|
|
||||||
|
#include "../kernel/system.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
#include "../drivers/framebuffer.h"
|
||||||
|
#include "../drivers/kb.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "../libc/crypto.h"
|
||||||
|
|
||||||
|
#define WIDTH 25
|
||||||
|
#define HEIGHT 25
|
||||||
|
#define PIXEL_SIZE 20
|
||||||
|
#define MAX_SNAKE_LENGTH 256
|
||||||
|
// to add:
|
||||||
|
// sound
|
||||||
|
// optimization (shit)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} SnakeSegment;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SnakeSegment segments[MAX_SNAKE_LENGTH];
|
||||||
|
int length;
|
||||||
|
int dx;
|
||||||
|
int dy;
|
||||||
|
} Snake;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} Food;
|
||||||
|
|
||||||
|
Snake snake;
|
||||||
|
Food food;
|
||||||
|
int score = 0;
|
||||||
|
bool onSnake;
|
||||||
|
|
||||||
|
int is_snake(int x, int y);
|
||||||
|
|
||||||
|
void init_game()
|
||||||
|
{
|
||||||
|
snake.length = 1;
|
||||||
|
snake.segments[0].x = WIDTH/2;
|
||||||
|
snake.segments[0].y = HEIGHT/2;
|
||||||
|
snake.dx = 1;
|
||||||
|
snake.dy = 0;
|
||||||
|
|
||||||
|
food.x = rand() % (WIDTH-1);
|
||||||
|
food.y = rand() % (HEIGHT-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_board()
|
||||||
|
{
|
||||||
|
for (int y=0; y<=HEIGHT; y++)
|
||||||
|
{
|
||||||
|
for (int x=0; x<=WIDTH; x++)
|
||||||
|
{
|
||||||
|
if (x == 0 || x == WIDTH || y == 0 || y == HEIGHT)
|
||||||
|
{
|
||||||
|
draw_square(x, y, white, PIXEL_SIZE);
|
||||||
|
}
|
||||||
|
else if (is_snake(x, y)) {
|
||||||
|
draw_square(x, y, green, PIXEL_SIZE);
|
||||||
|
} else if(x == food.x && y == food.y) {
|
||||||
|
draw_square(x, y, red, PIXEL_SIZE);
|
||||||
|
} else {
|
||||||
|
draw_square(x, y, black, PIXEL_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
move_cursor(WIDTH+42, 2);
|
||||||
|
colorputs("Snake Game!", black, green);
|
||||||
|
move_cursor(WIDTH+42, 4);
|
||||||
|
colorprintf(yellow, black, "Score: %d", score);
|
||||||
|
move_cursor(WIDTH+42, 5);
|
||||||
|
puts("Use WASD keys to move");
|
||||||
|
move_cursor(WIDTH+42, 6);
|
||||||
|
puts("Press Q to quit");
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_snake(int x, int y)
|
||||||
|
{
|
||||||
|
for (int i=0; i<snake.length; i++)
|
||||||
|
{
|
||||||
|
if (snake.segments[i].x == x && snake.segments[i].y == y)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_snake()
|
||||||
|
{
|
||||||
|
for (int i=snake.length-1; i>0; i--)
|
||||||
|
{
|
||||||
|
snake.segments[i] = snake.segments[i-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
snake.segments[0].x += snake.dx;
|
||||||
|
snake.segments[0].y += snake.dy;
|
||||||
|
|
||||||
|
if (snake.segments[0].x < 0) snake.segments[0].x = WIDTH-1;
|
||||||
|
if (snake.segments[0].x >= WIDTH) snake.segments[0].x = 0;
|
||||||
|
if (snake.segments[0].y < 0) snake.segments[0].y = HEIGHT-1;
|
||||||
|
if (snake.segments[0].y >= HEIGHT) snake.segments[0].y = 0;
|
||||||
|
|
||||||
|
if (snake.segments[0].x == food.x && snake.segments[0].y == food.y)
|
||||||
|
{
|
||||||
|
snake.length++;
|
||||||
|
score++;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
onSnake = false;
|
||||||
|
food.x = rand() % (WIDTH-1) + 1;
|
||||||
|
food.y = rand() % (HEIGHT-1) + 1;
|
||||||
|
|
||||||
|
for (int i=0; i<snake.length; i++)
|
||||||
|
{
|
||||||
|
if (snake.segments[i].x == food.x && snake.segments[i].y == food.y)
|
||||||
|
{
|
||||||
|
onSnake = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (onSnake);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=1; i<snake.length; i++)
|
||||||
|
{
|
||||||
|
if (snake.segments[0].x == snake.segments[i].x && snake.segments[0].y == snake.segments[i].y)
|
||||||
|
{
|
||||||
|
|
||||||
|
move_cursor(WIDTH+42, 8);
|
||||||
|
colorputs("Game Over!\n", white, red);
|
||||||
|
move_cursor(0, HEIGHT+10);
|
||||||
|
shell_install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_input(char key)
|
||||||
|
{
|
||||||
|
if (key == 'w' && snake.dy == 0) {
|
||||||
|
snake.dx = 0;
|
||||||
|
snake.dy = -1;
|
||||||
|
} else if (key == 's' && snake.dy == 0) {
|
||||||
|
snake.dx = 0;
|
||||||
|
snake.dy = 1;
|
||||||
|
} else if (key == 'a' && snake.dx == 0) {
|
||||||
|
snake.dx = -1;
|
||||||
|
snake.dy = 0;
|
||||||
|
} else if (key == 'd' && snake.dx == 0) {
|
||||||
|
snake.dx = 1;
|
||||||
|
snake.dy = 0;
|
||||||
|
} else if (key =='q') {
|
||||||
|
move_cursor(0, HEIGHT+10);
|
||||||
|
shell_install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void program_snake(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int game_speed;
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
game_speed = 4;
|
||||||
|
} else {
|
||||||
|
game_speed = atoi(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear();
|
||||||
|
init_game();
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
char key = keyboard_getchar_non_blocking();
|
||||||
|
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
handle_input(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
move_snake();
|
||||||
|
draw_board();
|
||||||
|
delay(game_speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/utils/uhex.c
Normal file
72
src/utils/uhex.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
// WIP: pushed but not done yet
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
printf("Usage: uhex <file>\nInline commands:\n\tpX - print position X\n\teX - edit position X\n\tq - quit\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BYTES_PER_LINE = 20;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -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();
|
||||||
@@ -14,7 +14,6 @@ void program_sysinfo();
|
|||||||
|
|
||||||
void get_cpuid();
|
void get_cpuid();
|
||||||
void get_meminfo(unsigned int multiboot_info_address); // to be fixed: cannot get full memory map (sysinfo -v)
|
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();
|
||||||
@@ -39,5 +38,14 @@ void program_ls();
|
|||||||
void program_cat();
|
void program_cat();
|
||||||
|
|
||||||
void program_bmp();
|
void program_bmp();
|
||||||
|
void program_lspci();
|
||||||
|
|
||||||
|
// Games
|
||||||
|
void program_navalbattle();
|
||||||
|
void program_conway();
|
||||||
|
void program_snake();
|
||||||
|
|
||||||
|
// Binaries loading and execution
|
||||||
|
void program_exec();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user