Files
Espresso/kernel/kshell.c
2026-03-20 16:57:08 -05:00

545 lines
10 KiB
C

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <drivers/ps2_keyboard.h>
#include <tty.h>
#include <kernel/ksh_debug.h>
#include <arch/x86/intrin.h>
#include <drivers/elf.h>
#include <kernel/syscall.h>
#include <scheduler.h>
#include <fs/fat16.h>
#include <kernel/kshell.h>
const char* shell_version = "0.0.2";
char* prompt = NULL;
int command = -1;
bool _debug = true;
int execute(void);
static void print_intro(void)
{
printf("Espresso kshell, ver %s on Espresso %s", shell_version, KERNEL_VERSION);
#ifdef _DEBUG
printf(" DEBUG BUILD");
#endif
printf("\nSSE level: ");
command = 1;
execute();
extern char* get_cpu_vendor_string(void);
extern char* get_cpu_brand_string(void);
/* XXX: NOTE: these do not need freeing. */
char* temp_ = get_cpu_vendor_string();
char* _temp = get_cpu_brand_string();
printf("CPU: %s\n", _temp == NULL ? "No info" : _temp);
printf("CPU vendor: %s\n", temp_ == NULL ? "No info" : temp_);
printf("\nCopyright %s David J Goeke\n", KERNEL_RELEASE_YEAR);
}
static char* commands[] = {
"kinfo",
"sseinfo",
"kernelmem",
"sectionmem",
"enable_debug",
"disable_debug",
"toggle_debug",
"get_debug",
"dumpregs",
"dumpgprs",
"testascii",
"printrandom",
"testfat16",
"printc",
"testscheduler",
"readfat16",
"help",
"exec",
"int16test",
NULL,
};
const int NUM_COMMANDS = 19; /* Yes, including the NULL */
void kshell_start(void)
{
printf("Welcome to the kshell!\n");
prompt = strdup(">");
char* i = NULL;
print_intro();
command = -1;
do
{
printf("%s ", prompt);
/*i = gets();*/
int j = 0;
i = gets_new(&j);
if (j == 0)
{
printf("Error?\n");
break;
}
i = strnlstrip(i);
command = -1;
if (strcmp(i, "") == 0)
{
continue;
}
else if (strcmp(i, "exit") == 0 || strcmp(i, "quit") == 0)
{
break;
}
for (int j = 0; j < NUM_COMMANDS; j++)
{
if (strcmp(i, commands[j]) == 0)
{
command = j;
break;
}
}
if (command == -1)
{
printf("Unknown command %s len %i\n", i, strlen(i));
}
else if (command == 4)
{
_debug = true;
}
else if (command == 5)
{
_debug = false;
}
else if (command == 6)
{
_debug = !_debug;
}
else if (command == 7)
{
printf("Debugging: %s\n", _debug == true ? "On" : "Off");
}
if (_debug)
{
printf(" ASCII -> ");
size_t len = strlen(i) + 1;
for (size_t n = 0; n < len; n++)
{
printf("%02X ", (int) i[n]);
}
printf("\n");
}
printf("C: %s; %i\n", commands[command], command);
execute();
} while (1);
if (i)
{
free(i);
}
printf("Goodbye!\n");
return;
}
/*
static char* commands[] = {
"kinfo",
"sseinfo",
"kernelmem",
"sectionmem",
"enable_debug",
"disable_debug",
"toggle_debug",
"get_debug",
"dumpregs",
"dumpgprs",
"testascii",
"printrandom",
"testfat16",
NULL,
};
*/
int execute(void)
{
switch (command)
{
case 0: {
printf("Espresso %s ", KERNEL_VERSION);
#ifdef _DEBUG
printf("DEBUG BUILD");
#endif
printf("\n");
break;
}
case 1: {
extern int sse_initialized;
switch (sse_initialized)
{
case 0:
printf("No SSE support");
break;
case 1:
printf("SSE1");
break;
case 2:
printf("SSE2");
break;
case 3:
printf("SSE3");
break;
case 4:
printf("SSSE3");
break;
case 5:
printf("SSE4.1");
break;
case 6:
printf("SSE4.2");
break;
default:
printf("WARNING: sse_initialized is in a invalid state!");
break;
}
printf("\n");
break;
}
case 2: {
extern uint8_t __kernel_start;
extern uint8_t __kernel_end;
size_t kernel_size = (size_t)&__kernel_end - (size_t)&__kernel_start;
printf("Kernel start: 0x%x\n", (&__kernel_start));
printf("Kernel end: 0x%x\n", (&__kernel_end));
printf("Kernel size (bytes): %llu\n", (uint64_t) kernel_size);
printf("Kernel size (kbytes): %llu\n", (((uint64_t) kernel_size) / 1000));
printf("Kernel size (mbytes): %f\n", (((uint64_t) kernel_size) / 1000.0) / 1000.0);
break;
}
case 3: {
extern uint8_t __kernel_text_start;
extern uint8_t __kernel_text_end;
extern uint8_t __kernel_rodata_start;
extern uint8_t __kernel_rodata_end;
extern uint8_t __kernel_data_start;
extern uint8_t __kernel_data_end;
extern uint8_t __bss_start;
extern uint8_t __bss_end;
printf(".text: %i\n.data: %i\n.rodata: %i\n.bss: %i\n", ((&__kernel_text_end) - (&__kernel_text_start)), ((&__kernel_data_end) - (&__kernel_data_start)),
((&__kernel_rodata_end) - (&__kernel_rodata_start)), ((&__bss_end) - (&__bss_start)));
break;
}
case 8: {
print_all_regs();
break;
}
case 9: {
print_gprs();
break;
}
case 10: {
/*extern void terminal_clear(void);*/
terminal_clear();
printf("Printing ASCII chars 0x00 through 0xFE, hit enter to exit\n");
sleep(2500);
terminal_clear();
for (int i = 0x00; i < 0xFF; i++)
{
printf("%c", (char) i);
}
printf("\n\n\\/ Cool ASCII art \\/\n%c%c\n%c%c\n", 0xDA, 0xBF, 0xC0, 0xD9);
gets();
break;
}
case 11: {
extern void seed_rand(uint32_t seed);
extern uint32_t ulrand(void);
uint64_t v = rdtsc();
seed_rand((uint32_t) v);
printf("%ull\n", ulrand());
break;
}
case 12: {
int retv = fat16_mount(0);
if (retv != 0)
{
printf("There was an error while mounting volume 0.\n");
break;
}
printf("Volume 0 mounted successfully.\n");
char fat_name[12];
fat16_file_t file;
filename_to_83("test.txt", fat_name);
retv = fat16_create_file(fat_name, &file);
if (retv != 0)
{
printf("There was an error while creating a file on volume 0.\n");
break;
}
uint8_t buf[512];
memset(buf, 0, sizeof(buf));
strcpy((char*) buf, "fg");
retv = fat16_write_file(&file, buf, (strlen((char*) buf)));
if (retv != 0)
{
printf("There was an error while writing to a file on volume 0.\n");
break;
}
uint8_t rbuf[512];
memset(rbuf, 0, sizeof(rbuf));
retv = fat16_read_file(&file, rbuf);
if (retv != 0)
{
printf("There was an error while reading from a file on volume 0.\n");
break;
}
printf("The data read should be: %s\n", (char*) buf);
printf("Read data: %s\n", (char*) rbuf);
printf("Deleting test file\n");
fat16_delete_file(fat_name);
break;
}
case 13:
{
printf("Enter char to print in decimal: ");
char* g = gets();
int val = atoi(g);
if (*g == '\0')
{
printf("Empty string entered\n");
break;
}
printf("%c\n", (char) val);
break;
}
case 14:
{
#if 0
void taskA() { while (1) printf("A"); }
void taskB() { while (1) printf("B"); }
create_task(taskA);
create_task(taskB);
#endif
break;
}
case 15:
{
char* filename = "t.bin";
int retv = fat16_mount(0);
if (retv != 0)
{
printf("There was an error while mounting volume 0.\n");
break;
}
printf("Volume 0 mounted successfully.\n");
char fat_name[12];
fat16_file_t file;
filename_to_83(filename, fat_name);
retv = fat16_find_file(fat_name, &file);
if (retv != 0)
{
printf("file %s could not be found\n", filename);
break;
}
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
retv = fat16_read_file(&file, buffer);
if (retv != 0)
{
printf("Could not read file s\n", (char*) filename);
break;
}
printf("read data: %s\n", (char*) buffer);
break;
}
case 16:
{
printf("Commands:\n");
for (int i = 0; i < NUM_COMMANDS; i++)
{
printf("%s\n", commands[i]);
}
break;
}
case 17:
{
char* filename = "hello.elf";
printf("Loading and executing file %s\n", filename);
int retv = fat16_mount(0);
if (retv != 0)
{
printf("There was an error while mounting volume 0.\n");
break;
}
printf("Volume 0 mounted successfully.\n");
char fat_name[12];
fat16_file_t file;
filename_to_83(filename, fat_name);
retv = fat16_find_file(fat_name, &file);
if (retv != 0)
{
printf("file %s could not be found\n", filename);
break;
}
uint8_t* buffer = malloc(file.size);
memset(buffer, 0, file.size);
retv = fat16_read_file(&file, buffer);
if (retv != 0)
{
printf("Could not read file s\n", (char*) filename);
break;
}
printf("Parsing ELF headers\n");
elf_executable_t* f = load_elf32(buffer);
printf("Attempting execution of executable...\n");
retv = f->entry_point();
printf("\nreturn value: %i\n", retv);
break;
}
case 18:
{
printf("testing int 16\n");
const char* str = "HELLO!\n";
syscall1(SYS_TERMINAL_WRITESTRING, str);
printf("test ran\n");
break;
}
}
return 0;
}