Annotation of nono/util/runx/doscall.cpp, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.