|
|
1.1 ! root 1: // vi:set ts=4: ! 2: ! 3: // ! 4: // nono ! 5: // Copyright (C) 2024 nono project ! 6: // Licensed under nono-license.txt ! 7: // ! 8: ! 9: #include "runx.h" ! 10: #include <fcntl.h> ! 11: #include <string.h> ! 12: #include <time.h> ! 13: ! 14: #define MAXFILES (10) // 同時にオープン出来るファイルハンドル数。適当 ! 15: ! 16: struct filedesc { ! 17: int fd; ! 18: char *filename; ! 19: }; ! 20: ! 21: static int32 open_file(uint32, uint32, int); ! 22: static uint32 write_file(uint32, uint32, uint32); ! 23: static int get_file_mode(uint32); ! 24: static uint32 close_file(uint32); ! 25: ! 26: static struct filedesc files[MAXFILES]; ! 27: ! 28: // 戻り値は 1 なら EXIT 処理、0 なら継続。 ! 29: int ! 30: doscall(pid_t pid, uint32 callno, struct reg *reg) ! 31: { ! 32: switch (callno) { ! 33: case 0x00: // _EXIT ! 34: TRACE(RegPC, "DOS _EXIT"); ! 35: // 関数 p() からの戻り値を 0 にする。 ! 36: RegD(0) = 0; ! 37: return 1; ! 38: ! 39: case 0x09: // _PRINT ! 40: { ! 41: uint32 msg; ! 42: msg = ptrace(PT_READ_D, pid, (void *)RegA(7), 0); ! 43: TRACE(RegPC, "DOS _PRINT($%06x)", msg); ! 44: if (msg == (uint32)-1) { ! 45: err(1, "doscall(%x): PT_READ_D", callno); ! 46: } ! 47: for (;;) { ! 48: uint32 ch32 = ptrace(PT_READ_D, pid, (void *)msg, 0); ! 49: for (int i = 0; i < 4; i++) { ! 50: if ((ch32 & 0xff000000) == 0) { ! 51: return 0; ! 52: } ! 53: fputc(ch32 >> 24, stdout); ! 54: ch32 <<= 8; ! 55: } ! 56: msg += 4; ! 57: } ! 58: break; ! 59: } ! 60: ! 61: case 0x1e: // _FPUTS ! 62: { ! 63: uint32 mesptr = readmem4(RegA(7)); ! 64: uint32 fileno = readmem2(RegA(7) + 4); ! 65: TRACE(RegPC, "DOS _FPUTS($%06x, fileno=%u)", mesptr, fileno); ! 66: ! 67: uint32 m = mesptr; ! 68: for (uint32 c; (c = readmem1(m)) != '\0'; m++) ! 69: ; ! 70: uint32 size = m - mesptr; ! 71: ! 72: write_file(fileno, mesptr, size); ! 73: break; ! 74: } ! 75: ! 76: case 0x20: // _SUPER ! 77: { ! 78: uint32 data = readmem4(RegA(7)); ! 79: ! 80: if (data == 0 && (GetSR & 0x2000) == 0) { ! 81: TRACE(RegPC, "DOS _SUPER(0)"); ! 82: emul.usp = RegA(7); ! 83: SetSR(GetSR | 0x2000); ! 84: data = emul.usp; ! 85: RegD(0) = emul.ssp; ! 86: RegA(7) = data; ! 87: } else if ((GetSR & 0x2000) != 0) { ! 88: TRACE(RegPC, "DOS _SUPER($%08x)", data); ! 89: emul.ssp = data; ! 90: SetSR(GetSR & ~0x2000); ! 91: RegA(7) = emul.usp; ! 92: } else { ! 93: TRACE(RegPC, "DOS _SUPER($%08x): XXX", data); ! 94: RegD(0) = -1; ! 95: } ! 96: break; ! 97: } ! 98: ! 99: case 0x25: // _INTVCS ! 100: { ! 101: uint16 intno = readmem2(RegA(7)); ! 102: uint32 addr = readmem4(RegA(7) + 2); ! 103: TRACE(RegPC, "DOS _INTVCS($%04x, $%06x)", intno, addr); ! 104: ! 105: uint32 vecaddr = (intno & 0xff) * 4; ! 106: if (intno <= 0xff) { ! 107: RegD(0) = readmem4(vecaddr); ! 108: writemem4(vecaddr, addr); ! 109: } else { ! 110: vecaddr += 0xd000; ! 111: RegD(0) = readmem4(vecaddr); ! 112: writemem4(vecaddr, addr); ! 113: } ! 114: break; ! 115: } ! 116: ! 117: case 0x27: // _GETTIM2 ! 118: { ! 119: struct tm tm; ! 120: time_t now = time(NULL); ! 121: localtime_r(&now, &tm); ! 122: TRACE(RegPC, "DOS _GETTIM2"); ! 123: RegD(0) = (tm.tm_hour << 16) ! 124: | (tm.tm_min << 8) ! 125: | tm.tm_sec; ! 126: break; ! 127: } ! 128: ! 129: case 0x2a: // _GETDATE ! 130: { ! 131: struct tm tm; ! 132: time_t now = time(NULL); ! 133: localtime_r(&now, &tm); ! 134: TRACE(RegPC, "DOS _GETDATE"); ! 135: RegD(0) = (tm.tm_wday << 16) ! 136: | ((tm.tm_year + 1900 - 1980) << 9) ! 137: | ((tm.tm_mon + 1) << 5) ! 138: | tm.tm_mday; ! 139: break; ! 140: } ! 141: ! 142: case 0x35: // _INTVCG ! 143: { ! 144: uint16 intno = readmem2(RegA(7)); ! 145: TRACE(RegPC, "DOS _INTVCG($%04x)", intno); ! 146: uint32 vecaddr = (intno & 0xff) * 4; ! 147: if (intno <= 0xff) { ! 148: RegD(0) = readmem4(vecaddr); ! 149: } else { ! 150: vecaddr += 0xd000; ! 151: RegD(0) = readmem4(vecaddr); ! 152: } ! 153: break; ! 154: } ! 155: ! 156: case 0x3c: // _CREATE ! 157: { ! 158: uint32 filename = readmem4(RegA(7)); ! 159: uint32 attr = readmem2(RegA(7) + 4); ! 160: ! 161: TRACE(RegPC, "DOS _CREATE($%06x, attr=$%04x)", filename, attr); ! 162: int32 fileno = open_file(filename, attr, ! 163: O_CREAT | O_TRUNC | O_RDWR | O_SYNC); ! 164: RegD(0) = fileno; ! 165: break; ! 166: } ! 167: ! 168: case 0x3d: // _OPEN ! 169: { ! 170: uint32 filename = readmem4(RegA(7)); ! 171: uint32 mode = readmem2(RegA(7) + 4); ! 172: TRACE(RegPC, "DOS _OPEN($%06x, mode=$%04x)", filename, mode); ! 173: ! 174: int unix_mode = 0; ! 175: bool ok = true; ! 176: ! 177: switch (mode & 0x03) { ! 178: case 2: ! 179: unix_mode |= O_RDWR; ! 180: break; ! 181: case 1: ! 182: unix_mode |= O_WRONLY; ! 183: break; ! 184: case 0: ! 185: unix_mode |= O_RDONLY; ! 186: break; ! 187: default: ! 188: RegD(0) = -12; // アクセスモード異常 ! 189: ok = false; ! 190: break; ! 191: } ! 192: ! 193: if (ok) { ! 194: int32 fileno = open_file(filename, 0, unix_mode | O_SYNC); ! 195: RegD(0) = fileno; ! 196: } ! 197: break; ! 198: } ! 199: ! 200: case 0x3e: // _CLOSE ! 201: { ! 202: uint16 fileno = readmem2(RegA(7)); ! 203: ! 204: TRACE(RegPC, "DOS _CLOSE(%u)", fileno); ! 205: RegD(0) = close_file(fileno); ! 206: break; ! 207: } ! 208: ! 209: case 0x40: // _WRITE ! 210: { ! 211: uint16 fileno = readmem2(RegA(7)); ! 212: uint32 dataptr = readmem4(RegA(7) + 2); ! 213: uint32 size = readmem4(RegA(7) + 6); ! 214: ! 215: TRACE(RegPC, "DOS _WRITE(%u, $%06x, len=$%06x)", fileno, dataptr, size); ! 216: RegD(0) = write_file(fileno, dataptr, size); ! 217: break; ! 218: } ! 219: ! 220: case 0x44: // _IOCTRL ! 221: { ! 222: uint32 mode = readmem2(RegA(7)); ! 223: uint32 fileno; ! 224: switch (mode) { ! 225: case 0: // IOCTRLGT 装置情報取得 ! 226: fileno = readmem2(RegA(7) + 2); ! 227: if (fileno == 0) { // STDIN ! 228: RegD(0) = 0x8081; // 100u'uuuu'100u'0001; ! 229: } else if (fileno == 1) { // STDOUT ! 230: RegD(0) = 0x8082; // 100u'uuuu'100u'0010; ! 231: } else if (fileno == 2) { // STDERR ! 232: RegD(0) = 0x8081; // 100u'uuuu'100u'0001; ! 233: } else { ! 234: RegD(0) = -1; ! 235: } ! 236: TRACE(RegPC, "DOS _IOCTRL(mode=0(IOCTRLGT), fileno=%u) -> $%x", ! 237: fileno, RegD(0)); ! 238: break; ! 239: ! 240: case 7: // IOCTRLOS 出力ステータス取得 ! 241: fileno = readmem2(RegA(7) + 2); ! 242: if (fileno == 0) { ! 243: RegD(0) = 0; ! 244: } else if (fileno == 1 || fileno == 2) { ! 245: RegD(0) = -1; ! 246: } else { ! 247: int filemode = get_file_mode(fileno); ! 248: if (filemode < 0) { ! 249: RegD(0) = filemode; ! 250: } else if (filemode == O_WRONLY || filemode == O_RDWR) { ! 251: RegD(0) = -1; ! 252: } else { ! 253: RegD(0) = 0; ! 254: } ! 255: } ! 256: TRACE(RegPC, "DOS _IOCTRL(mode=7(IOCTRLOS), fileno=%u) -> $%x", ! 257: fileno, RegD(0)); ! 258: break; ! 259: ! 260: default: ! 261: errx(1, "%06x: DOS _IOCTRL(mode=%u) not implemented", RegPC, mode); ! 262: } ! 263: break; ! 264: } ! 265: ! 266: case 0x4a: // _SETBLOCK ! 267: { ! 268: uint32 memptr = readmem4(RegA(7)); ! 269: uint32 len = readmem4(RegA(7) + 4); ! 270: ! 271: TRACE(RegPC, "DOS _SETBLOCK(ptr=$%06x, len=$%06x)", memptr, len); ! 272: // 何もせずに出来たという。 ! 273: RegD(0) = len; ! 274: break; ! 275: } ! 276: ! 277: case 0xff: // _CHANGE_PR ! 278: TRACE(RegPC, "DOS _CHANGE_PR"); ! 279: // 何もしない。 ! 280: break; ! 281: ! 282: default: ! 283: errx(1, "%06x: Unsupported DOS call $%x", RegPC, callno); ! 284: } ! 285: return 0; ! 286: } ! 287: ! 288: // DOS CALL 関連の初期化。 ! 289: int ! 290: init_doscall() ! 291: { ! 292: emul.ssp = 0x10000; ! 293: ! 294: files[0].fd = 0; ! 295: files[1].fd = 1; ! 296: files[2].fd = 2; ! 297: for (int i = 3; i < countof(files); i++) { ! 298: files[i].fd = -1; ! 299: } ! 300: ! 301: return 0; ! 302: } ! 303: ! 304: // ファイルオープン。 ! 305: // fileaddr: Human68k ファイル名の先頭ゲストアドレス ! 306: // attr: Human68k 属性 ! 307: // 戻り値はオープンしたファイルハンドル。負数ならエラーコード。 ! 308: static int32 ! 309: open_file(uint32 fileaddr, uint32 attr, int mode) ! 310: { ! 311: int32 fileno; ! 312: struct filedesc *f = NULL; ! 313: ! 314: // 空きエントリを探す。 ! 315: for (int i = 0; i < countof(files); i++) { ! 316: if (files[i].fd == -1) { ! 317: fileno = i; ! 318: f = &files[fileno]; ! 319: break; ! 320: } ! 321: } ! 322: if (f == NULL) { ! 323: errno = EMFILE; ! 324: warn("%s", __func__); ! 325: return -4; ! 326: } ! 327: ! 328: char filename[256]; ! 329: char *p = filename; ! 330: for (int i = 0; i < sizeof(filename) - 3; i++) { ! 331: uint c = readmem1(fileaddr++); ! 332: if (c == 0) { ! 333: break; ! 334: } ! 335: if (c < 32 || c >= 127 || c == 0x5c) { ! 336: int n = snprintf(p, sizeof(filename) - 3 - (p - filename), ! 337: "%02x", c); ! 338: p += n; ! 339: } else { ! 340: *p++ = c; ! 341: } ! 342: } ! 343: *p = '\0'; ! 344: ! 345: DEBUG(2, "open_file: \"%s\" -> %u", filename, fileno); ! 346: int fd = open(filename, mode, 0666); ! 347: if (fd < 0) { ! 348: if (errno != ENOENT) { ! 349: warn("open_file: %s", filename); ! 350: } ! 351: return -1; ! 352: } ! 353: ! 354: f->fd = fd; ! 355: f->filename = strdup(filename); ! 356: ! 357: return fileno; ! 358: } ! 359: ! 360: // ファイルハンドルへの書き出し。 ! 361: static uint32 ! 362: write_file(uint32 fileno, uint32 addr, uint32 size) ! 363: { ! 364: if (fileno >= countof(files)) { ! 365: errno = ERANGE; ! 366: warn("%s: fileno=%d", __func__, fileno); ! 367: return -14; ! 368: } ! 369: ! 370: struct filedesc *f = &files[fileno]; ! 371: if (f->fd < 0) { ! 372: errno = EINVAL; ! 373: warn("%s: fileno=%d", __func__, fileno); ! 374: return -6; ! 375: } ! 376: ! 377: char buf[size]; ! 378: for (int i = 0; i < size; i++) { ! 379: buf[i] = readmem1(addr + i); ! 380: } ! 381: int n = write(f->fd, buf, size); ! 382: if (n < 0) { ! 383: warn("%s: fileno=%d", __func__, fileno); ! 384: return -1; ! 385: } ! 386: return size; ! 387: } ! 388: ! 389: static int ! 390: get_file_mode(uint32 fileno) ! 391: { ! 392: struct filedesc *f; ! 393: ! 394: if (fileno >= countof(files)) { ! 395: return -2 /* FILE_NOT_FOUND */; ! 396: } ! 397: ! 398: f = &files[fileno]; ! 399: if (f->fd < 0) { ! 400: return -2 /* FILE_NOT_FOUND */; ! 401: } ! 402: ! 403: int fl = fcntl(f->fd, F_GETFL); ! 404: int accmode = fl & O_ACCMODE; ! 405: ! 406: return accmode; ! 407: } ! 408: ! 409: // ファイルハンドルのクローズ。 ! 410: static uint32 ! 411: close_file(uint32 fileno) ! 412: { ! 413: if (fileno >= countof(files)) { ! 414: errno = ERANGE; ! 415: warn("%s: fileno=%d", __func__, fileno); ! 416: return -14; ! 417: } ! 418: ! 419: struct filedesc *f = &files[fileno]; ! 420: if (f->fd < 0) { ! 421: errno = EINVAL; ! 422: warn("%s: fileno=%d", __func__, fileno); ! 423: return -6; ! 424: } ! 425: ! 426: if (f->fd >= 3) { ! 427: close(f->fd); ! 428: } ! 429: return 0; ! 430: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.