|
|
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.