10 Commits

Author SHA1 Message Date
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
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
d89a1c4071 Fix: compatibility, kernel stack, + docs 2024-09-14 20:08:30 +02:00
37 changed files with 313 additions and 22 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

@@ -8,6 +8,7 @@
- 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
@@ -41,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`.
@@ -120,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.

View File

@@ -143,3 +143,7 @@ Starts a simplified and buggy snake game. You can choose the speed by setting th
Controls: Controls:
- `q` to quit - `q` to quit
- `wasd` to move - `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).

View File

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

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

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

View File

@@ -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;
@@ -174,3 +187,52 @@ uint32_t tar_get_file_size(uint8_t* initrd, const char* filename)
} }
return -1; 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;
}

View File

@@ -35,5 +35,6 @@ 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); 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

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

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

View File

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

View File

@@ -15,7 +15,7 @@
#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" #include "../libc/crypto.h"
void kmain(multiboot2_info *mb_info) void kmain(multiboot2_info *mb_info)
@@ -78,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", 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);
@@ -118,6 +118,8 @@ void kmain(multiboot2_info *mb_info)
printf("[debug] malloc test ptr1=0x%x, ptr2=0x%x\n", (unsigned int)ptr1, (unsigned int)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");

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

View File

@@ -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"
@@ -146,6 +146,7 @@ void shell_install()
register_command("lspci", program_lspci); register_command("lspci", program_lspci);
register_command("naval", program_navalbattle); register_command("naval", program_navalbattle);
register_command("snake", program_snake); register_command("snake", program_snake);
register_command("exec", program_exec);
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

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

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

@@ -11,6 +11,8 @@
#include "../drivers/rtc.h" #include "../drivers/rtc.h"
#include "../kernel/io.h" #include "../kernel/io.h"
#include "../drivers/pci.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
@@ -74,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\t lspci\t naval\nsnake\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
@@ -133,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()
{ {
@@ -151,3 +153,24 @@ void program_lspci()
{ {
scan_pci_bus(); 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();
}

72
src/utils/uhex.c Normal file
View 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;
}
*/

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();
@@ -45,4 +45,7 @@ void program_navalbattle();
void program_conway(); void program_conway();
void program_snake(); void program_snake();
// Binaries loading and execution
void program_exec();
#endif #endif