Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e17b428bcc | ||
|
|
8ad4efb3d0 | ||
|
|
3612f223b6 | ||
|
|
5ca49cefd0 | ||
|
|
00b131fa72 | ||
|
|
51024e1d06 | ||
|
|
c47e29f9ed | ||
|
|
e5d3b460b3 | ||
|
|
f3b30bbb9a | ||
|
|
3524fdc760 |
@@ -10,14 +10,67 @@ Blank OS runs on a monolithic kernel booted by a 3rd party bootloader; GRUB (who
|
||||
|
||||
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.
|
||||
|
||||
### System calls
|
||||
|
||||
No system calls are available, as the OS runs in kernel-space.
|
||||
|
||||
## Making programs for the OS
|
||||
|
||||
### Programming
|
||||
### Step 1 - Making the program and the entry point
|
||||
|
||||
Basically you can use the kernel C library functions available in `src/libc/` and make programs out of those functions. Then you can set up the shell for your program to be launchable.
|
||||
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`.
|
||||
|
||||
More on that soon.
|
||||
In this file, you will put the functions your program will use. The entry point for the program should be a void function named `program_<PROGRAM_NAME>`. The entry point can either take no arguments, or use the classic argc/argv structure.
|
||||
|
||||
Valid examples for entry points include:
|
||||
|
||||
```
|
||||
void program_myprogram()
|
||||
void program_myprogram(void)
|
||||
void program_myprogram(int argc, char* argv[])
|
||||
```
|
||||
|
||||
Then, code your stuff freely. The entry point function will basically be the "main" function of your program, like in a regular C file. You can make your own header file too, for example `myprogram.h`.
|
||||
Keep in mind that the standard C library is not available here, so you'll have to use functions from the BlankOS C library, which is located in `src/libc`. Also feel free to look at the header files in `src/drivers` and `src/kernel`, there might be interesting functions in there too (managing input/output devices, the timer, etc..)
|
||||
|
||||
### Step 2 - Registering the program
|
||||
|
||||
Now that your program is done, you will need to make it a part of the OS.
|
||||
|
||||
#### General program header file registering
|
||||
|
||||
To make the entry point function reachable from the shell, you first have to include it in the general programs header file located in `src/programs/programs.h`.
|
||||
|
||||
Put the entry point function prototype in that file. A valid example might be:
|
||||
|
||||
```
|
||||
void program_myprogram(int argc, char* argv[]);
|
||||
```
|
||||
|
||||
#### Shell command registering
|
||||
|
||||
Now that your entry point is reachable from the shell source file, you'll have to register it as a command. To do that, locate the section in `src/kernel/shell.c`, in the very beginning of the `shell_install()` function that has a lot of similar lines to the one below:
|
||||
|
||||
```
|
||||
register_command("myprogram", program_myprogram);
|
||||
```
|
||||
|
||||
Add one of these lines for your entry point and the command name you'd like. (like the line above). First argument is the desired command name, and second argument is the entry point for your program.
|
||||
|
||||
Don't make your command name too long, preferably a few characters, like the other ones.
|
||||
|
||||
#### Help utility registering (optional)
|
||||
|
||||
Finally, you can add your command to the list of available commands by adding it to the `printf` call in the `src/programs/misc.c` source file, in the function `program_help()`.
|
||||
|
||||
If possible make sure that the new command name is aligned with the other ones.
|
||||
|
||||
### Step 3 - Compiling and linking
|
||||
|
||||
The linking process should be taken care of by the appropriate Linker script `link.ld` and the Makefile instructions and targets. Nothing should be changed in those files, and your source files should be added automatically.
|
||||
|
||||
### Step 4 - Contributing to the project (optional)
|
||||
|
||||
If you're proud of what you've made, you can clone the repo, make your changes, open a pull request and maybe your program will be added to the main BlankOS repo, and later distributed in the new ISOs!
|
||||
|
||||
### Compiling and linking
|
||||
|
||||
The linking process should be taken care by the appropriate Linker script `link.ld` and the Makefile instructions and targets.
|
||||
|
||||
12
README.md
12
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
# BlankOS
|
||||
|
||||
Rewritten monolithic version of Blank OS for the x86 processor architecture. The OS relies on an old, legacy version of GRUB as the bootloader (eltorito). This *should* be GRUB 2 compatible. Emulation was tested on Bochs and QEMU using Arch Linux 6.9.7-arch1-1, and on real hardware too.
|
||||
Rewritten monolithic, ring 0, lower-half, single-threaded kernel for the x86 processor architecture, using GRUB (eltorito) as bootloader. Emulation was tested on Bochs and QEMU using Arch Linux 6.9.7-arch1-1, and on real hardware too.
|
||||
The long-term goal of this OS is to be capable of running user programs and having its own complete kernel C library so that users can write their own C programs and expand the system!
|
||||
|
||||
## Features
|
||||
@@ -17,6 +17,14 @@ The long-term goal of this OS is to be capable of running user programs and havi
|
||||
- Cool color output!!
|
||||
- Some small working kernel-space programs!!
|
||||
|
||||
### Kernel-space programs
|
||||
|
||||
- A brainfuck interpreter
|
||||
- An arithmetic calculator
|
||||
- ROT13 and Morse cipher programs
|
||||
- Conway's Game of Life
|
||||
- And some more...
|
||||
|
||||
## Usage
|
||||
|
||||
Download the latest BlankOS ISO image from the "Releases" tab, and emulate it directly using the QEMU emulator:
|
||||
@@ -25,7 +33,7 @@ Download the latest BlankOS ISO image from the "Releases" tab, and emulate it di
|
||||
qemu-system-i386 blankOS-i386-0.3.45.iso
|
||||
```
|
||||
|
||||
Alternatively, burn the image on a USB stick and use it on a machine (see section "Real Hardware").
|
||||
Alternatively, burn the image on a USB stick and use it on a machine. (see section "Real Hardware"). *Note that the ISO images provided in the "Releases" tab are already real-hardware capable; no need to do anything except burning the image on a USB stick and running it on your machine.*
|
||||
|
||||
## Building from source
|
||||
|
||||
|
||||
32
USERS.md
32
USERS.md
@@ -40,8 +40,7 @@ Clears the screen by scrolling (screen height) times.
|
||||
|
||||
#### `math`
|
||||
|
||||
**This program is not working!**
|
||||
The lexer and parser should be okay, but I can't figure out the `%f` floating point format specifier in the freestanding printf implementation; it triggers weird exceptions that I don't understand. So no math interpreter for now.
|
||||
A math lexer & parser that can calculate simple arithmetic operations. Adding, subtracting, multiplying, dividing, and factoring are supported. (I plan to get support for trigonometric functions maybe)
|
||||
|
||||
#### `bf`
|
||||
|
||||
@@ -50,3 +49,32 @@ A brainfuck interpreter with every instruction and default tape size (30k cells)
|
||||
#### `uptime`
|
||||
|
||||
Gets system uptime from the timer in ticks. Ticks are incremented at a rate of 18.222Hz (18.222 ticks per second).
|
||||
|
||||
#### `echo`
|
||||
|
||||
The classic echo command, that outputs your input.
|
||||
|
||||
#### `sysinfo`
|
||||
|
||||
Outputs information about the current system (CPU and RAM).
|
||||
|
||||
Options:
|
||||
- `nothing` will show basic info about the CPUid and lower/upper memory.
|
||||
- `-v` will output the CPUID, lower/upper memory, and the memory map.
|
||||
|
||||
#### `conway`
|
||||
|
||||
A classic Game of Life implementation with standard rules and 100 generations.
|
||||
|
||||
Options:
|
||||
- `<nothing>` will spawn a random soup of cells
|
||||
- `-g` will spawn a classic glider
|
||||
- `-l` will spawn a lightweight spaceship
|
||||
|
||||
#### `rot13`
|
||||
|
||||
Encode a string using the rot13 cipher.
|
||||
|
||||
#### `morse`
|
||||
|
||||
Convert a string to its morse equivalent.
|
||||
|
||||
Binary file not shown.
2
makefile
2
makefile
@@ -1,5 +1,5 @@
|
||||
CC = i386-elf-7.5.0-Linux-x86_64/bin/i386-elf-gcc
|
||||
CFLAGS = -Wall -Wextra -Wno-div-by-zero -Wno-builtin-declaration-mismatch -c -I src/
|
||||
CFLAGS = -Wall -Wextra -Wno-builtin-declaration-mismatch -c -I src/
|
||||
LDFLAGS = -T link.ld -melf_i386
|
||||
AS = nasm
|
||||
ASFLAGS = -f elf
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "../kernel/io.h"
|
||||
#include "serial.h"
|
||||
#include "../libc/stdio.h"
|
||||
|
||||
int init_serial()
|
||||
{
|
||||
@@ -61,5 +62,220 @@ void log(const char* str, const int errlevel)
|
||||
break;
|
||||
}
|
||||
serial_puts(str);
|
||||
}
|
||||
|
||||
const char serial_charset[] = "0123456789abcdef";
|
||||
|
||||
int* serial_printf_number(int* argp, int length, bool sign, int radix)
|
||||
{
|
||||
char buffer[32];
|
||||
unsigned long long number;
|
||||
int number_sign = 1;
|
||||
int pos = 0;
|
||||
|
||||
switch(length)
|
||||
{
|
||||
case PRINTF_LENGTH_SHORT_SHORT:
|
||||
case PRINTF_LENGTH_SHORT:
|
||||
case PRINTF_LENGTH_START:
|
||||
if (sign)
|
||||
{
|
||||
int n = *argp;
|
||||
if (n < 0)
|
||||
{
|
||||
n = -n;
|
||||
number_sign = -1;
|
||||
}
|
||||
number = (unsigned long long) n;
|
||||
}
|
||||
else {
|
||||
number = *(unsigned int*) argp;
|
||||
}
|
||||
argp++;
|
||||
break;
|
||||
case PRINTF_LENGTH_LONG:
|
||||
if (sign)
|
||||
{
|
||||
long int n = *(long int*)argp;
|
||||
if (n < 0)
|
||||
{
|
||||
n = -n;
|
||||
number_sign = -1;
|
||||
}
|
||||
number = (unsigned long long) n;
|
||||
}
|
||||
else {
|
||||
number = *(unsigned long int*) argp;
|
||||
}
|
||||
argp += 2;
|
||||
break;
|
||||
case PRINTF_LENGTH_LONG_LONG:
|
||||
if (sign)
|
||||
{
|
||||
long long int n = *(long long int*)argp;
|
||||
if (n < 0)
|
||||
{
|
||||
n = -n;
|
||||
number_sign = -1;
|
||||
}
|
||||
number = (unsigned long long) n;
|
||||
}
|
||||
else {
|
||||
number = *(unsigned long long int*) argp;
|
||||
}
|
||||
argp += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
uint32_t rem;
|
||||
x86_div64_32(number, radix, &number, &rem);
|
||||
buffer[pos++] = serial_charset[rem];
|
||||
} while (number > 0);
|
||||
|
||||
if (sign && number_sign < 0)
|
||||
{
|
||||
buffer[pos++] = '-';
|
||||
}
|
||||
|
||||
while (--pos >= 0)
|
||||
{
|
||||
write_serial(buffer[pos]);
|
||||
}
|
||||
|
||||
return argp;
|
||||
}
|
||||
void serial_printf(int errlevel, const char* fmt, ...)
|
||||
{
|
||||
switch (errlevel)
|
||||
{
|
||||
case 0:
|
||||
serial_puts("[ERROR] ");
|
||||
break;
|
||||
case 1:
|
||||
serial_puts("[WARNING] ");
|
||||
break;
|
||||
case 2:
|
||||
serial_puts("[INFO] ");
|
||||
break;
|
||||
case 3:
|
||||
serial_puts("[DEBUG] ");
|
||||
break;
|
||||
}
|
||||
|
||||
int* argp = (int*) &fmt;
|
||||
int state = PRINTF_STATE_START;
|
||||
int length = PRINTF_LENGTH_START;
|
||||
int radix = 10;
|
||||
bool sign = false;
|
||||
|
||||
argp++;
|
||||
while (*fmt)
|
||||
{
|
||||
switch(state) {
|
||||
case PRINTF_STATE_START:
|
||||
if (*fmt == '%')
|
||||
{
|
||||
state = PRINTF_STATE_LENGTH;
|
||||
}
|
||||
else {
|
||||
write_serial(*fmt);
|
||||
}
|
||||
break;
|
||||
case PRINTF_STATE_LENGTH:
|
||||
if (*fmt == 'h')
|
||||
{
|
||||
length = PRINTF_LENGTH_SHORT;
|
||||
state = PRINTF_STATE_SHORT;
|
||||
}
|
||||
else if (*fmt == 'l')
|
||||
{
|
||||
length = PRINTF_LENGTH_LONG;
|
||||
state = PRINTF_STATE_LONG;
|
||||
}
|
||||
else {
|
||||
goto PRINTF_STATE_SPEC_;
|
||||
}
|
||||
break;
|
||||
case PRINTF_STATE_SHORT:
|
||||
if (*fmt == 'h')
|
||||
{
|
||||
length = PRINTF_LENGTH_SHORT_SHORT;
|
||||
state = PRINTF_STATE_SPEC;
|
||||
}
|
||||
else {
|
||||
goto PRINTF_STATE_SPEC_;
|
||||
}
|
||||
break;
|
||||
case PRINTF_STATE_LONG:
|
||||
if (*fmt == 'l')
|
||||
{
|
||||
length = PRINTF_LENGTH_LONG_LONG;
|
||||
state = PRINTF_STATE_SPEC;
|
||||
}
|
||||
else {
|
||||
goto PRINTF_STATE_SPEC_;
|
||||
}
|
||||
break;
|
||||
case PRINTF_STATE_SPEC:
|
||||
PRINTF_STATE_SPEC_:
|
||||
switch(*fmt)
|
||||
{
|
||||
case 'c':
|
||||
serial_puts(*(const char **)argp);
|
||||
argp++;
|
||||
break;
|
||||
case 's':
|
||||
serial_puts(*(const char **)argp);
|
||||
argp++;
|
||||
break;
|
||||
case '%':
|
||||
putc('%');
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
radix = 10;
|
||||
sign = true;
|
||||
argp = serial_printf_number(argp, length, sign, radix);
|
||||
break;
|
||||
case 'u':
|
||||
radix = 10;
|
||||
sign = false;
|
||||
argp = serial_printf_number(argp, length, sign, radix);
|
||||
break;
|
||||
case 'X':
|
||||
case 'x':
|
||||
case 'p':
|
||||
radix = 16;
|
||||
sign = false;
|
||||
argp = serial_printf_number(argp, length, sign, radix);
|
||||
break;
|
||||
case 'o':
|
||||
radix = 8;
|
||||
sign = false;
|
||||
argp = serial_printf_number(argp, length, sign, radix);
|
||||
break;
|
||||
case 'f': {
|
||||
// Handle floating-point numbers
|
||||
double* dargp = (double*)argp;
|
||||
double d = *(double*)dargp;
|
||||
char buffer[64];
|
||||
dtostrf(d, buffer, 6); // Default precision: 6
|
||||
serial_puts(buffer);
|
||||
argp += 2; // Incrementing by 2 to move past the double argument
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = PRINTF_STATE_START;
|
||||
length = PRINTF_LENGTH_START;
|
||||
radix = 10;
|
||||
sign = false;
|
||||
break;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
serial_puts("\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ int is_transmit_empty();
|
||||
void write_serial(const char a);
|
||||
void serial_puts(const char* str);
|
||||
void log(const char* str, const int errlevel);
|
||||
|
||||
void serial_printf(int errlevel, const char* fmt, ...);
|
||||
#endif
|
||||
|
||||
@@ -12,35 +12,34 @@ char* ascii_title =
|
||||
" 888oooo88 888 ooooo888 888 888 888o888 888 888 888oooooo \n"
|
||||
" 888 888 888 888 888 888 888 8888 88o 888o o888 888\n"
|
||||
" o888ooo888 o888o 88ooo88 8o o888o o888o o888o o888o 88ooo88 o88oooo888\n\n"
|
||||
" --------------------------------- v0.3.45 --------------------------------\n\n";
|
||||
" --------------------------------- v0.3.55 --------------------------------\n\n";
|
||||
|
||||
int kmain(int retvalue)
|
||||
unsigned int g_multiboot_info_address;
|
||||
|
||||
void kmain(unsigned int multiboot_info_address)
|
||||
{
|
||||
g_multiboot_info_address = multiboot_info_address;
|
||||
|
||||
init_serial();
|
||||
log("serial connection established", 3);
|
||||
log("serial connection established\n", 3);
|
||||
gdt_install();
|
||||
log("initialized GDT entries", 2);
|
||||
log("initialized GDT entries\n", 2);
|
||||
idt_install();
|
||||
log("initialized IDT", 2);
|
||||
log("initialized IDT\n", 2);
|
||||
isr_install();
|
||||
log("initialized ISRs", 2);
|
||||
log("initialized ISRs\n", 2);
|
||||
irq_install();
|
||||
__asm__ __volatile__("sti");
|
||||
log("initialized IRQs", 2),
|
||||
|
||||
log("kernel started", 2);
|
||||
log("initialized IRQs\n", 2),
|
||||
|
||||
clear();
|
||||
|
||||
colorputs(ascii_title, 10);
|
||||
colorputs(" by @xamidev - star the repo for a cookie!\n\n", 14);
|
||||
|
||||
// TODO: Grub modules to load programs
|
||||
|
||||
timer_install();
|
||||
serial_printf(2, "%d\tinitialized timer handler", global_ticks);
|
||||
keyboard_install();
|
||||
serial_printf(2, "%d\tinitialized keyboard handler", global_ticks);
|
||||
shell_install();
|
||||
|
||||
return retvalue;
|
||||
serial_printf(2, "%d\tstarted system shell", global_ticks);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ extern kmain
|
||||
loader:
|
||||
cli
|
||||
; mov eax, 0xCAFEBABE
|
||||
push dword 42
|
||||
; push dword 42
|
||||
push ebx
|
||||
call kmain
|
||||
|
||||
.loop:
|
||||
|
||||
@@ -2,61 +2,91 @@
|
||||
#include "../libc/stdio.h"
|
||||
#include "../libc/string.h"
|
||||
#include "../programs/programs.h"
|
||||
#include "../libc/stdint.h"
|
||||
|
||||
#define BUFFER_SIZE 256
|
||||
#define MAX_COMMANDS 16
|
||||
#define MAX_ARGS 64
|
||||
|
||||
typedef void (*command_func_t)(int argc, char *argv[]);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
command_func_t function;
|
||||
} shell_command_t;
|
||||
|
||||
shell_command_t shell_commands[MAX_COMMANDS];
|
||||
int command_count = 0;
|
||||
|
||||
void register_command(const char* name, command_func_t function)
|
||||
{
|
||||
if (command_count < MAX_COMMANDS)
|
||||
{
|
||||
shell_commands[command_count].name = name;
|
||||
shell_commands[command_count].function = function;
|
||||
command_count++;
|
||||
}
|
||||
}
|
||||
|
||||
command_func_t find_command(const char* name)
|
||||
{
|
||||
for (int i=0; i < command_count; i++)
|
||||
{
|
||||
if (strcmp(name, shell_commands[i].name) == 0)
|
||||
return shell_commands[i].function;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_input(char* input, char* argv[], int max_args)
|
||||
{
|
||||
int argc = 0;
|
||||
char* token = strtok(input, " ");
|
||||
while (token != NULL && argc < max_args - 1)
|
||||
{
|
||||
argv[argc++] = token;
|
||||
token = strtok(NULL, " ");
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
return argc;
|
||||
}
|
||||
|
||||
void shell_install()
|
||||
{
|
||||
while (1) // Bad!!
|
||||
register_command("help", program_help);
|
||||
register_command("panic", program_panic);
|
||||
register_command("words", program_words);
|
||||
register_command("primes", program_primes);
|
||||
register_command("rainbow", program_rainbow);
|
||||
register_command("clear", program_clear);
|
||||
register_command("math", program_math);
|
||||
register_command("bf", program_bf);
|
||||
register_command("uptime", program_uptime);
|
||||
register_command("echo", program_echo);
|
||||
register_command("sysinfo", program_sysinfo);
|
||||
register_command("conway", program_conway);
|
||||
register_command("rot13", program_rot13);
|
||||
register_command("morse", program_morse);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char input_buffer[BUFFER_SIZE];
|
||||
char* argv[MAX_ARGS];
|
||||
colorputs("blankos> ", 9);
|
||||
get_input(input_buffer, BUFFER_SIZE);
|
||||
puts("\n");
|
||||
|
||||
// Childish shell
|
||||
if (strcmp(input_buffer, "") == 0)
|
||||
int argc = parse_input(input_buffer, argv, MAX_ARGS);
|
||||
|
||||
if (argc == 0) continue;
|
||||
|
||||
command_func_t command = find_command(argv[0]);
|
||||
if (command)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (strcmp(input_buffer, "help") == 0)
|
||||
{
|
||||
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\tuptime\n");
|
||||
}
|
||||
else if (strcmp(input_buffer, "panic") == 0)
|
||||
{
|
||||
printf("%d", 4/0);
|
||||
}
|
||||
else if (strcmp(input_buffer, "words") == 0)
|
||||
{
|
||||
program_words();
|
||||
}
|
||||
else if (strcmp(input_buffer, "primes") == 0)
|
||||
{
|
||||
program_primes();
|
||||
}
|
||||
else if (strcmp(input_buffer, "rainbow") == 0)
|
||||
{
|
||||
program_rainbow();
|
||||
}
|
||||
else if (strcmp(input_buffer, "clear") == 0)
|
||||
{
|
||||
program_clear();
|
||||
}
|
||||
else if (strcmp(input_buffer, "math") == 0)
|
||||
{
|
||||
program_math();
|
||||
}
|
||||
else if (strcmp(input_buffer, "bf") == 0)
|
||||
{
|
||||
program_bf();
|
||||
}
|
||||
else if (strcmp(input_buffer, "uptime") == 0)
|
||||
{
|
||||
program_uptime();
|
||||
}
|
||||
else {
|
||||
printf("Unknown command %s\n", input_buffer);
|
||||
command(argc, argv);
|
||||
} else {
|
||||
printf("Unknown command %s\n", argv[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
src/kernel/sysinfo.c
Normal file
11
src/kernel/sysinfo.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "../libc/stdio.h"
|
||||
#include "../libc/string.h"
|
||||
|
||||
void cpuid(int code, unsigned int* a, unsigned int* d)
|
||||
{
|
||||
asm volatile("cpuid"
|
||||
: "=a"(*a), "=d"(*d)
|
||||
: "a"(code)
|
||||
: "ecx", "ebx");
|
||||
}
|
||||
|
||||
6
src/kernel/sysinfo.h
Normal file
6
src/kernel/sysinfo.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef SYSINFO_H
|
||||
#define SYSINFO_H
|
||||
|
||||
void cpuid(int code, unsigned int* a, unsigned int* d);
|
||||
|
||||
#endif
|
||||
@@ -26,5 +26,7 @@ int uptime();
|
||||
|
||||
extern volatile unsigned long global_ticks;
|
||||
|
||||
extern unsigned int g_multiboot_info_address;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "crypto.h"
|
||||
#include "../libc/stdint.h"
|
||||
|
||||
int lcg(int seed)
|
||||
{
|
||||
@@ -22,3 +23,21 @@ int randint(int seed)
|
||||
int x = lcg(seed);
|
||||
return x;
|
||||
}
|
||||
|
||||
static uint32_t next = 1;
|
||||
|
||||
uint32_t rand()
|
||||
{
|
||||
next = next * 1103515245 + 12345;
|
||||
return (next/65536) % 32768;
|
||||
}
|
||||
|
||||
float rand_float()
|
||||
{
|
||||
return rand() / 32767.0f;
|
||||
}
|
||||
|
||||
void srand(uint32_t seed)
|
||||
{
|
||||
next = seed;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
|
||||
#define RAND_MAX 1024
|
||||
|
||||
#include "../libc/stdint.h"
|
||||
|
||||
int lcg(int seed);
|
||||
int randint(int seed);
|
||||
uint32_t rand();
|
||||
float rand_float();
|
||||
void srand(uint32_t seed);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,4 +17,6 @@ typedef uint8_t bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,4 +40,6 @@ int* printf_number(int* argp, int length, bool sign, int radix);
|
||||
int getch();
|
||||
void get_input(char *buffer, int size);
|
||||
|
||||
void dtostrf(double val, char *buffer, int precision);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
int strlen(char* str)
|
||||
#include "stdint.h"
|
||||
|
||||
int strlen(const char* str)
|
||||
{
|
||||
int len = 0;
|
||||
while (*str++)
|
||||
@@ -8,7 +10,7 @@ int strlen(char* str)
|
||||
return len;
|
||||
}
|
||||
|
||||
int strcmp(char* str1, char* str2)
|
||||
int strcmp(const char* str1, const char* str2)
|
||||
{
|
||||
while (*str1 && (*str1 == *str2))
|
||||
{
|
||||
@@ -17,3 +19,52 @@ int strcmp(char* str1, char* str2)
|
||||
}
|
||||
return *(const unsigned char*)str1 - *(const unsigned char*)str2;
|
||||
}
|
||||
|
||||
char* strchr(const char* str, int c)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
if (*str == (char)c)
|
||||
{
|
||||
return (char*)str;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
if (c == '\0')
|
||||
{
|
||||
return (char*)str;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* strtok(char* str, const char* delimiter)
|
||||
{
|
||||
static char* last;
|
||||
if (str)
|
||||
{
|
||||
last = str;
|
||||
} else {
|
||||
str = last;
|
||||
}
|
||||
|
||||
if (!str || *str == '\0')
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* token_start = str;
|
||||
while (*str && !strchr(delimiter, *str))
|
||||
{
|
||||
str++;
|
||||
}
|
||||
|
||||
if (*str)
|
||||
{
|
||||
*str = '\0';
|
||||
last = str + 1;
|
||||
} else {
|
||||
last = NULL;
|
||||
}
|
||||
|
||||
return token_start;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef INCLUDE_STRING_H
|
||||
#define INCLUDE_STRING_H
|
||||
|
||||
int strlen(char* str);
|
||||
int strcmp(char* str1, char* str2);
|
||||
int strlen(const char* str);
|
||||
int strcmp(const char* str1, const char* str2);
|
||||
char* strtok(char* str, const char* delimiter);
|
||||
|
||||
#endif
|
||||
|
||||
128
src/programs/ciphers.c
Normal file
128
src/programs/ciphers.c
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "../libc/stdio.h"
|
||||
#include "ciphers.h"
|
||||
|
||||
void rot13(char* input, char* output)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (input[i] != '\0')
|
||||
{
|
||||
char c = input[i];
|
||||
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
output[i] = ((c - 'a' + 13) % 26) + 'a';
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
output[i] = ((c - 'A' + 13) % 26) + 'A';
|
||||
} else {
|
||||
output[i] = c;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
output[i] = '\0';
|
||||
}
|
||||
|
||||
void program_rot13()
|
||||
{
|
||||
char input_buffer[BUFFER_SIZE];
|
||||
char output[BUFFER_SIZE];
|
||||
puts("String? ");
|
||||
get_input(input_buffer, BUFFER_SIZE);
|
||||
rot13(input_buffer, output);
|
||||
printf("\n%s\n", output);
|
||||
}
|
||||
|
||||
#include "../libc/string.h"
|
||||
#include "../libc/stdint.h"
|
||||
|
||||
const char* morse_alphabet[] = {
|
||||
".-", // A
|
||||
"-...", // B
|
||||
"-.-.", // C
|
||||
"-..", // D
|
||||
".", // E
|
||||
"..-.", // F
|
||||
"--.", // G
|
||||
"....", // H
|
||||
"..", // I
|
||||
".---", // J
|
||||
"-.-", // K
|
||||
".-..", // L
|
||||
"--", // M
|
||||
"-.", // N
|
||||
"---", // O
|
||||
".--.", // P
|
||||
"--.-", // Q
|
||||
".-.", // R
|
||||
"...", // S
|
||||
"-", // T
|
||||
"..-", // U
|
||||
"...-", // V
|
||||
".--", // W
|
||||
"-..-", // X
|
||||
"-.--", // Y
|
||||
"--.." // Z
|
||||
};
|
||||
|
||||
const char* morse_digits[] = {
|
||||
"-----", // 0
|
||||
".----", // 1
|
||||
"..---", // 2
|
||||
"...--", // 3
|
||||
"....-", // 4
|
||||
".....", // 5
|
||||
"-....", // 6
|
||||
"--...", // 7
|
||||
"---..", // 8
|
||||
"----." // 9
|
||||
};
|
||||
|
||||
void to_morse(const char* input, char* output) {
|
||||
int i = 0;
|
||||
int pos = 0;
|
||||
|
||||
while (input[i] != '\0') {
|
||||
char c = input[i];
|
||||
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
const char* morse_code = morse_alphabet[c - 'a'];
|
||||
int j = 0;
|
||||
while (morse_code[j] != '\0') {
|
||||
output[pos++] = morse_code[j++];
|
||||
}
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
const char* morse_code = morse_alphabet[c - 'A'];
|
||||
int j = 0;
|
||||
while (morse_code[j] != '\0') {
|
||||
output[pos++] = morse_code[j++];
|
||||
}
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
const char* morse_code = morse_digits[c - '0'];
|
||||
int j = 0;
|
||||
while (morse_code[j] != '\0') {
|
||||
output[pos++] = morse_code[j++];
|
||||
}
|
||||
} else if (c == ' ') {
|
||||
output[pos++] = ' ';
|
||||
}
|
||||
|
||||
output[pos++] = ' ';
|
||||
i++;
|
||||
}
|
||||
|
||||
if (pos > 0) {
|
||||
output[pos - 1] = '\0';
|
||||
} else {
|
||||
output[pos] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void program_morse() {
|
||||
char output[512];
|
||||
char input_buffer[BUFFER_SIZE];
|
||||
puts("String? ");
|
||||
get_input(input_buffer, BUFFER_SIZE);
|
||||
to_morse(input_buffer, output);
|
||||
printf("\n%s\n", output);
|
||||
}
|
||||
|
||||
6
src/programs/ciphers.h
Normal file
6
src/programs/ciphers.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef CIPHERS_H
|
||||
#define CIPHERS_H
|
||||
|
||||
#define BUFFER_SIZE 256
|
||||
|
||||
#endif
|
||||
132
src/programs/conway.c
Normal file
132
src/programs/conway.c
Normal file
@@ -0,0 +1,132 @@
|
||||
#include "conway.h"
|
||||
#include "../libc/stdio.h"
|
||||
#include "../kernel/system.h"
|
||||
#include "../libc/crypto.h"
|
||||
#include "../libc/stdint.h"
|
||||
#include "../drivers/serial.h"
|
||||
#include "../libc/string.h"
|
||||
|
||||
void print_grid(const unsigned char grid[X][Y])
|
||||
{
|
||||
for (int i=0; i<X; i++)
|
||||
{
|
||||
for (int j=0; j<Y; j++)
|
||||
{
|
||||
//(grid[i][j] == LIVE) ? putc(42) : putc(32);
|
||||
if (grid[i][j] == LIVE) {
|
||||
serial_printf(3, "alive");
|
||||
colorputc(32, 120);
|
||||
} else {
|
||||
putc(32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count_live_neighbors(const unsigned char grid[X][Y], int i, int j)
|
||||
{
|
||||
int live_neighbors = 0;
|
||||
|
||||
for (int x=-1; x<=1; x++)
|
||||
{
|
||||
for (int y=-1; y<=1; y++)
|
||||
{
|
||||
if (x==0 && y==0) continue;
|
||||
|
||||
int ni = i+x;
|
||||
int nj = j+y;
|
||||
|
||||
if (ni >= 0 && ni < X && nj >= 0)
|
||||
{
|
||||
if (grid[ni][nj] == LIVE) live_neighbors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return live_neighbors;
|
||||
}
|
||||
|
||||
void grid_new_generation(unsigned char grid[X][Y], unsigned char temp[X][Y])
|
||||
{
|
||||
for (int i=0; i<X; i++)
|
||||
{
|
||||
for (int j=0; j<Y; j++)
|
||||
{
|
||||
int cell = grid[i][j];
|
||||
int live_neighbors = count_live_neighbors(grid, i, j);
|
||||
|
||||
if (cell == LIVE)
|
||||
{
|
||||
switch(live_neighbors)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
temp[i][j] = LIVE;
|
||||
break;
|
||||
default:
|
||||
temp[i][j] = DEAD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (cell == DEAD && live_neighbors == 3)
|
||||
{
|
||||
temp[i][j] = LIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<X; i++)
|
||||
{
|
||||
for (int j=0; j<Y; j++)
|
||||
{
|
||||
grid[i][j] = temp[i][j];
|
||||
temp[i][j] = DEAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void soup(unsigned char grid[X][Y])
|
||||
{
|
||||
srand(global_ticks);
|
||||
for (int i=0; i<X; i++)
|
||||
{
|
||||
for (int j=0; j<Y; j++)
|
||||
{
|
||||
grid[i][j] = rand_float() > SOUP_PROB ? LIVE : DEAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void program_conway(int argc, char* argv[])
|
||||
{
|
||||
clear();
|
||||
unsigned char grid[X][Y] = {0};
|
||||
unsigned char temp[X][Y] = {0};
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
soup(grid);
|
||||
} else if (argc == 2 && strcmp(argv[1], "-g") == 0) {
|
||||
grid[1][2] = LIVE;
|
||||
grid[2][3] = LIVE;
|
||||
grid[3][1] = LIVE;
|
||||
grid[3][2] = LIVE;
|
||||
grid[3][3] = LIVE;
|
||||
} else if (argc == 2 && strcmp(argv[1], "-l") == 0) {
|
||||
grid[10][3] = LIVE; grid[10][4] = LIVE; grid[10][5] = LIVE; grid[10][6] = LIVE;
|
||||
grid[11][2] = LIVE; grid[11][6] = LIVE;
|
||||
grid[12][6] = LIVE;
|
||||
grid[13][2] = LIVE; grid[13][5] = LIVE;
|
||||
}
|
||||
|
||||
print_grid(grid);
|
||||
puts("generation 0");
|
||||
for (int i=1; i<GENERATIONS; i++)
|
||||
{
|
||||
grid_new_generation(grid, temp);
|
||||
delay(DELAY);
|
||||
clear();
|
||||
print_grid(grid);
|
||||
printf("generation %d", i);
|
||||
}
|
||||
|
||||
}
|
||||
18
src/programs/conway.h
Normal file
18
src/programs/conway.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef CONWAY_H
|
||||
#define CONWAY_H
|
||||
|
||||
#define X 25
|
||||
#define Y 80
|
||||
|
||||
#define GENERATIONS 100
|
||||
#define DEAD 0
|
||||
#define LIVE 1
|
||||
#define SOUP_PROB 0.7
|
||||
#define DELAY 10
|
||||
|
||||
void print_grid(const unsigned char grid[X][Y]);
|
||||
int count_live_neighbors(const unsigned char grid[X][Y], int i, int j);
|
||||
void grid_new_generation(unsigned char grid[X][Y], unsigned char temp[X][Y]);
|
||||
void soup(unsigned char grid[X][Y]);
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "../libc/stdio.h"
|
||||
#include "../kernel/system.h"
|
||||
#include "../libc/string.h"
|
||||
|
||||
// Print a rainbow colorful text for testing
|
||||
|
||||
@@ -39,3 +40,31 @@ void program_uptime()
|
||||
double seconds = ticks/18.2065; // PIC channel 0 freq
|
||||
printf("%d ticks\t%f seconds\n", ticks, seconds);
|
||||
}
|
||||
|
||||
// Get help
|
||||
|
||||
void program_help()
|
||||
{
|
||||
printf("help\tpanic\twords\tprimes\trainbow\tclear\nmath\tbf\t uptime echo\t sysinfo\tconway\nrot13 morse\n");
|
||||
}
|
||||
|
||||
// Panic
|
||||
|
||||
void program_panic()
|
||||
{
|
||||
asm volatile("int $0x13");
|
||||
}
|
||||
|
||||
// Output input
|
||||
|
||||
void program_echo(int argc, char* argv[])
|
||||
{
|
||||
for (int i=1; i<argc; i++)
|
||||
{
|
||||
puts(argv[i]);
|
||||
if (i < argc-1) {
|
||||
putc(' ');
|
||||
}
|
||||
}
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
@@ -5,10 +5,21 @@ void program_words();
|
||||
void program_primes();
|
||||
void program_math();
|
||||
void program_bf();
|
||||
void program_sysinfo();
|
||||
|
||||
void get_cpuid();
|
||||
void get_meminfo(unsigned int multiboot_info_address);
|
||||
void program_conway();
|
||||
|
||||
// Ciphers
|
||||
void program_rot13();
|
||||
void program_morse();
|
||||
|
||||
// Misc
|
||||
void program_rainbow();
|
||||
void program_clear();
|
||||
void program_uptime();
|
||||
|
||||
void program_panic();
|
||||
void program_help();
|
||||
void program_echo();
|
||||
#endif
|
||||
|
||||
78
src/programs/sysinfo.c
Normal file
78
src/programs/sysinfo.c
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
#include "../kernel/sysinfo.h"
|
||||
#include "../libc/stdio.h"
|
||||
#include "../kernel/system.h"
|
||||
#include "../libc/string.h"
|
||||
|
||||
extern unsigned int multiboot_info_address;
|
||||
|
||||
typedef struct multiboot_memory_map
|
||||
{
|
||||
unsigned int size;
|
||||
unsigned int base_addr_low;
|
||||
unsigned int base_addr_high;
|
||||
unsigned int length_low;
|
||||
unsigned int length_high;
|
||||
unsigned int type;
|
||||
} multiboot_memory_map_t;
|
||||
|
||||
void get_cpuid()
|
||||
{
|
||||
// CPUid
|
||||
|
||||
unsigned int eax, edx;
|
||||
char vendor[13];
|
||||
unsigned int* v = (unsigned int*)vendor;
|
||||
|
||||
asm volatile("cpuid"
|
||||
: "=b"(v[0]), "=d"(v[1]), "=c"(v[2])
|
||||
: "a"(0));
|
||||
vendor[12] = '\0';
|
||||
|
||||
cpuid(1, &eax, &edx);
|
||||
unsigned int model = (eax >> 4) & 0xF;
|
||||
unsigned int family = (eax >> 8) & 0xF;
|
||||
|
||||
printf("CPU information\n\tvendor: %s\n\tfamily: %u\n\tmodel: %u\n\tfeatures: 0x%x\n", vendor, family, model, edx);
|
||||
}
|
||||
|
||||
void get_meminfo(unsigned int multiboot_info_address, int verbose)
|
||||
{
|
||||
// RAM
|
||||
|
||||
unsigned int mem_lower = *((unsigned int*)(multiboot_info_address + 4));
|
||||
unsigned int mem_upper = *((unsigned int*)(multiboot_info_address + 8));
|
||||
|
||||
printf("RAM information\n\tLower memory: %u KB\n\tUpper memory: %u KB\n", mem_lower, mem_upper);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
multiboot_memory_map_t* mmap = (multiboot_memory_map_t*)*((unsigned int*)(multiboot_info_address + 44));
|
||||
printf("Memory map:\nBase addr | Length | Type\n----------------------------------------------------\n");
|
||||
|
||||
while ((unsigned int)mmap < multiboot_info_address + *((unsigned int*)(multiboot_info_address + 40)))
|
||||
{
|
||||
if (mmap->length_high != 0 && mmap->length_low != 0)
|
||||
{
|
||||
printf("0x%x%x | 0x%x%x | %u\n",
|
||||
mmap->base_addr_high, mmap->base_addr_low,
|
||||
mmap->length_high, mmap->length_low,
|
||||
mmap->type);
|
||||
}
|
||||
mmap = (multiboot_memory_map_t*)((unsigned int)mmap + mmap->size + sizeof(unsigned int));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void program_sysinfo(int argc, char* argv[])
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
get_cpuid();
|
||||
get_meminfo(g_multiboot_info_address, 0);
|
||||
} else if (argc == 2 && strcmp(argv[1], "-v") == 0)
|
||||
{
|
||||
get_cpuid();
|
||||
get_meminfo(g_multiboot_info_address, 1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user