diff --git a/Makefile b/Makefile index 5b4face..5ce143f 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,8 @@ clean: @rm -f $(OBJS) boot.bin kernel.bin kernel.elf $(IMAGE) @$(MAKE) --no-print-directory -C tests clean +# If the shutdown command doesn't work, change this to "qemu-system-i386 -fda $< -hda rootfs/kfs.img -device isa-debug-exit,iobase=0x501,iosize=0x1" +# This same message is also in core/shell.c run: $(IMAGE) qemu-system-i386 -fda $< -hda rootfs/kfs.img > /dev/null 2>&1 diff --git a/kernel/core/shell.c b/kernel/core/shell.c index 26626b2..ed1fcb1 100644 --- a/kernel/core/shell.c +++ b/kernel/core/shell.c @@ -14,9 +14,14 @@ #include "../lib/math.h" #define CMD_COMP(name) (strcmp(strtok(chars, " "), name) == 0) +#define MAX_CAT_SIZE 8192 // Max file size for cat (8KB for now) extern struct kfs_superblock superblock; +static inline void outb(uint16_t port, uint8_t val) { + __asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port)); +} + void reboot(void) { klog("reboot triggered"); asm volatile ( @@ -26,12 +31,57 @@ void reboot(void) { ); } +// NOTE: This probably won't work for the current qemu run command for testing. +// If not, try: qemu-system-i386 -fda floppy.img -hda rootfs/kfs.img -device isa-debug-exit,iobase=0x501,iosize=0x1 +void shutdown(void) { + klog("shutdown triggered\n"); + + // QEMU ISA debug exit + outb(0x501, 0x00); // Exit with code 0 + + // Try ACPI shutdown + outb(0xB004, 0x2000); // Bochs/QEMU + outb(0x604, 0x2000); // QEMU (but newer) + outb(0x4004, 0x3400); // VirtualBox + + // Try writing to ACPI PM1a control register + outb(0x600, 0x34); + outb(0xb004, 0x2000); + + // If ACPI didn't work, try APM + asm volatile( + "mov $0x5301, %%ax\n" + "xor %%bx, %%bx\n" + "int $0x15\n" + "jc apm_fail\n" + + "mov $0x5308, %%ax\n" + "mov $1, %%bx\n" + "mov $1, %%cx\n" + "int $0x15\n" + + "mov $0x5307, %%ax\n" + "mov $1, %%bx\n" + "mov $3, %%cx\n" + "int $0x15\n" + + "apm_fail:\n" + ::: "ax", "bx", "cx" + ); + + klog("shutdown failed - halting\n"); + asm volatile("cli"); + for (;;) { + asm volatile("hlt"); + } +} void sh(void) { klog("sh: scheduler and elfs are not properly implemented yet. dropping into temporary shell.\n"); char chars[128]; int i; + static uint8_t cat_buffer[MAX_CAT_SIZE]; // Static buffer to avoid stack overflow for (;;) { puts("// "); @@ -49,9 +99,13 @@ void sh(void) { putc('\b'); } } else { + if ((unsigned int)i >= sizeof(chars) - 1) { + chars[i] = 0; + break; + } putc(c); chars[i++] = c; - if (c == '\n' || (unsigned int)i >= sizeof(chars) - 1) { + if (c == '\n') { chars[i - 1] = 0; break; } @@ -79,13 +133,15 @@ void sh(void) { struct kfs_file* f = kfs_find(chars + 4); if (!f) { printf("cat: %s: not found\n", chars + 4); + } else if (f->size > MAX_CAT_SIZE) { + printf("cat: file too large (max %d bytes)\n", MAX_CAT_SIZE); } else { - uint8_t data[(f->size + 511) & ~511]; - if (kfs_read(f->name, data) < 0) { + uint32_t rounded_size = (f->size + 511) & ~511; + if (kfs_read(f->name, cat_buffer) < 0) { puts("kfs: ioerr\n"); } else { for (uint32_t j = 0; j < f->size; j++) - putc(data[j]); + putc(cat_buffer[j]); putc('\n'); } } @@ -93,9 +149,23 @@ void sh(void) { else if (CMD_COMP("reboot")) { reboot(); } + else if (CMD_COMP("shutdown")) { + shutdown(); + } else if (CMD_COMP("exec")) { exec(chars + 5) == ERR_FORMAT ? puts("exec: format error\n") : 0; } + + // Placeholder for now + // Don't remove these comments until there is a proper implementation for elf. + // AHEM *gingrspacecadet* + // - Bryson + + /*else if (CMD_COMP("elf")) { + extern int elfExec(const char* name, void** entry, struct uexAlloc* out_alloc); + elfExec(chars + 4, NULL, NULL); + } + */ else if (CMD_COMP("help")) { puts("Available commands:\n" " version - show kernel version\n" @@ -104,7 +174,9 @@ void sh(void) { " exec - execute UEX file\n" " clear - clear the screen\n" " help - show this help message\n" - " touch - create an empty file\n"); + " touch - create an empty file\n" + " reboot - reboot the system\n" + " shutdown - power off the system\n"); } else if (chars[0] != 0) { printf("%s: command not found\n", chars); }