|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2023 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // Windrv (相当)
9: //
10:
11: #pragma once
12:
13: #include "device.h"
14: #include <array>
15: #include <deque>
16: #include <map>
17:
18: class HostWindrv;
19: class MainbusDevice;
20: class MPU680x0Device;
21: class WindrvDevice;
22:
23: // Human68k の定数とか構造体とか。
24: class Human68k
25: {
26: public:
27: static const int MAX_PATH = 96;
28:
29: static const uint8 ATTR_RDONLY = 0x01;
30: static const uint8 ATTR_HIDDEN = 0x02;
31: static const uint8 ATTR_SYSTEM = 0x04;
32: static const uint8 ATTR_VOLUME = 0x08;
33: static const uint8 ATTR_DIR = 0x10;
34: static const uint8 ATTR_ARCHIVE = 0x20;
35:
36: // 標準(<fcntl.h>) の O_RDONLY とかは #define なので、
37: // ここで別の名前空間で同名の定数を定義するとかが出来ない。
38: static const int OPEN_RDONLY = 0;
39: static const int OPEN_WRONLY = 1;
40: static const int OPEN_RDWR = 2;
41:
42: #define DEF static const uint32
43: // エラーコード(下位バイト)
44: DEF ERR_INVALID_UNIT = 0x0001; // 無効なユニット番号
45: DEF ERR_INVALID_COMMAND = 0x0003; // 無効なコマンド
46: DEF ERR_WRITE = 0x000a; // 書き込みエラー
47: DEF ERR_READ = 0x000b; // 読み込みエラー
48: DEF ERR_MISC = 0x000c; // エラーが発生しました
49: DEF ERR_WRITE_PROTECT = 0x000e; // 書き込み保護されている
50: // エラーコード(上位バイト)
51: DEF ERR_IGNORE = 0x4000; // 無視(I)
52: DEF ERR_RETRY = 0x2000; // 再実行(R)
53: DEF ERR_ABORT = 0x1000; // 中止(A)
54: // 合成したもの
55: DEF ERR_INVALID_UNIT_IA = ERR_INVALID_UNIT | ERR_IGNORE | ERR_ABORT;
56: DEF ERR_INVALID_COMMAND_IA = ERR_INVALID_COMMAND | ERR_IGNORE | ERR_ABORT;
57:
58: // ステータスコード
59: DEF RES_INVALID_FUNC = -1; // 無効なファンクションコード
60: DEF RES_FILE_NOT_FOUND = -2; // ファイルが見付からない
61: DEF RES_DIR_NOT_FOUND = -3; // ディレクトリが見付からない
62: DEF RES_TOO_MANY_HANDLE = -4; // オープンしているハンドルが多い
63: DEF RES_NOT_A_FILE = -5; // ディレクトリ・ボリュームは不可
64: DEF RES_NOT_OPENED = -6; // ハンドルはオープンされていない
65: DEF RES_INVALID_MEM = -7; // メモリ管理領域が不正
66: DEF RES_NO_MEMORY = -8; // メモリが足りない
67: DEF RES_INVALID_PTR = -9; // ポインタが無効
68: DEF RES_INVALID_ENV = -10; // 環境が不正
69: DEF RES_ILLEGAL_FORMAT = -11; // 実行ファイルのフォーマットが不正
70: DEF RES_INVALID_MODE = -12; // オープンのアクセスモードが不正
71: DEF RES_INVALID_PATH = -13; // ファイル名が不正
72: DEF RES_INVALID_PARAM = -14; // パラメータが不正
73: DEF RES_INVALID_DRIVE = -15; // ドライブ指定が不正
74: DEF RES_CURRENT_DIR = -16; // カレントディレクトリは削除出来ない
75: DEF RES_NO_IOCTRL = -17; // IOCTRL 出来ないデバイス
76: DEF RES_LAST_FILE = -18; // これ以上ファイルが見付からない
77: DEF RES_CANNOT_WRITE = -19; // ファイルは書き込み出来ない
78: DEF RES_DIR_EXISTS = -20; // ディレクトリはすでに存在する
79: DEF RES_CANNOT_DELETE = -21; // ファイルがあるので削除出来ない
80: DEF RES_CANNOT_RENAME = -22; // ファイルがあるのでリネーム出来ない
81: DEF RES_DISK_FULL = -23; // ディスクが一杯
82: DEF RES_DIR_FULL = -24; // ディレクトリが一杯
83: DEF RES_CANNOT_SEEK = -25; // シーク出来ない
84: DEF RES_SUPERVISOR = -26; // スーパバイザ状態でスーパバイザ指定
85: DEF RES_THREAD_EXISTS = -27; // スレッド名が存在する
86: DEF RES_PROCESS_BUF = -28; // プロセス間通信バッファが書き込み禁止
87: DEF RES_BACKGROUND = -29; // バックグラウンドプロセスを起動出来ない
88: DEF RES_NO_LOCKBUF = -32; // ロック領域が足りない
89: DEF RES_LOCKED = -33; // ロックされている
90: DEF RES_DRIVE_OPENED = -34; // ドライブのハンドルはオープンされている
91: DEF RES_TOO_MANY_LINKS = -35; // シンボリックリンクのネストが多い
92: DEF RES_FILE_EXISTS = -80; // ファイルが存在する
93: #undef DEF
94:
95: struct FILES {
96: uint8 sattr; // $00: 検索する属性
97: uint8 drive; // $01: ドライブ番号
98: uint32 sector; // $02: ディレクトリのセクタ番号
99: // (DOS _FILES の先頭アドレスで代用)
100: //uint16 sector2; // $06: 詳細不明、未使用
101: uint16 offset; // $08: ディレクトリの位置、詳細不明
102: //char[8] name1; // $0a: 作業用ファイル名、未使用
103: //char[3] ext; // $12: 作業用拡張子、未使用
104: uint8 attr; // $15: ファイル属性
105: uint16 time; // $16: 最終更新時刻
106: uint16 date; // $18: 最終更新日付
107: uint32 size; // $1a: ファイルサイズ
108: //char[23] name; // $1e: ファイル名(フル)
109:
110: // ファイル名。
111: // マルチバイト文字をサポートした場合はここはホスト文字コードの
112: // ファイル名なので、ゲスト文字コード(Shift_JIS)で23バイトに
113: // 収まってもホスト文字コードで23バイトで収まるとは限らない。
114: std::string name;
115:
116: // (parent を通じて) 必要なフィールドだけを VM メモリに書き出す。
117: void WriteToMem(WindrvDevice *parent, uint32 addr) const;
118: };
119:
120: class FCB
121: {
122: // +$00, 6.B: (内部使用)
123: // +$06, 1.L: ファイルポインタ
124: // +$0a, 1.L: (内部使用)
125: // +$0e, 1.B: オープンモード
126: // +$0f, 21.B: (内部使用)
127: // +$24, 8.B: ファイル名1
128: // +$2c, 3.B: 拡張子
129: // +$2f, 1.B: ファイル属性
130: // +$30, 10.B: ファイル名2
131: // +$3a, 1.W: 最終更新時刻
132: // +$3c, 1.W: 最終更新日付
133: // +$3e, 1.W: (内部使用)
134: // +$40, 1.L: ファイルサイズ
135: // +$44, 7.L: (内部使用)
136: public:
137: FCB(WindrvDevice *parent_, uint32 addr_);
138:
139: // ここにコピーは持たず、都度 VM メモリを参照/更新する。
140: // FCB はフィールドが多いわりに Open、Read などの各コマンドの
141: // フィールドアクセスはまばらななので。
142: uint32 GetPos() const; // 現在位置取得
143: void SetPos(uint32); // 現在位置設定
144: void AddPos(uint32); // 現在位置を加算
145: uint8 GetMode() const; // オープンモード取得
146: void SetDateTime(uint32); // 日付時刻を設定
147: uint32 GetSize() const; // サイズ取得
148: void SetSize(uint32); // サイズ設定
149: void SetName(const std::string& name1, const std::string& name2,
150: const std::string& ext); // ファイル名を設定
151:
152: uint32 GetAddr() const { return addr; }
153:
154: protected:
155: WindrvDevice *parent {};
156:
157: private:
158: uint32 addr {}; // FCB アドレス(検索キー)
159: };
160:
161: struct capacity {
162: uint16 avail_clusters; // 空きクラスタ数
163: uint16 total_clusters; // 総クラスタ数
164: uint16 sectors_per_cluster;
165: uint16 bytes_per_sector;
166:
167: // (parent を通じて) VM メモリに書き出す。
168: void WriteToMem(WindrvDevice *parent, uint32 addr) const;
169: };
170:
171: struct DPB {
172: uint16 sector_size; // 1セクタあたりのバイト数
173: uint8 cluster_size; // 1クラスタあたりのセクタ数 - 1
174: uint8 shift; // クラスタからセクタへのシフト数
175: // (bit7=%1 なら 16bit FAT ?)
176: uint16 fat_sector; // FAT の先頭セクタ番号
177: uint8 fat_max; // FAT 領域の個数
178: uint8 fat_size; // 1つの FAT 領域のセクタ数
179: uint16 file_max; // ルートディレクトリの最大ファイル数
180: uint16 data_sector; // データ領域の先頭セクタ
181: uint16 cluster_max; // 総クラスタ数
182: uint16 root_sector; // ルートディレクトリの先頭セクタ番号
183: uint8 media; // メディア ID
184:
185: // (parent を通じて) VM メモリに書き出す。
186: void WriteToMem(WindrvDevice *parent, uint32 addr) const;
187: };
188:
189: // 属性をデバッグ表示用文字列にする。
190: static std::string AttrStr(uint8 attr);
191:
192: // オープンモードを表示用文字列にする。
193: static std::string OpenModeStr(uint8 mode);
194:
195: // ステータスコード/エラーコードに対応するメッセージを返す。
196: static const char *GetResultMsg(uint32 result);
197:
198: // UNIX 時刻から MS-DOS 形式の日付時刻を取得。
199: // uint32 の上位が日付、下位が時刻で返す。
200: static uint32 Unixtime2DateTime(time_t);
201:
202: // MS-DOS 形式の日付時刻から UNIX 時刻を取得。
203: static time_t DateTime2Unixtime(uint32);
204:
205: private:
206: static const char * const result_msg[];
207: static const char * const err_msg[];
208: };
209:
210: // 仮想ディレクトリエントリ
211: class VDirent
212: {
213: public:
214: VDirent(const std::string& name_, bool isdir_);
215:
216: // ここの属性は Valid かどうかと Dir/Archive(Regular) のみを使う。
217: // Files/NFiles で拾う時は (タイムスタンプやサイズとともに)
218: // 属性も改めてファイルシステムから拾う。
219: bool IsValid() const { return isvalid; }
220: bool IsDir() const { return isdir; }
221: bool IsArchive() const { return !isdir; }
222:
223: // このエントリを Human68k に見せないようにする。
224: void Invalidate() { isvalid = false; }
225:
226: std::string name {}; // ホストファイル名。
227: bool isdir {}; // ディレクトリなら true、ファイルなら false。
228: bool isvalid {}; // エントリが有効なら true。
229: };
230:
231: // 仮想ディレクトリ構造
232: class VDir
233: {
234: public:
235: VDir();
236: VDir(HostWindrv *host_, const std::string& path_);
237:
238: // ホスト相対パスを返す。
239: const std::string& GetPath() const { return path; }
240:
241: // このディレクトリから name にマッチするエントリを返す。
242: // 見付からなければ NULL を返す。
243: const VDirent *MatchName(const std::string& name, bool want_exist) const;
244:
245: void Acquire();
246: void Release();
247:
248: // 参照カウントを返す。
249: int Refcount() const { return refcount; }
250:
251: // この VDir 構成時の mtime [nsec] を返す。
252: uint64 GetMTime() const { return mtime; }
253:
254: // mtime を更新する。
255: void SetMTime(uint64 mtime_) { mtime = mtime_; }
256:
257: // この VDir の参照時刻 [usec] を返す。
258: uint64 GetATime() const { return atime; }
259:
260: // 参照時刻を更新する。
261: void UpdateATime();
262:
263: // このディレクトリ内のエントリ。
264: std::vector<VDirent> list {};
265:
266: private:
267: // ホストでの相対パス。
268: std::string path {};
269:
270: // ホストの対応ディレクトリの更新日時。
271: // (st_mtimespec がある場合のみ使用する)
272: uint64 mtime {};
273:
274: // この VDir を参照した実時刻 [usec]。
275: // こっちは、キャッシュから追い出す人を決定するために使うので uint64。
276: uint64 atime {};
277:
278: // 参照中のディレクトリを消さないようにするため。
279: int refcount {};
280:
281: HostWindrv *host {};
282: };
283:
284: // VDir を自動変数みたいに勝手にクローズしてほしい。
285: class AutoVDir
286: {
287: public:
288: AutoVDir(HostWindrv *host_, VDir *vdir_) {
289: host = host_;
290: vdir = vdir_;
291: }
292: ~AutoVDir();
293:
294: // vdir-> で VDir* をアクセスすることで透過っぽく見せる。
295: VDir *operator->() const noexcept {
296: return vdir;
297: }
298:
299: // unique_ptr と同様に (bool) で有効かどうかを返す。
300: explicit operator bool() const noexcept {
301: return (vdir != NULL);
302: }
303:
304: private:
305: HostWindrv *host {};
306: VDir *vdir {};
307: };
308:
309: // FILES のこちら側のバッファ。
310: class FilesBuf
311: {
312: public:
313: FilesBuf(uint32 key_, HostWindrv *host_);
314: void Init(uint32 key_, HostWindrv *host_);
315:
316: uint64 GetATime() const { return atime; }
317: void UpdateATime();
318:
319: public:
320: uint32 key {}; // FILES バッファアドレス
321: HostWindrv *host {}; // ホスト (ドライブ)
322: std::string path {}; // ホスト相対パス
323:
324: // マッチしたファイル名一覧。
325: // Files/NFiles で取得するたびに先頭から削除していく方式。
326: std::deque<std::string> list {};
327:
328: // 直近にマッチしたファイル名(ログ出力用)
329: std::string fname {};
330:
331: private:
332: uint64 atime {};
333: };
334:
335: class Windrv
336: {
337: public:
338: // Human68k の FCB 構造体とホスト側で必要なメンバを集約したクラス。
339: // ハンドルのように使う。
340: class FCB : public Human68k::FCB
341: {
342: using inherited = Human68k::FCB;
343: public:
344: FCB(WindrvDevice *, uint32 addr_, HostWindrv *host_);
345:
346: void Close();
347:
348: // 対応するホストドライバ
349: HostWindrv *host {};
350: // ファイルディスクリプタ
351: int fd {};
352: };
353:
354: // いずれオプションになるかも知れないが。
355: static const bool option_case_sensitive = false;
356: };
357:
358: class WindrvDevice : public IODevice, Windrv
359: {
360: using inherited = IODevice;
361: friend class Human68k;
362: friend class Windrv;
363:
364: // Human68k の NAMESTS 構造体を読み込んだもの。
365: // windrv.sys では、Windrv デバイスから windrv.sys にこの構造体を返す
366: // ケースはなく、すべて windrv.sys から Windrv デバイスへの方向なので、
367: // 受け取った時点でホスト側に都合のいいように加工して保持する。
368: class NAMESTS
369: {
370: // +$00, 1.B: ワイルドカード文字数
371: // +$01, 1.B: ドライブ番号 (A:=0、B:=1、…)
372: // +$02,65.B: パス
373: // +$43, 8.B: ファイル名1 (余りは ' ' で埋める)
374: // +$4b, 3.B: 拡張子 (余りは ' ' で埋める)
375: // +$4e,10.B: ファイル名2 (余りは '\0' で埋める)
376: //
377: // NAMESTS 内のパスは '\' 区切り、最後にも '\' が付いて '\0' で終端、
378: // らしいが、観測してると '\t'(\x09) 区切りで最後にも '\t' が付いて
379: // '\0' で終端する文字列が来てる。なんだべ。
380: public:
381: static const int Size = 0x58; // 構造体の大きさ
382: private:
383: std::string path; // '/' 区切り
384: std::string name1; // パディングの ' ' を除いたもの
385: std::string ext; // パディングの ' ' を除いたもの
386: std::string name2; // パディングの '\0' を除いたもの
387: public:
388: int wildcard;
389: int drive;
390:
391: public:
392: // コンストラクタ
393: NAMESTS(WindrvDevice *, uint32 addr);
394:
395: // drive, path を '/' 区切りで返す。
396: std::string GetDrivePath() const;
397:
398: // path のみ('/' 区切り)を返す。
399: const std::string& GetPath() const { return path; }
400:
401: // ファイル名(8+10.3)を返す。
402: std::string GetName() const;
403:
404: const std::string& GetName1() const { return name1; }
405: const std::string& GetName2() const { return name2; }
406: const std::string& GetExt() const { return ext; }
407:
408: // ドライブ、パス、ファイル名を返す。
409: std::string GetFull() const;
410:
411: // ログ表示用のドライブ、パス文字列を返す。
412: std::string PrintDrivePath() const;
413: };
414:
415: // 最大ドライブ数
416: static const int MaxDrives = 1;
417:
418: // FilesBuf の最大数
419: static const int MaxFilesBuf = 32; // (適当)
420:
421: public:
422: WindrvDevice();
423: ~WindrvDevice() override;
424:
425: bool Create() override;
426: void SetLogLevel(int) override;
427: bool Init() override;
428: void ResetHard(bool poweron) override;
429:
430: busdata Read8(uint32 addr) override;
431: busdata Write8(uint32 addr, uint32 data) override;
432: busdata Peek8(uint32 addr) override;
433:
434: // Windrv を組み込むなら true を返す。
435: static bool IsWindrv();
436:
437: private:
438: uint32 GetIdent() const;
439: void Execute();
440: uint32 DispatchCommand();
441:
442: uint32 CmdInitialize();
443: uint32 CmdCheckDir(HostWindrv *);
444: uint32 CmdMakeDir(HostWindrv *);
445: uint32 CmdRemoveDir(HostWindrv *);
446: uint32 CmdRename(HostWindrv *);
447: uint32 CmdDelete(HostWindrv *);
448: uint32 CmdAttribute(HostWindrv *);
449: uint32 CmdFiles(HostWindrv *);
450: uint32 CmdNFiles(HostWindrv *);
451: uint32 CmdCreate(HostWindrv *);
452: uint32 CmdOpen(HostWindrv *);
453: uint32 CmdClose(HostWindrv *);
454: uint32 CmdRead(HostWindrv *);
455: uint32 CmdWrite(HostWindrv *);
456: uint32 CmdSeek(HostWindrv *);
457: uint32 CmdFileTime(HostWindrv *);
458: uint32 CmdGetCapacity(HostWindrv *);
459: uint32 CmdCtrlDrive(HostWindrv *);
460: uint32 CmdGetDPB(HostWindrv *);
461: uint32 CmdDiskRead(HostWindrv *);
462: uint32 CmdDiskWrite(HostWindrv *);
463: uint32 CmdIoControl(HostWindrv *);
464: uint32 CmdFlush(HostWindrv *);
465: uint32 CmdCheckMedia(HostWindrv *);
466: uint32 CmdLock(HostWindrv *);
467:
468: void SetResult(uint32);
469:
470: // result を表示用に整形して返す
471: static std::string ResultStr(uint32 result);
472:
473: // メモリアクセス
474: uint32 ReadMem8(uint32 addr) const;
475: void WriteMem8(uint32 addr, uint32 data);
476: uint32 ReadMem16(uint32 addr) const;
477: void WriteMem16(uint32 addr, uint32 data);
478: uint32 ReadMem32(uint32 addr) const;
479: void WriteMem32(uint32 addr, uint32 data);
480: uint32 ReadMemAddr(uint32 addr) const;
481: void WriteMemAddr(uint32 addr, uint32 data);
482: void ReadMem(void *dst, uint32 srcaddr, int len) const;
483: void WriteMem(uint32 dstaddr, const void *src, int len);
484:
485: uint32 FilesCommon(FilesBuf *, uint32 addr);
486: bool MatchFilename(const std::string& fname, const NAMESTS& ns) const;
487: static bool MatchWildcard(const std::string& fn, const std::string& pn);
488:
489: // addr に対応する FILES バッファを探す。
490: FilesBuf *SearchFilesBuf(uint32 addr) const;
491: // addr に対応する FILES バッファを作成して返す。
492: FilesBuf *AllocFilesBuf(uint32 addr, HostWindrv *);
493:
494: // addr に対応する FCB を探す。
495: Windrv::FCB *SearchFCB(uint32 addr) const;
496: // FCB を登録する。
497: uint32 AddFCB(const Windrv::FCB&);
498: // FCB を解放して削除する。
499: void FreeFCB(Windrv::FCB *);
500:
501: uint32 a5 {};
502: uint32 command {};
503:
504: // ログ表示用
505: std::string cmdname {};
506:
507: std::array<std::unique_ptr<HostWindrv>, MaxDrives> hosts /*{}*/;
508:
509: std::map<uint32, FilesBuf*> filesmap {};
510:
511: std::map<uint32, FCB*> fcbmap {};
512:
513: MainbusDevice *mainbus {};
514: MPU680x0Device *mpu680x0 {};
515: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.