Annotation of nono/util/runx/doscall.cpp, revision 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.