Annotation of nono/vm/goldfish_tty.cpp, revision 1.1.1.6

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2024 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // Goldfish TTY
                      9: //
                     10: 
                     11: // レジスタ仕様は次の通り。
                     12: //  +$00.L PUT_CHAR            -W: 1バイト出力
                     13: //  +$04.L BYTES_READY R-: 受信キューにあるバイト数を取得
                     14: //  +$08.L COMMAND             -W: コマンド
                     15: //  +$0c.L -
                     16: //  +$10.L DATA_PTR            -W: DMA 開始アドレス
                     17: //  +$14.L DATA_LEN            -W: DMA データ長
                     18: //  +$18.L DATA_PTR_HIGH W: DMA 開始アドレスの上位 32 ビット
                     19: //  +$1c.L -
                     20: //  +$20.L VERSION             R-: このデバイスのバージョン ($1)
                     21: //
                     22: // コマンドは
                     23: //  $00 INT_DISABLE
                     24: //  $01 INT_ENABLE
                     25: //  $02 WRITE_BUFFER
                     26: //  $03 READ_BUFFER
                     27: //
                     28: // 受信キューにデータがあれば割り込みを上げる。
                     29: // 受信キューが空になると割り込みを下げる。
                     30: //
                     31: // WRITE_BUFFER, READ_BUFFER はたぶんバスマスタ的転送。
                     32: // 読み出し時 (READ_BUFFER) は、DATA_PTR で指定したアドレスにたぶん最大
                     33: // DATA_LEN バイトを GFTTY デバイスが書き込む。
                     34: // 書き込み時 (WRITE_BUFFER) は、DATA_PTR で指定したアドレスから DATA_LEN
                     35: // バイトを GFTTY デバイスが読み込む。
                     36: //
                     37: // nono では DATA_PTR_HIGH は実装しない。
                     38: 
                     39: #include "goldfish_tty.h"
                     40: #include "goldfish_pic.h"
                     41: #include "hostcom.h"
                     42: #include "mainbus.h"
                     43: #include "scheduler.h"
1.1.1.4   root       44: #include "syncer.h"
1.1       root       45: 
                     46: // コンストラクタ
                     47: GFTTYDevice::GFTTYDevice()
                     48:        : inherited(OBJ_GFTTY)
                     49: {
                     50: }
                     51: 
                     52: // デストラクタ
                     53: GFTTYDevice::~GFTTYDevice()
                     54: {
                     55:        if ((bool)hostcom) {
1.1.1.5   root       56:                hostcom->ResetRxCallback();
1.1       root       57:        }
                     58: }
                     59: 
                     60: bool
                     61: GFTTYDevice::Create()
                     62: {
                     63:        // 対応するホストドライバを作成
1.1.1.4   root       64:        try {
1.1.1.5   root       65:                hostcom.reset(new HostCOMDevice(this, 0, "GoldfishTTY"));
1.1.1.4   root       66:        } catch (...) { }
1.1       root       67:        if ((bool)hostcom == false) {
1.1.1.4   root       68:                warnx("Failed to initialize HostCOMDevice at %s", __method__);
1.1       root       69:                return false;
                     70:        }
1.1.1.5   root       71:        hostcom->SetRxCallback(ToDeviceCallback(&GFTTYDevice::HostRxCallback), 0);
1.1       root       72: 
                     73:        return true;
                     74: }
                     75: 
                     76: void
                     77: GFTTYDevice::SetLogLevel(int loglevel_)
                     78: {
                     79:        inherited::SetLogLevel(loglevel_);
                     80: 
1.1.1.4   root       81:        if ((bool)hostcom) {
                     82:                hostcom->SetLogLevel(loglevel_);
                     83:        }
1.1       root       84: }
                     85: 
                     86: // 初期化
                     87: bool
                     88: GFTTYDevice::Init()
                     89: {
                     90:        mainbus = GetMainbusDevice();
                     91: 
                     92:        gfpic = GetGFPICDevice(1);
                     93:        gfpic->RegistIRQ(32, "GFTTY", this);
                     94: 
1.1.1.5   root       95:        scheduler->ConnectMessage(MessageID::HOSTCOM0_RX, this,
1.1       root       96:                ToMessageCallback(&GFTTYDevice::RxMessage));
                     97:        return true;
                     98: }
                     99: 
                    100: // 電源オン/リセット
                    101: void
                    102: GFTTYDevice::ResetHard(bool poweron)
                    103: {
1.1.1.4   root      104:        sesame_idx = 0;
1.1       root      105:        rxq.clear();
                    106:        intr_enable = false;
                    107:        ChangeInterrupt();
                    108: }
                    109: 
                    110: busdata
