#include #include #include #include #include "../emul.h" #include "shell-bin.h" /* Collapse OS shell with filesystem * * On startup, if "cfsin" directory exists, it packs it as a afke block device * and loads it in. Upon halting, unpcks the contents of that block device in * "cfsout" directory. * * Memory layout: * * 0x0000 - 0x3fff: ROM code from shell.asm * 0x4000 - 0x4fff: Kernel memory * 0x5000 - 0xffff: Userspace * * I/O Ports: * * 0 - stdin / stdout * 1 - Filesystem blockdev data read/write. Reads and write data to the address * previously selected through port 2 */ //#define DEBUG #define MAX_FSDEV_SIZE 0x20000 // in sync with glue.asm #define RAMSTART 0x2000 #define STDIO_PORT 0x00 #define FS_DATA_PORT 0x01 // Controls what address (24bit) the data port returns. To select an address, // this port has to be written to 3 times, starting with the MSB. // Reading this port returns an out-of-bounds indicator. Meaning: // 0 means addr is within bounds // 1 means that we're equal to fsdev size (error for reading, ok for writing) // 2 means more than fsdev size (always invalid) // 3 means incomplete addr setting #define FS_ADDR_PORT 0x02 static uint8_t fsdev[MAX_FSDEV_SIZE] = {0}; static uint32_t fsdev_ptr = 0; // 0 = idle, 1 = received MSB (of 24bit addr), 2 = received middle addr static int fsdev_addr_lvl = 0; static int running; static uint8_t iord_stdio() { int c = getchar(); if (c == EOF) { running = 0; } return (uint8_t)c; } static uint8_t iord_fsdata() { if (fsdev_addr_lvl != 0) { fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); return 0; } if (fsdev_ptr < MAX_FSDEV_SIZE) { #ifdef DEBUG fprintf(stderr, "Reading FSDEV at offset %d\n", fsdev_ptr); #endif return fsdev[fsdev_ptr]; } else { fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr); return 0; } } static uint8_t iord_fsaddr() { if (fsdev_addr_lvl != 0) { return 3; } else if (fsdev_ptr >= MAX_FSDEV_SIZE) { fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, MAX_FSDEV_SIZE); return 2; } else { return 0; } } static void iowr_stdio(uint8_t val) { if (val == 0x04) { // CTRL+D running = 0; } else { putchar(val); } } static void iowr_fsdata(uint8_t val) { if (fsdev_addr_lvl != 0) { fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); return; } if (fsdev_ptr < MAX_FSDEV_SIZE) { #ifdef DEBUG fprintf(stderr, "Writing to FSDEV (%d)\n", fsdev_ptr); #endif fsdev[fsdev_ptr] = val; } else { fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr); } } static void iowr_fsaddr(uint8_t val) { if (fsdev_addr_lvl == 0) { fsdev_ptr = val << 16; fsdev_addr_lvl = 1; } else if (fsdev_addr_lvl == 1) { fsdev_ptr |= val << 8; fsdev_addr_lvl = 2; } else { fsdev_ptr |= val; fsdev_addr_lvl = 0; } } int main(int argc, char *argv[]) { FILE *fp = NULL; while (1) { int c = getopt(argc, argv, "f:"); if (c < 0) { break; } switch (c) { case 'f': fp = fopen(optarg, "r"); if (fp == NULL) { fprintf(stderr, "Can't open %s\n", optarg); return 1; } break; default: fprintf(stderr, "Usage: shell [-f fsdev]\n"); return 1; } } // Setup fs blockdev if (fp == NULL) { fp = popen("../cfspack/cfspack cfsin", "r"); if (fp == NULL) { fprintf(stderr, "Can't initialize filesystem. Leaving blank.\n"); } } if (fp != NULL) { fprintf(stderr, "Initializing filesystem\n"); int i = 0; int c; while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) { fsdev[i++] = c & 0xff; } if (i == MAX_FSDEV_SIZE) { fprintf(stderr, "Filesytem image too large.\n"); return 1; } pclose(fp); } bool tty = isatty(fileno(stdin)); struct termios termInfo; if (tty) { // Turn echo off: the shell takes care of its own echoing. if (tcgetattr(0, &termInfo) == -1) { printf("Can't setup terminal.\n"); return 1; } termInfo.c_lflag &= ~ECHO; termInfo.c_lflag &= ~ICANON; tcsetattr(0, TCSAFLUSH, &termInfo); } Machine *m = emul_init(); m->ramstart = RAMSTART; m->iord[STDIO_PORT] = iord_stdio; m->iord[FS_DATA_PORT] = iord_fsdata; m->iord[FS_ADDR_PORT] = iord_fsaddr; m->iowr[STDIO_PORT] = iowr_stdio; m->iowr[FS_DATA_PORT] = iowr_fsdata; m->iowr[FS_ADDR_PORT] = iowr_fsaddr; // initialize memory for (int i=0; imem[i] = KERNEL[i]; } // Run! running = 1; while (running && emul_step()); if (tty) { printf("Done!\n"); termInfo.c_lflag |= ECHO; termInfo.c_lflag |= ICANON; tcsetattr(0, TCSAFLUSH, &termInfo); emul_printdebug(); } return 0; }