Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
5.5KB

  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <termios.h>
  5. #include "../emul.h"
  6. #include "shell-bin.h"
  7. #include "../../tools/cfspack/cfs.h"
  8. /* Collapse OS shell with filesystem
  9. *
  10. * On startup, if "cfsin" directory exists, it packs it as a afke block device
  11. * and loads it in. Upon halting, unpcks the contents of that block device in
  12. * "cfsout" directory.
  13. *
  14. * Memory layout:
  15. *
  16. * 0x0000 - 0x3fff: ROM code from shell.asm
  17. * 0x4000 - 0x4fff: Kernel memory
  18. * 0x5000 - 0xffff: Userspace
  19. *
  20. * I/O Ports:
  21. *
  22. * 0 - stdin / stdout
  23. * 1 - Filesystem blockdev data read/write. Reads and write data to the address
  24. * previously selected through port 2
  25. */
  26. //#define DEBUG
  27. #define MAX_FSDEV_SIZE 0x20000
  28. // in sync with glue.asm
  29. #define RAMSTART 0x2000
  30. #define STDIO_PORT 0x00
  31. #define FS_DATA_PORT 0x01
  32. // Controls what address (24bit) the data port returns. To select an address,
  33. // this port has to be written to 3 times, starting with the MSB.
  34. // Reading this port returns an out-of-bounds indicator. Meaning:
  35. // 0 means addr is within bounds
  36. // 1 means that we're equal to fsdev size (error for reading, ok for writing)
  37. // 2 means more than fsdev size (always invalid)
  38. // 3 means incomplete addr setting
  39. #define FS_ADDR_PORT 0x02
  40. static uint8_t fsdev[MAX_FSDEV_SIZE] = {0};
  41. static uint32_t fsdev_ptr = 0;
  42. // 0 = idle, 1 = received MSB (of 24bit addr), 2 = received middle addr
  43. static int fsdev_addr_lvl = 0;
  44. static int running;
  45. static uint8_t iord_stdio()
  46. {
  47. int c = getchar();
  48. if (c == EOF) {
  49. running = 0;
  50. }
  51. return (uint8_t)c;
  52. }
  53. static uint8_t iord_fsdata()
  54. {
  55. if (fsdev_addr_lvl != 0) {
  56. fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
  57. return 0;
  58. }
  59. if (fsdev_ptr < MAX_FSDEV_SIZE) {
  60. #ifdef DEBUG
  61. fprintf(stderr, "Reading FSDEV at offset %d\n", fsdev_ptr);
  62. #endif
  63. return fsdev[fsdev_ptr];
  64. } else {
  65. fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr);
  66. return 0;
  67. }
  68. }
  69. static uint8_t iord_fsaddr()
  70. {
  71. if (fsdev_addr_lvl != 0) {
  72. return 3;
  73. } else if (fsdev_ptr >= MAX_FSDEV_SIZE) {
  74. fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, MAX_FSDEV_SIZE);
  75. return 2;
  76. } else {
  77. return 0;
  78. }
  79. }
  80. static void iowr_stdio(uint8_t val)
  81. {
  82. if (val == 0x04) { // CTRL+D
  83. running = 0;
  84. } else {
  85. putchar(val);
  86. }
  87. }
  88. static void iowr_fsdata(uint8_t val)
  89. {
  90. if (fsdev_addr_lvl != 0) {
  91. fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
  92. return;
  93. }
  94. if (fsdev_ptr < MAX_FSDEV_SIZE) {
  95. #ifdef DEBUG
  96. fprintf(stderr, "Writing to FSDEV (%d)\n", fsdev_ptr);
  97. #endif
  98. fsdev[fsdev_ptr] = val;
  99. } else {
  100. fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr);
  101. }
  102. }
  103. static void iowr_fsaddr(uint8_t val)
  104. {
  105. if (fsdev_addr_lvl == 0) {
  106. fsdev_ptr = val << 16;
  107. fsdev_addr_lvl = 1;
  108. } else if (fsdev_addr_lvl == 1) {
  109. fsdev_ptr |= val << 8;
  110. fsdev_addr_lvl = 2;
  111. } else {
  112. fsdev_ptr |= val;
  113. fsdev_addr_lvl = 0;
  114. }
  115. }
  116. int main(int argc, char *argv[])
  117. {
  118. FILE *fp = NULL;
  119. while (1) {
  120. int c = getopt(argc, argv, "f:");
  121. if (c < 0) {
  122. break;
  123. }
  124. switch (c) {
  125. case 'f':
  126. fp = fopen(optarg, "r");
  127. if (fp == NULL) {
  128. fprintf(stderr, "Can't open %s\n", optarg);
  129. return 1;
  130. }
  131. fprintf(stderr, "Initializing filesystem from %s\n", optarg);
  132. int i = 0;
  133. int c;
  134. while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) {
  135. fsdev[i++] = c & 0xff;
  136. }
  137. if (i == MAX_FSDEV_SIZE) {
  138. fprintf(stderr, "Filesytem image too large.\n");
  139. return 1;
  140. }
  141. pclose(fp);
  142. break;
  143. default:
  144. fprintf(stderr, "Usage: shell [-f fsdev]\n");
  145. return 1;
  146. }
  147. }
  148. // Setup fs blockdev
  149. if (fp == NULL) {
  150. fprintf(stderr, "Initializing filesystem from cfsin\n");
  151. fp = fmemopen(fsdev, MAX_FSDEV_SIZE, "w");
  152. set_spit_stream(fp);
  153. if (spitdir("cfsin", "", NULL) != 0) {
  154. fprintf(stderr, "Can't initialize filesystem. Leaving blank.\n");
  155. }
  156. fclose(fp);
  157. }
  158. bool tty = isatty(fileno(stdin));
  159. struct termios termInfo;
  160. if (tty) {
  161. // Turn echo off: the shell takes care of its own echoing.
  162. if (tcgetattr(0, &termInfo) == -1) {
  163. printf("Can't setup terminal.\n");
  164. return 1;
  165. }
  166. termInfo.c_lflag &= ~ECHO;
  167. termInfo.c_lflag &= ~ICANON;
  168. tcsetattr(0, TCSAFLUSH, &termInfo);
  169. }
  170. Machine *m = emul_init();
  171. m->ramstart = RAMSTART;
  172. m->iord[STDIO_PORT] = iord_stdio;
  173. m->iord[FS_DATA_PORT] = iord_fsdata;
  174. m->iord[FS_ADDR_PORT] = iord_fsaddr;
  175. m->iowr[STDIO_PORT] = iowr_stdio;
  176. m->iowr[FS_DATA_PORT] = iowr_fsdata;
  177. m->iowr[FS_ADDR_PORT] = iowr_fsaddr;
  178. // initialize memory
  179. for (int i=0; i<sizeof(KERNEL); i++) {
  180. m->mem[i] = KERNEL[i];
  181. }
  182. // Run!
  183. running = 1;
  184. while (running && emul_step());
  185. if (tty) {
  186. printf("Done!\n");
  187. termInfo.c_lflag |= ECHO;
  188. termInfo.c_lflag |= ICANON;
  189. tcsetattr(0, TCSAFLUSH, &termInfo);
  190. emul_printdebug();
  191. }
  192. return 0;
  193. }