1.1.1.2   root      111: GFTTYDevice::ReadPort(uint32 offset)
1.1       root      112: {
                    113:        busdata data;
                    114: 
                    115:        switch (offset) {
                    116:         case BYTES_READY:
1.1.1.2   root      117:                data = GetREADY();
                    118:                putlog(2, "BYTES_READY -> $%08x", data.Data());
1.1       root      119:                break;
                    120: 
                    121:         case VERSION:
1.1.1.2   root      122:                data = GFTTYVersion;
1.1       root      123:                putlog(2, "VERSION -> $%08x", data.Data());
                    124:                break;
                    125: 
                    126:         default:
1.1.1.6 ! root      127:                putlog(1, "Read $%08x.L", mainbus->GetPaddr());
1.1       root      128:                data.SetBusErr();
                    129:                break;
                    130:        }
                    131: 
1.1.1.2   root      132:        data |= BusData::Size4;
1.1       root      133:        return data;
                    134: }
                    135: 
                    136: busdata
1.1.1.2   root      137: GFTTYDevice::WritePort(uint32 offset, uint32 data)
1.1       root      138: {
                    139:        busdata r;
                    140: 
                    141:        switch (offset) {
                    142:         case PUT_CHAR:
                    143:                putlog(2, "PUT_CHAR <- $%02x", data);
1.1.1.4   root      144:                Tx(data);
1.1       root      145:                break;
                    146: 
                    147:         case COMMAND:
                    148:                Command(data);
                    149:                break;
                    150: 
                    151:         case DATA_PTR:
                    152:                putlog(2, "DATA_PTR <- $%08x", data);
                    153:                dma_ptr = data;
                    154:                break;
                    155: 
                    156:         case DATA_LEN:
                    157:                putlog(2, "DATA_LEN <- $%08x", data);
                    158:                dma_len = data;
                    159:                break;
                    160: 
                    161:         default:
1.1.1.6 ! root      162:                putlog(1, "Write $%08x.L", mainbus->GetPaddr());
1.1       root      163:                r.SetBusErr();
                    164:                break;
                    165:        }
1.1.1.2   root      166: 
                    167:        r |= BusData::Size4;
1.1       root      168:        return r;
                    169: }
                    170: 
                    171: busdata
1.1.1.2   root      172: GFTTYDevice::PeekPort(uint32 offset)
                    173: {
                    174:        switch (offset) {
                    175:         case BYTES_READY:
                    176:                return GetREADY();
                    177:         case VERSION:
                    178:                return GFTTYVersion;
                    179:         default:
                    180:                return BusData::BusErr;
                    181:        }
                    182: }
                    183: 
                    184: // 着信しているバイト数を返す。
                    185: uint32
                    186: GFTTYDevice::GetREADY() const
1.1       root      187: {
1.1.1.2   root      188:        return rxq.size();
1.1       root      189: }
                    190: 
                    191: void
                    192: GFTTYDevice::Command(uint32 cmd)
                    193: {
                    194:        switch (cmd) {
                    195:         case CMD_INT_DISABLE:
                    196:                putlog(1, "CMD_INT_DISABLE");
                    197:                intr_enable = false;
                    198:                ChangeInterrupt();
                    199:                break;
                    200: 
                    201:         case CMD_INT_ENABLE:
                    202:                putlog(1, "CMD_INT_ENABLE");
                    203:                intr_enable = true;
                    204:                ChangeInterrupt();
                    205:                break;
                    206: 
                    207:         case CMD_WRITE_BUFFER:
                    208:         {
                    209:                // ゲストからの書き込み
                    210:                putlog(1, "CMD_WRITE_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
                    211:                uint32 addr = dma_ptr;
                    212:                uint32 end = addr + dma_len;
                    213:                for (; addr < end; addr++) {
1.1.1.2   root      214:                        busdata data = mainbus->HVRead1(addr);
1.1       root      215:                        if (data.IsBusErr()) {
                    216:                                putlog(1, "WRITE_BUFFER: BusError at $%08x", addr);
                    217:                                break;
                    218:                        }
1.1.1.4   root      219:                        Tx(data);
1.1       root      220:                }
                    221:                break;
                    222:         }
                    223: 
                    224:         case CMD_READ_BUFFER:
                    225:         {
                    226:                // ゲストからの読み込み (ゲスト空間へ書き出し)
                    227:                putlog(1, "CMD_READ_BUFFER($%08x, $%08x)", dma_ptr, dma_len);
                    228:                uint32 addr = dma_ptr;
                    229:                uint32 len = std::min(dma_len, (uint32)rxq.size());
                    230:                for (uint32 end = addr + len; addr < end; addr++) {
                    231:                        uint32 data = rxq.front();
                    232:                        rxq.pop_front();
1.1.1.2   root      233:                        busdata bd = mainbus->HVWrite1(addr, data);
1.1       root      234:                        if (bd.IsBusErr()) {
                    235:                                putlog(1, "READ_BUFFER: BusError at $%08x", addr);
                    236:                                break;
                    237:                        }
                    238:                }
                    239:                ChangeInterrupt();
                    240:                break;
                    241:         }
                    242: 
                    243:         default:
                    244:                putlog(1, "Unknown command $%08x", cmd);
                    245:                break;
                    246:        }
                    247: }
                    248: 
1.1.1.4   root      249: // 1バイト送信。
                    250: void
                    251: GFTTYDevice::Tx(uint32 data)
                    252: {
1.1.1.6 ! root      253:        // --perf によるパフォーマンス測定用のギミック。
1.1.1.4   root      254:        // GFTTY に特定の文字列を書き込むと、
                    255:        // VM 電源オン時から現在までの実時間をログに出力する。NetBSD の
                    256:        // マルチユーザブートがあらかた終わってログインプロンプトが出る手前の
                    257:        // /etc/rc.local に
                    258:        //
                    259:        // printf '\e[?68008h\e[?68008l'
                    260:        //
                    261:        // と書いておくことで、ここまでにかかる時間を表示できる。
                    262:        // この値はホスト性能に依存するため、同一環境下での相対比較のみ可能。
                    263:        //
                    264:        // このエスケープシーケンスは DEC/xterm 拡張の設定と解除を続けて行う
                    265:        // もので、68008 は空いてそうな適当な値。知らない番号の拡張機能については
                    266:        // おそらく黙って何もしないだけだと思うので、どの端末エミュレータを通過
                    267:        // しても副作用は少ないと思われる。
                    268:        static const char sesame[] = "\x1b[?68008h\x1b[?68008l";
                    269:        if (__predict_false(data == sesame[sesame_idx])) {
                    270:                sesame_idx++;
                    271:                if (__predict_false(sesame_idx >= strlen(sesame))) {
                    272:                        GetSyncer()->PutlogRealtime();
                    273:                        sesame_idx = 0;
                    274:                }
                    275:        } else {
                    276:                sesame_idx = 0;
                    277:        }
                    278: 
                    279:        // 1バイト送信。
                    280:        hostcom->Tx(data);
                    281: }
                    282: 
1.1       root      283: void
                    284: GFTTYDevice::ChangeInterrupt()
                    285: {
                    286:        bool irq = (intr_enable && rxq.empty() == false);
                    287:        gfpic->ChangeINT(this, irq);
                    288: }
                    289: 
                    290: // ホストスレッドからの受信通知
                    291: // (HostCOM スレッドで呼ばれる)
                    292: void
1.1.1.5   root      293: GFTTYDevice::HostRxCallback(uint32 dummy)
1.1       root      294: {
1.1.1.5   root      295:        scheduler->SendMessage(MessageID::HOSTCOM0_RX);
1.1       root      296: }
                    297: 
                    298: // ホストシリアルからの1バイト(以上)受信メッセージ
                    299: // (VM スレッドで呼ばれる)
                    300: void
                    301: GFTTYDevice::RxMessage(MessageID msgid, uint32 arg)
                    302: {
                    303:        bool recv = false;
                    304: 
                    305:        for (;;) {
                    306:                uint32 data = hostcom->Rx();
                    307:                if ((int32)data < 0) {
                    308:                        break;
                    309:                }
                    310:                rxq.push_back(data);
                    311:                recv = true;
                    312:        }
                    313: 
                    314:        if (recv) {
                    315:                ChangeInterrupt();
                    316:        }
                    317: }

unix.superglobalmegacorp.com

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