From 52b6e5d77c741beef767d27264a81cccc9780af9 Mon Sep 17 00:00:00 2001 From: t3tra-dev Date: Thu, 19 Jun 2025 11:55:09 +0900 Subject: [PATCH 1/2] feat(proc): process table, `posix_spawn()`, scheduler, and IPC --- PROGRESS.md | 53 +++--- build.ninja | 7 +- kernel/include/init.h | 3 + kernel/include/ipc.h | 87 ++++++++++ kernel/include/process.h | 115 +++++++++++++ kernel/init/main.c | 36 +++- kernel/ipc/ipc.c | 260 +++++++++++++++++++++++++++++ kernel/ipc/pipe.c | 308 ++++++++++++++++++++++++++++++++++ kernel/lib/stdio.c | 176 ++++++++++++++++--- kernel/process/process.c | 334 +++++++++++++++++++++++++++++++++++++ kernel/process/scheduler.c | 239 ++++++++++++++++++++++++++ kernel/process/spawn.c | 238 ++++++++++++++++++++++++++ kernel/shell/shell.c | 105 +++++++++++- 13 files changed, 1910 insertions(+), 51 deletions(-) create mode 100644 kernel/include/ipc.h create mode 100644 kernel/include/process.h create mode 100644 kernel/ipc/ipc.c create mode 100644 kernel/ipc/pipe.c create mode 100644 kernel/process/process.c create mode 100644 kernel/process/scheduler.c create mode 100644 kernel/process/spawn.c diff --git a/PROGRESS.md b/PROGRESS.md index 84ee980..5b77e16 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -42,19 +42,36 @@ - `help` - ヘルプ表示 - `clear` - 画面クリア - `echo` - テキスト出力 - - `ps` - プロセス一覧 (スタブ) + - `ps` - プロセス一覧 + - `kill` - プロセス終了 + - `spawn` - テストプロセス生成 - `ls` - ファイル一覧 (スタブ) - `cat` - ファイル表示 (スタブ) - `about` - システム情報 - `exit` - 終了 -#### 6. GUI/ブラウザ統合 +#### 6. プロセス管理 +- [x] プロセステーブルの実装 + - [x] プロセス制御ブロック (PCB) + - [x] 最大64プロセスのサポート + - [x] プロセス状態管理 (UNUSED, INIT, READY, RUNNING, WAITING, ZOMBIE, TERMINATED) +- [x] `posix_spawn` 実装 (fork()の代替) +- [x] プロセススケジューラー + - [x] ラウンドロビンスケジューリング + - [x] レディキュー管理 + - [x] 協調的マルチタスキング (WebAssembly制約) +- [x] プロセス間通信 (IPC) + - [x] メッセージパッシング + - [x] パイプ実装 + - [x] ブロッキング/ノンブロッキング操作 + +#### 7. GUI/ブラウザ統合 - [x] ターミナルウィンドウ UI - [x] ウィンドウマネージャー (ドラッグ、最大化) - [x] stdin/stdout のブラウザ統合 - [x] コマンドハンドラー経由の入力処理 -#### 7. ビルドシステム +#### 8. ビルドシステム - [x] Ninja ビルドシステム - [x] TypeScript/JavaScript モジュール構造 - [x] CSS分離 @@ -63,27 +80,21 @@ ### 高優先度 -#### 1. プロセス管理 -- [ ] プロセステーブルの実装 -- [ ] `fork()` の代替実装 (`posix_spawn`) -- [ ] プロセススケジューラー -- [ ] プロセス間通信 (IPC) - -#### 2. ファイルシステム +#### 1. ファイルシステム - [ ] 実際のファイルシステム実装 - [ ] IndexedDB バックエンド - [ ] ディレクトリ操作 (mkdir, rmdir) - [ ] ファイル操作 (open, read, write, close) - [ ] パーミッション管理 -#### 3. ネットワーク +#### 2. ネットワーク - [ ] ソケット API の実装 - [ ] WebSocket ベースのネットワーク層 - [ ] 基本的なネットワークコマンド (ping, wget 相当) ### 中優先度 -#### 4. シェル拡張 +#### 3. シェル拡張 - [ ] パイプ機能 - [ ] リダイレクト - [ ] 環境変数 @@ -91,12 +102,12 @@ - [ ] コマンド履歴 - [ ] タブ補完 -#### 5. デバイスドライバ +#### 4. デバイスドライバ - [ ] キーボードドライバ (詳細な入力処理) - [ ] マウスドライバ - [ ] フレームバッファドライバ (グラフィックス) -#### 6. 標準ユーティリティ +#### 5. 標準ユーティリティ - [ ] 基本的なUNIXコマンド群 - [ ] `cp`, `mv`, `rm` - [ ] `grep`, `sed`, `awk` @@ -104,13 +115,13 @@ ### 低優先度 -#### 7. 高度な機能 +#### 6. 高度な機能 - [ ] マルチスレッド (pthread) - [ ] 共有ライブラリ - [ ] デバッガー - [ ] パッケージマネージャー -#### 8. パフォーマンス最適化 +#### 7. パフォーマンス最適化 - [ ] メモリ管理の最適化 - [ ] ファイルシステムキャッシュ - [ ] コンパイラ最適化 @@ -126,7 +137,6 @@ - procfs の完全な実装が必要 (`kernel/fs/vfs.c:183`) 3. **標準ライブラリ** - - 可変引数の処理が未実装 (`kernel/lib/stdio.c:95-96, 103-104`) - 数値変換が未実装 (`kernel/drivers/console.c:111`) 4. **ドライバ** @@ -154,7 +164,8 @@ ## 次のステップ -1. プロセス管理の基本実装を開始 -2. 実際のファイルシステムの実装 -3. より多くのシェルコマンドの追加 -4. テストスイートの作成 +1. 実際のファイルシステムの実装 (IndexedDB バックエンド) +2. プロセス管理の高度な機能 (シグナル、wait/waitpid) +3. シェルのパイプとリダイレクト機能 +4. より多くのUNIXコマンドの実装 +5. テストスイートの作成 diff --git a/build.ninja b/build.ninja index 5f5ea14..d09fb57 100644 --- a/build.ninja +++ b/build.ninja @@ -18,9 +18,14 @@ build build/kernel/lib/stdio.o: CC kernel/lib/stdio.c build build/kernel/lib/wasi_wrapper.o: CC kernel/lib/wasi_wrapper.c build build/kernel/shell/shell.o: CC kernel/shell/shell.c build build/kernel/shell/shell_api.o: CC kernel/shell/shell_api.c +build build/kernel/process/process.o: CC kernel/process/process.c +build build/kernel/process/scheduler.o: CC kernel/process/scheduler.c +build build/kernel/process/spawn.o: CC kernel/process/spawn.c +build build/kernel/ipc/ipc.o: CC kernel/ipc/ipc.c +build build/kernel/ipc/pipe.o: CC kernel/ipc/pipe.c # カーネルリンク -build build/kernel.wasm: LD build/kernel/init/main.o build/kernel/mm/memory.o build/kernel/fs/vfs.o build/kernel/drivers/console.o build/kernel/drivers/drivers.o build/kernel/lib/string.o build/kernel/lib/stdio.o build/kernel/lib/wasi_wrapper.o build/kernel/shell/shell.o build/kernel/shell/shell_api.o +build build/kernel.wasm: LD build/kernel/init/main.o build/kernel/mm/memory.o build/kernel/fs/vfs.o build/kernel/drivers/console.o build/kernel/drivers/drivers.o build/kernel/lib/string.o build/kernel/lib/stdio.o build/kernel/lib/wasi_wrapper.o build/kernel/shell/shell.o build/kernel/shell/shell_api.o build/kernel/process/process.o build/kernel/process/scheduler.o build/kernel/process/spawn.o build/kernel/ipc/ipc.o build/kernel/ipc/pipe.o # GUI とシステムライブラリ build build/index.html: COPY gui/index.html diff --git a/kernel/include/init.h b/kernel/include/init.h index 11ddf6d..5cc07b9 100644 --- a/kernel/include/init.h +++ b/kernel/include/init.h @@ -9,6 +9,9 @@ int mm_init(void); /* メモリ管理初期化 */ int fs_init(void); /* ファイルシステム初期化 */ int drivers_init(void); /* デバイスドライバ初期化 */ +int process_init(void); /* プロセス管理初期化 */ +void scheduler_init(void); /* スケジューラ初期化 */ +int ipc_init(void); /* IPC初期化 */ /* 初期化順序定義 */ #define INIT_LEVEL_EARLY 0 diff --git a/kernel/include/ipc.h b/kernel/include/ipc.h new file mode 100644 index 0000000..5523e6f --- /dev/null +++ b/kernel/include/ipc.h @@ -0,0 +1,87 @@ +/* + * WebVM プロセス間通信 (IPC) ヘッダ + */ + +#ifndef __WEBVM_IPC_H__ +#define __WEBVM_IPC_H__ + +#include +#include +#include "process.h" + +/* IPC定数 */ +#define MAX_MESSAGE_SIZE 1024 +#define MAX_MESSAGES_PER_PROCESS 16 + +/* メッセージタイプ */ +typedef enum { + MSG_TYPE_DATA = 0, /* データメッセージ */ + MSG_TYPE_SIGNAL, /* シグナル */ + MSG_TYPE_PIPE, /* パイプデータ */ + MSG_TYPE_SHARED_MEM /* 共有メモリ通知 */ +} message_type_t; + +/* メッセージ構造体 */ +struct ipc_message { + pid_t sender_pid; /* 送信者PID */ + pid_t receiver_pid; /* 受信者PID */ + message_type_t type; /* メッセージタイプ */ + size_t size; /* データサイズ */ + void *data; /* データポインタ */ + uint64_t timestamp; /* タイムスタンプ */ + struct ipc_message *next; /* 次のメッセージ */ +}; + +/* メッセージキュー */ +struct message_queue { + struct ipc_message *head; + struct ipc_message *tail; + uint32_t count; + uint32_t max_messages; +}; + +/* パイプ構造体 */ +struct pipe { + char *buffer; /* バッファ */ + size_t size; /* バッファサイズ */ + size_t read_pos; /* 読み込み位置 */ + size_t write_pos; /* 書き込み位置 */ + pid_t reader_pid; /* 読み込みプロセス */ + pid_t writer_pid; /* 書き込みプロセス */ + bool closed_read; /* 読み込み側クローズ */ + bool closed_write; /* 書き込み側クローズ */ +}; + +/* 共有メモリセグメント */ +struct shared_memory { + void *address; /* メモリアドレス */ + size_t size; /* サイズ */ + uint32_t ref_count; /* 参照カウント */ + pid_t owner_pid; /* 所有者PID */ + uint32_t flags; /* フラグ */ +}; + +/* IPC初期化 */ +int ipc_init(void); + +/* メッセージ送受信 */ +int ipc_send_message(pid_t to_pid, const void *data, size_t size, message_type_t type); +int ipc_receive_message(struct ipc_message **msg, bool blocking); +void ipc_free_message(struct ipc_message *msg); + +/* パイプ操作 */ +int ipc_create_pipe(int *read_fd, int *write_fd); +int ipc_pipe_read(int fd, void *buf, size_t count); +int ipc_pipe_write(int fd, const void *buf, size_t count); +int ipc_pipe_close(int fd); + +/* 共有メモリ */ +void *ipc_create_shared_memory(size_t size); +void *ipc_attach_shared_memory(int shmid); +int ipc_detach_shared_memory(void *addr); +int ipc_destroy_shared_memory(int shmid); + +/* デバッグ */ +void ipc_dump_queues(void); + +#endif /* __WEBVM_IPC_H__ */ \ No newline at end of file diff --git a/kernel/include/process.h b/kernel/include/process.h new file mode 100644 index 0000000..15f6592 --- /dev/null +++ b/kernel/include/process.h @@ -0,0 +1,115 @@ +/* + * WebVM プロセス管理ヘッダ + */ + +#ifndef __WEBVM_PROCESS_H__ +#define __WEBVM_PROCESS_H__ + +#include +#include +#include + +/* プロセス定数 */ +#define MAX_PROCESSES 64 +#define MAX_PROCESS_NAME 32 +#define PROCESS_STACK_SIZE (64 * 1024) /* 64KB スタック */ + +/* プロセス状態 */ +typedef enum { + PROCESS_STATE_UNUSED = 0, + PROCESS_STATE_INIT, + PROCESS_STATE_READY, + PROCESS_STATE_RUNNING, + PROCESS_STATE_WAITING, + PROCESS_STATE_ZOMBIE, + PROCESS_STATE_TERMINATED +} process_state_t; + +/* プロセスID型 */ +typedef int32_t pid_t; + +/* プロセスコンテキスト (WebAssembly制約下での簡易版) */ +struct process_context { + void *stack_ptr; /* スタックポインタ */ + void *pc; /* プログラムカウンタ (関数ポインタ) */ + uint32_t flags; /* フラグ */ +}; + +/* プロセス制御ブロック (PCB) */ +struct process { + pid_t pid; /* プロセスID */ + pid_t ppid; /* 親プロセスID */ + char name[MAX_PROCESS_NAME]; /* プロセス名 */ + process_state_t state; /* プロセス状態 */ + + /* メモリ管理 */ + void *stack_base; /* スタックベースアドレス */ + size_t stack_size; /* スタックサイズ */ + void *heap_base; /* ヒープベースアドレス */ + size_t heap_size; /* ヒープサイズ */ + + /* コンテキスト */ + struct process_context context; /* プロセスコンテキスト */ + + /* エントリポイント */ + int (*entry)(int argc, char **argv); /* プロセスエントリポイント */ + int argc; /* 引数カウント */ + char **argv; /* 引数配列 */ + + /* 終了情報 */ + int exit_code; /* 終了コード */ + + /* 統計情報 */ + uint64_t start_time; /* 開始時刻 */ + uint64_t cpu_time; /* CPU使用時間 */ + + /* リンクリスト */ + struct process *next; /* 次のプロセス */ + struct process *prev; /* 前のプロセス */ +}; + +/* プロセステーブル */ +struct process_table { + struct process processes[MAX_PROCESSES]; + struct process *current; /* 現在実行中のプロセス */ + struct process *ready_list; /* 実行可能プロセスリスト */ + pid_t next_pid; /* 次のPID */ + uint32_t process_count; /* プロセス数 */ +}; + +/* プロセス管理関数 */ +int process_init(void); +pid_t process_create(const char *name, int (*entry)(int, char**), int argc, char **argv); +int process_exit(int exit_code); +int process_wait(pid_t pid); +int process_kill(pid_t pid, int signal); +struct process *process_get_current(void); +struct process *process_find(pid_t pid); + +/* スケジューラ関数 */ +void scheduler_init(void); +void scheduler_tick(void); +void scheduler_yield(void); +void scheduler_add_ready(struct process *proc); +void scheduler_remove_ready(struct process *proc); + +/* POSIX spawn API */ +typedef struct { + int flags; + /* 将来的な拡張用 */ +} posix_spawnattr_t; + +typedef struct { + char **argv; + char **envp; +} posix_spawn_file_actions_t; + +int posix_spawn(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]); + +/* デバッグ関数 */ +void process_dump_table(void); + +#endif /* __WEBVM_PROCESS_H__ */ \ No newline at end of file diff --git a/kernel/init/main.c b/kernel/init/main.c index b64063a..bfc9a4e 100644 --- a/kernel/init/main.c +++ b/kernel/init/main.c @@ -59,6 +59,24 @@ static int kernel_init(void) { } kputs("[INIT] Device drivers initialized"); + /* プロセス管理の初期化 */ + if (process_init() < 0) { + kfprintf(STDERR_FILENO, "[INIT] Failed to initialize process management\n"); + return -1; + } + kputs("[INIT] Process management initialized"); + + /* スケジューラの初期化 */ + scheduler_init(); + kputs("[INIT] Scheduler initialized"); + + /* IPC初期化 */ + if (ipc_init() < 0) { + kfprintf(STDERR_FILENO, "[INIT] Failed to initialize IPC\n"); + return -1; + } + kputs("[INIT] IPC initialized"); + kernel_initialized = 1; kputs("[INIT] Kernel initialization complete"); @@ -74,11 +92,17 @@ static void kernel_main_loop(void) { /* ここでシェルまたは init プロセスを起動する */ kputs("[KERNEL] Starting shell..."); - /* シェルを起動 */ + /* + * シェルを起動 + * 注意: 現在はWebAssemblyの制約により、シェルは + * カーネルコンテキストで実行される + */ shell_main(); - /* シェルが終了した場合 (通常は到達しない) */ - kputs("[KERNEL] Shell exited, halting system..."); + /* + * シェルは初期化後すぐに戻り、実際のコマンド処理は + * JavaScriptからのhandle_command呼び出しで行われる + */ } /** @@ -99,8 +123,10 @@ void kernel_main(void) { /* メインループ */ kernel_main_loop(); - kputs("[DEBUG] kernel_main() finished"); - wasi_exit(0); + /* + * WebAssemblyでは実際にはここに到達しない + * handle_commandがJavaScriptから呼ばれるのを待つ + */ } /** diff --git a/kernel/ipc/ipc.c b/kernel/ipc/ipc.c new file mode 100644 index 0000000..255efd8 --- /dev/null +++ b/kernel/ipc/ipc.c @@ -0,0 +1,260 @@ +/* + * WebVM プロセス間通信 (IPC) 実装 + */ + +#include "../include/ipc.h" +#include "../include/kernel.h" +#include "../include/mm.h" +#include "../include/wasi_syscalls.h" + +/* 外部関数宣言 */ +int kprintf(const char *format, ...); + +/* 文字列関数 */ +static void *memcpy(void *dest, const void *src, size_t n) { + unsigned char *d = dest; + const unsigned char *s = src; + while (n--) { + *d++ = *s++; + } + return dest; +} + +/* グローバルメッセージキューテーブル */ +static struct { + struct message_queue queues[MAX_PROCESSES]; + bool initialized; +} ipc_state = { + .initialized = false +}; + +/** + * IPC初期化 + */ +int ipc_init(void) { + kprintf("[IPC] Initializing IPC subsystem...\n"); + + /* 全プロセスのメッセージキューを初期化 */ + for (int i = 0; i < MAX_PROCESSES; i++) { + ipc_state.queues[i].head = NULL; + ipc_state.queues[i].tail = NULL; + ipc_state.queues[i].count = 0; + ipc_state.queues[i].max_messages = MAX_MESSAGES_PER_PROCESS; + } + + ipc_state.initialized = true; + kprintf("[IPC] IPC subsystem initialized\n"); + + return 0; +} + +/** + * メッセージをキューに追加 + */ +static int enqueue_message(pid_t pid, struct ipc_message *msg) { + struct message_queue *queue; + + if (pid < 0 || pid >= MAX_PROCESSES) { + return -1; + } + + queue = &ipc_state.queues[pid]; + + /* キューが満杯かチェック */ + if (queue->count >= queue->max_messages) { + kprintf("[IPC] Message queue full for process %d\n", pid); + return -1; + } + + /* キューに追加 */ + msg->next = NULL; + if (queue->tail) { + queue->tail->next = msg; + } else { + queue->head = msg; + } + queue->tail = msg; + queue->count++; + + return 0; +} + +/** + * メッセージをキューから取り出し + */ +static struct ipc_message *dequeue_message(pid_t pid) { + struct message_queue *queue; + struct ipc_message *msg; + + if (pid < 0 || pid >= MAX_PROCESSES) { + return NULL; + } + + queue = &ipc_state.queues[pid]; + + /* キューが空かチェック */ + if (queue->head == NULL) { + return NULL; + } + + /* 先頭から取り出し */ + msg = queue->head; + queue->head = msg->next; + if (queue->head == NULL) { + queue->tail = NULL; + } + queue->count--; + + msg->next = NULL; + return msg; +} + +/** + * メッセージ送信 + */ +int ipc_send_message(pid_t to_pid, const void *data, size_t size, message_type_t type) { + struct ipc_message *msg; + struct process *sender; + struct process *receiver; + + if (!ipc_state.initialized) { + kprintf("[IPC] IPC not initialized\n"); + return -1; + } + + /* 送信者と受信者を確認 */ + sender = process_get_current(); + if (sender == NULL) { + return -1; + } + + receiver = process_find(to_pid); + if (receiver == NULL) { + kprintf("[IPC] Process %d not found\n", to_pid); + return -1; + } + + /* メッセージを割り当て */ + msg = (struct ipc_message *)kmalloc(sizeof(struct ipc_message)); + if (msg == NULL) { + kprintf("[IPC] Failed to allocate message\n"); + return -1; + } + + /* データをコピー */ + if (size > 0 && data != NULL) { + msg->data = kmalloc(size); + if (msg->data == NULL) { + kfree(msg); + return -1; + } + memcpy(msg->data, data, size); + } else { + msg->data = NULL; + } + + /* メッセージ情報を設定 */ + msg->sender_pid = sender->pid; + msg->receiver_pid = to_pid; + msg->type = type; + msg->size = size; + msg->timestamp = wasi_get_time_ns(); + msg->next = NULL; + + /* キューに追加 */ + if (enqueue_message(to_pid, msg) < 0) { + if (msg->data) { + kfree(msg->data); + } + kfree(msg); + return -1; + } + + kprintf("[IPC] Message sent from %d to %d (type=%d, size=%zu)\n", + sender->pid, to_pid, type, size); + + /* 受信プロセスを起床 (TODO: 実装) */ + if (receiver->state == PROCESS_STATE_WAITING) { + receiver->state = PROCESS_STATE_READY; + scheduler_add_ready(receiver); + } + + return 0; +} + +/** + * メッセージ受信 + */ +int ipc_receive_message(struct ipc_message **msg, bool blocking) { + struct process *current; + struct ipc_message *received; + + if (!ipc_state.initialized || msg == NULL) { + return -1; + } + + current = process_get_current(); + if (current == NULL) { + return -1; + } + + while (1) { + /* メッセージを取り出し */ + received = dequeue_message(current->pid); + if (received != NULL) { + *msg = received; + kprintf("[IPC] Process %d received message from %d\n", + current->pid, received->sender_pid); + return 0; + } + + /* ノンブロッキングモードの場合は即座に返る */ + if (!blocking) { + *msg = NULL; + return 0; + } + + /* ブロッキングモードの場合は待機 */ + kprintf("[IPC] Process %d waiting for message\n", current->pid); + current->state = PROCESS_STATE_WAITING; + scheduler_yield(); + } +} + +/** + * メッセージを解放 + */ +void ipc_free_message(struct ipc_message *msg) { + if (msg == NULL) { + return; + } + + if (msg->data) { + kfree(msg->data); + } + kfree(msg); +} + +/** + * メッセージキューをダンプ (デバッグ用) + */ +void ipc_dump_queues(void) { + kprintf("[IPC] Message queue dump:\n"); + kprintf("PID COUNT MESSAGES\n"); + kprintf("--- ----- --------\n"); + + for (int i = 0; i < MAX_PROCESSES; i++) { + struct message_queue *queue = &ipc_state.queues[i]; + if (queue->count > 0) { + kprintf("%-3d %-5d ", i, queue->count); + + struct ipc_message *msg = queue->head; + while (msg) { + kprintf("(from:%d,type:%d,size:%zu) ", + msg->sender_pid, msg->type, msg->size); + msg = msg->next; + } + kprintf("\n"); + } + } +} \ No newline at end of file diff --git a/kernel/ipc/pipe.c b/kernel/ipc/pipe.c new file mode 100644 index 0000000..d4f4679 --- /dev/null +++ b/kernel/ipc/pipe.c @@ -0,0 +1,308 @@ +/* + * WebVM パイプ実装 + */ + +#include "../include/ipc.h" +#include "../include/kernel.h" +#include "../include/mm.h" +#include "../include/process.h" + +/* 外部関数宣言 */ +int kprintf(const char *format, ...); + +/* 文字列関数 */ +static void *memcpy(void *dest, const void *src, size_t n) { + unsigned char *d = dest; + const unsigned char *s = src; + while (n--) { + *d++ = *s++; + } + return dest; +} + +static size_t min(size_t a, size_t b) { + return a < b ? a : b; +} + +/* パイプ定数 */ +#define PIPE_BUFFER_SIZE 4096 +#define MAX_PIPES 32 + +/* パイプファイルディスクリプタのベース */ +#define PIPE_FD_BASE 100 + +/* パイプテーブル */ +static struct { + struct pipe pipes[MAX_PIPES]; + bool used[MAX_PIPES]; + int next_fd; +} pipe_table = { + .next_fd = PIPE_FD_BASE +}; + +/** + * 空きパイプスロットを探す + */ +static int find_free_pipe(void) { + for (int i = 0; i < MAX_PIPES; i++) { + if (!pipe_table.used[i]) { + return i; + } + } + return -1; +} + +/** + * ファイルディスクリプタからパイプインデックスを取得 + */ +static int fd_to_pipe_index(int fd) { + if (fd < PIPE_FD_BASE || fd >= PIPE_FD_BASE + MAX_PIPES) { + return -1; + } + return fd - PIPE_FD_BASE; +} + +/** + * パイプを作成 + */ +int ipc_create_pipe(int *read_fd, int *write_fd) { + struct pipe *pipe; + struct process *current; + int index; + + if (read_fd == NULL || write_fd == NULL) { + return -1; + } + + /* 空きスロットを探す */ + index = find_free_pipe(); + if (index < 0) { + kprintf("[PIPE] No free pipe slots\n"); + return -1; + } + + /* 現在のプロセスを取得 */ + current = process_get_current(); + if (current == NULL) { + return -1; + } + + /* パイプを初期化 */ + pipe = &pipe_table.pipes[index]; + pipe->buffer = kmalloc(PIPE_BUFFER_SIZE); + if (pipe->buffer == NULL) { + kprintf("[PIPE] Failed to allocate pipe buffer\n"); + return -1; + } + + pipe->size = PIPE_BUFFER_SIZE; + pipe->read_pos = 0; + pipe->write_pos = 0; + pipe->reader_pid = current->pid; + pipe->writer_pid = current->pid; + pipe->closed_read = false; + pipe->closed_write = false; + + pipe_table.used[index] = true; + + /* ファイルディスクリプタを設定 */ + *read_fd = PIPE_FD_BASE + index; + *write_fd = PIPE_FD_BASE + index; /* 簡略化のため同じFDを使用 */ + + kprintf("[PIPE] Created pipe: read_fd=%d, write_fd=%d\n", *read_fd, *write_fd); + + return 0; +} + +/** + * パイプから読み込み + */ +int ipc_pipe_read(int fd, void *buf, size_t count) { + struct pipe *pipe; + struct process *current; + int index; + size_t available, to_read; + + if (buf == NULL || count == 0) { + return 0; + } + + /* パイプインデックスを取得 */ + index = fd_to_pipe_index(fd); + if (index < 0 || !pipe_table.used[index]) { + kprintf("[PIPE] Invalid pipe fd: %d\n", fd); + return -1; + } + + pipe = &pipe_table.pipes[index]; + + /* 読み込み側がクローズされているかチェック */ + if (pipe->closed_read) { + kprintf("[PIPE] Pipe read end closed\n"); + return -1; + } + + /* 現在のプロセスを確認 */ + current = process_get_current(); + if (current == NULL) { + return -1; + } + + /* データが利用可能になるまで待機 */ + while (1) { + /* 利用可能なデータ量を計算 */ + if (pipe->write_pos >= pipe->read_pos) { + available = pipe->write_pos - pipe->read_pos; + } else { + available = pipe->size - pipe->read_pos + pipe->write_pos; + } + + /* データがある場合は読み込み */ + if (available > 0) { + to_read = min(count, available); + + /* リングバッファから読み込み */ + if (pipe->read_pos + to_read <= pipe->size) { + memcpy(buf, pipe->buffer + pipe->read_pos, to_read); + pipe->read_pos = (pipe->read_pos + to_read) % pipe->size; + } else { + /* バッファの終端をまたぐ場合 */ + size_t first_part = pipe->size - pipe->read_pos; + memcpy(buf, pipe->buffer + pipe->read_pos, first_part); + memcpy((char *)buf + first_part, pipe->buffer, to_read - first_part); + pipe->read_pos = to_read - first_part; + } + + return to_read; + } + + /* 書き込み側がクローズされている場合はEOF */ + if (pipe->closed_write) { + return 0; + } + + /* データを待機 */ + kprintf("[PIPE] Process %d waiting for pipe data\n", current->pid); + current->state = PROCESS_STATE_WAITING; + scheduler_yield(); + } +} + +/** + * パイプに書き込み + */ +int ipc_pipe_write(int fd, const void *buf, size_t count) { + struct pipe *pipe; + struct process *current; + struct process *reader; + int index; + size_t available, to_write; + + if (buf == NULL || count == 0) { + return 0; + } + + /* パイプインデックスを取得 */ + index = fd_to_pipe_index(fd); + if (index < 0 || !pipe_table.used[index]) { + kprintf("[PIPE] Invalid pipe fd: %d\n", fd); + return -1; + } + + pipe = &pipe_table.pipes[index]; + + /* 書き込み側がクローズされているかチェック */ + if (pipe->closed_write) { + kprintf("[PIPE] Pipe write end closed\n"); + return -1; + } + + /* 読み込み側がクローズされている場合はSIGPIPE */ + if (pipe->closed_read) { + kprintf("[PIPE] Broken pipe\n"); + /* TODO: SIGPIPEを送信 */ + return -1; + } + + /* 現在のプロセスを確認 */ + current = process_get_current(); + if (current == NULL) { + return -1; + } + + /* 利用可能な空き容量を計算 */ + if (pipe->write_pos >= pipe->read_pos) { + available = pipe->size - (pipe->write_pos - pipe->read_pos) - 1; + } else { + available = pipe->read_pos - pipe->write_pos - 1; + } + + /* 書き込めるサイズを計算 */ + to_write = min(count, available); + if (to_write == 0) { + /* バッファフル - 簡略化のためエラーを返す */ + kprintf("[PIPE] Pipe buffer full\n"); + return -1; + } + + /* リングバッファに書き込み */ + if (pipe->write_pos + to_write <= pipe->size) { + memcpy(pipe->buffer + pipe->write_pos, buf, to_write); + pipe->write_pos = (pipe->write_pos + to_write) % pipe->size; + } else { + /* バッファの終端をまたぐ場合 */ + size_t first_part = pipe->size - pipe->write_pos; + memcpy(pipe->buffer + pipe->write_pos, buf, first_part); + memcpy(pipe->buffer, (const char *)buf + first_part, to_write - first_part); + pipe->write_pos = to_write - first_part; + } + + /* 読み込みプロセスを起床 */ + reader = process_find(pipe->reader_pid); + if (reader && reader->state == PROCESS_STATE_WAITING) { + reader->state = PROCESS_STATE_READY; + scheduler_add_ready(reader); + } + + return to_write; +} + +/** + * パイプをクローズ + */ +int ipc_pipe_close(int fd) { + struct pipe *pipe; + struct process *current; + int index; + + /* パイプインデックスを取得 */ + index = fd_to_pipe_index(fd); + if (index < 0 || !pipe_table.used[index]) { + kprintf("[PIPE] Invalid pipe fd: %d\n", fd); + return -1; + } + + pipe = &pipe_table.pipes[index]; + current = process_get_current(); + if (current == NULL) { + return -1; + } + + /* 読み込み側/書き込み側を判定してクローズ */ + if (current->pid == pipe->reader_pid) { + pipe->closed_read = true; + } + if (current->pid == pipe->writer_pid) { + pipe->closed_write = true; + } + + /* 両端がクローズされたらパイプを解放 */ + if (pipe->closed_read && pipe->closed_write) { + kfree(pipe->buffer); + pipe->buffer = NULL; + pipe_table.used[index] = false; + kprintf("[PIPE] Pipe destroyed: fd=%d\n", fd); + } + + return 0; +} \ No newline at end of file diff --git a/kernel/lib/stdio.c b/kernel/lib/stdio.c index ad8090c..dde5094 100644 --- a/kernel/lib/stdio.c +++ b/kernel/lib/stdio.c @@ -6,6 +6,7 @@ #include "../include/kernel.h" #include "../include/wasi_syscalls.h" +#include /* 内部関数宣言 */ static int strlen_internal(const char *str); @@ -28,23 +29,35 @@ static void itoa_internal(int value, char *str, int base) { char *ptr = str; char *ptr1 = str; char tmp_char; - int tmp_value; + int is_negative = 0; + unsigned int uvalue; if (base < 2 || base > 36) { *str = '\0'; return; } + /* 負の数の処理 */ + if (value < 0 && base == 10) { + is_negative = 1; + uvalue = (unsigned int)(-value); + } else { + uvalue = (unsigned int)value; + } + + /* 数値を文字に変換 */ do { - tmp_value = value; - value /= base; - *ptr++ = "0123456789abcdefghijklmnopqrstuvwxyz"[tmp_value - value * base]; - } while (value); + *ptr++ = "0123456789abcdefghijklmnopqrstuvwxyz"[uvalue % base]; + uvalue /= base; + } while (uvalue); - if (tmp_value < 0) + /* 負の符号を追加 */ + if (is_negative) *ptr++ = '-'; + *ptr-- = '\0'; + /* 文字列を反転 */ while (ptr1 < ptr) { tmp_char = *ptr; *ptr-- = *ptr1; @@ -77,30 +90,96 @@ int kprintf(const char *format, ...) { char buffer[1024]; int buf_idx = 0; int i = 0; + va_list args; + int total_written = 0; + + va_start(args, format); - /* 簡易的な実装 - %s, %d, %x のみサポート */ + /* 簡易的な実装 - %s, %d, %x, %-Nd のみサポート */ while (format[i] && buf_idx < sizeof(buffer) - 1) { if (format[i] == '%' && format[i + 1]) { i++; + + /* フィールド幅を解析 */ + int field_width = 0; + int left_align = 0; + + if (format[i] == '-') { + left_align = 1; + i++; + } + + while (format[i] >= '0' && format[i] <= '9') { + field_width = field_width * 10 + (format[i] - '0'); + i++; + } + switch (format[i]) { case 's': { /* 文字列は直接出力 */ if (buf_idx > 0) { wasi_write(STDOUT_FILENO, buffer, buf_idx); + total_written += buf_idx; buf_idx = 0; } - /* TODO: 可変引数から文字列を取得 */ - const char *str = "TODO"; - wasi_write(STDOUT_FILENO, str, strlen_internal(str)); + const char *str = va_arg(args, const char *); + if (str == NULL) str = "(null)"; + int str_len = strlen_internal(str); + + /* フィールド幅の処理 */ + if (field_width > str_len && !left_align) { + for (int j = 0; j < field_width - str_len; j++) { + wasi_write(STDOUT_FILENO, " ", 1); + total_written++; + } + } + + wasi_write(STDOUT_FILENO, str, str_len); + total_written += str_len; + + if (field_width > str_len && left_align) { + for (int j = 0; j < field_width - str_len; j++) { + wasi_write(STDOUT_FILENO, " ", 1); + total_written++; + } + } break; } case 'd': { /* 整数は変換して追加 */ char num_buf[32]; - /* TODO: 可変引数から整数を取得 */ - int num = 0; + int num = va_arg(args, int); itoa_internal(num, num_buf, 10); int num_len = strlen_internal(num_buf); + + /* フィールド幅の処理 */ + if (field_width > num_len && !left_align) { + for (int j = 0; j < field_width - num_len; j++) { + if (buf_idx < sizeof(buffer) - 1) { + buffer[buf_idx++] = ' '; + } + } + } + + for (int j = 0; j < num_len && buf_idx < sizeof(buffer) - 1; j++) { + buffer[buf_idx++] = num_buf[j]; + } + + if (field_width > num_len && left_align) { + for (int j = 0; j < field_width - num_len; j++) { + if (buf_idx < sizeof(buffer) - 1) { + buffer[buf_idx++] = ' '; + } + } + } + break; + } + case 'x': { + /* 16進数 */ + char num_buf[32]; + unsigned int num = va_arg(args, unsigned int); + itoa_internal(num, num_buf, 16); + int num_len = strlen_internal(num_buf); for (int j = 0; j < num_len && buf_idx < sizeof(buffer) - 1; j++) { buffer[buf_idx++] = num_buf[j]; } @@ -111,7 +190,9 @@ int kprintf(const char *format, ...) { break; default: buffer[buf_idx++] = '%'; - buffer[buf_idx++] = format[i]; + if (buf_idx < sizeof(buffer) - 1) { + buffer[buf_idx++] = format[i]; + } break; } i++; @@ -122,17 +203,74 @@ int kprintf(const char *format, ...) { if (buf_idx > 0) { wasi_write(STDOUT_FILENO, buffer, buf_idx); + total_written += buf_idx; } - - return buf_idx; + + va_end(args); + return total_written; } /** * エラー出力 */ int kfprintf(int fd, const char *format, ...) { - /* 簡易実装 - formatをそのまま出力 */ - int len = strlen_internal(format); - wasi_write(fd, format, len); - return len; + char buffer[1024]; + int buf_idx = 0; + int i = 0; + va_list args; + int total_written = 0; + + va_start(args, format); + + /* kprintfと同じ実装だが、出力先がfd */ + while (format[i] && buf_idx < sizeof(buffer) - 1) { + if (format[i] == '%' && format[i + 1]) { + i++; + switch (format[i]) { + case 's': { + if (buf_idx > 0) { + wasi_write(fd, buffer, buf_idx); + total_written += buf_idx; + buf_idx = 0; + } + const char *str = va_arg(args, const char *); + if (str == NULL) str = "(null)"; + int str_len = strlen_internal(str); + wasi_write(fd, str, str_len); + total_written += str_len; + break; + } + case 'd': { + char num_buf[32]; + int num = va_arg(args, int); + itoa_internal(num, num_buf, 10); + int num_len = strlen_internal(num_buf); + for (int j = 0; j < num_len && buf_idx < sizeof(buffer) - 1; j++) { + buffer[buf_idx++] = num_buf[j]; + } + break; + } + case '%': + buffer[buf_idx++] = '%'; + break; + default: + buffer[buf_idx++] = '%'; + if (buf_idx < sizeof(buffer) - 1) { + buffer[buf_idx++] = format[i]; + } + break; + } + i++; + } else { + buffer[buf_idx++] = format[i++]; + } + } + + if (buf_idx > 0) { + wasi_write(fd, buffer, buf_idx); + total_written += buf_idx; + } + + va_end(args); + return total_written; } diff --git a/kernel/process/process.c b/kernel/process/process.c new file mode 100644 index 0000000..3d8a682 --- /dev/null +++ b/kernel/process/process.c @@ -0,0 +1,334 @@ +/* + * WebVM プロセス管理実装 + */ + +#include "../include/process.h" +#include "../include/kernel.h" +#include "../include/mm.h" +#include "../include/wasi_syscalls.h" + +/* グローバルプロセステーブル */ +struct process_table g_process_table; + +/* カーネルプロセス (PID 0) */ +static struct process kernel_process = { + .pid = 0, + .ppid = -1, + .name = "kernel", + .state = PROCESS_STATE_RUNNING, + .exit_code = 0 +}; + +/* シェルプロセス (PID 1) */ +static struct process shell_process = { + .pid = 1, + .ppid = 0, + .name = "shell", + .state = PROCESS_STATE_RUNNING, + .exit_code = 0 +}; + +/* 外部関数宣言 */ +int kprintf(const char *format, ...); + +/* 文字列関数 */ +static void *memset(void *s, int c, size_t n) { + unsigned char *p = s; + while (n--) { + *p++ = (unsigned char)c; + } + return s; +} + +static char *strncpy(char *dest, const char *src, size_t n) { + size_t i; + for (i = 0; i < n && src[i] != '\0'; i++) { + dest[i] = src[i]; + } + for (; i < n; i++) { + dest[i] = '\0'; + } + return dest; +} + +/** + * プロセス管理の初期化 + */ +int process_init(void) { + kprintf("[PROCESS] Initializing process management...\n"); + + /* プロセステーブルの初期化 */ + memset(&g_process_table, 0, sizeof(g_process_table)); + + /* 全プロセススロットを未使用に設定 */ + for (int i = 0; i < MAX_PROCESSES; i++) { + g_process_table.processes[i].state = PROCESS_STATE_UNUSED; + g_process_table.processes[i].pid = -1; + } + + /* カーネルプロセスを登録 */ + g_process_table.processes[0] = kernel_process; + + /* シェルプロセスを登録 */ + g_process_table.processes[1] = shell_process; + + /* 現在実行中はシェル */ + g_process_table.current = &g_process_table.processes[1]; + g_process_table.process_count = 2; + g_process_table.next_pid = 2; + + kprintf("[PROCESS] Process management initialized\n"); + return 0; +} + +/** + * 空きプロセススロットを探す + */ +static struct process *find_free_slot(void) { + /* スロット0はカーネルプロセス用なので、1から開始 */ + for (int i = 1; i < MAX_PROCESSES; i++) { + if (g_process_table.processes[i].state == PROCESS_STATE_UNUSED) { + return &g_process_table.processes[i]; + } + } + return NULL; +} + +/** + * プロセスを作成 + */ +pid_t process_create(const char *name, int (*entry)(int, char**), int argc, char **argv) { + struct process *proc; + + /* 空きスロットを探す */ + proc = find_free_slot(); + if (proc == NULL) { + kprintf("[PROCESS] No free process slots available\n"); + return -1; + } + + /* プロセス情報を設定 */ + proc->pid = g_process_table.next_pid++; + proc->ppid = g_process_table.current ? g_process_table.current->pid : 0; + strncpy(proc->name, name, MAX_PROCESS_NAME - 1); + proc->name[MAX_PROCESS_NAME - 1] = '\0'; + proc->state = PROCESS_STATE_INIT; + + /* スタックを割り当て */ + proc->stack_size = PROCESS_STACK_SIZE; + proc->stack_base = kmalloc(proc->stack_size); + if (proc->stack_base == NULL) { + kprintf("[PROCESS] Failed to allocate stack for process %d\n", proc->pid); + proc->state = PROCESS_STATE_UNUSED; + return -1; + } + + /* スタックポインタを設定 (スタックは下向きに成長) */ + proc->context.stack_ptr = (char *)proc->stack_base + proc->stack_size; + + /* エントリポイントと引数を設定 */ + proc->entry = entry; + proc->argc = argc; + proc->argv = argv; + proc->context.pc = entry; + + /* 時刻情報を初期化 */ + proc->start_time = wasi_get_time_ns(); + proc->cpu_time = 0; + + /* プロセスを準備完了状態にする */ + proc->state = PROCESS_STATE_READY; + + /* レディキューに追加 */ + scheduler_add_ready(proc); + + g_process_table.process_count++; + + kprintf("[PROCESS] Created process %d: %s\n", proc->pid, proc->name); + return proc->pid; +} + +/** + * プロセスを終了 + */ +int process_exit(int exit_code) { + struct process *current = process_get_current(); + + if (current == NULL || current->pid == 0) { + kprintf("[PROCESS] Kernel process cannot exit\n"); + return -1; + } + + kprintf("[PROCESS] Process %d exiting with code %d\n", current->pid, exit_code); + + /* 終了コードを設定 */ + current->exit_code = exit_code; + + /* スタックを解放 */ + if (current->stack_base) { + kfree(current->stack_base); + current->stack_base = NULL; + } + + /* ヒープを解放 (将来的な実装) */ + if (current->heap_base) { + kfree(current->heap_base); + current->heap_base = NULL; + } + + /* プロセス状態をゾンビに設定 */ + current->state = PROCESS_STATE_ZOMBIE; + + /* 親プロセスがwaitしていない場合は、すぐに終了状態にする */ + /* TODO: 親プロセスへの通知実装 */ + current->state = PROCESS_STATE_UNUSED; + current->pid = -1; + + g_process_table.process_count--; + + /* スケジューラに制御を渡す */ + scheduler_yield(); + + return 0; +} + +/** + * プロセスを待機 + */ +int process_wait(pid_t pid) { + struct process *proc; + + /* プロセスを検索 */ + proc = process_find(pid); + if (proc == NULL) { + kprintf("[PROCESS] Process %d not found\n", pid); + return -1; + } + + /* プロセスがまだ実行中の場合は待機 */ + while (proc->state != PROCESS_STATE_ZOMBIE && + proc->state != PROCESS_STATE_TERMINATED) { + /* TODO: 実際の待機実装 (現在はビジーウェイト) */ + scheduler_yield(); + } + + /* 終了コードを取得 */ + int exit_code = proc->exit_code; + + /* プロセススロットを解放 */ + proc->state = PROCESS_STATE_UNUSED; + proc->pid = -1; + + return exit_code; +} + +/** + * プロセスを強制終了 + */ +int process_kill(pid_t pid, int signal) { + struct process *proc; + + /* プロセスを検索 */ + proc = process_find(pid); + if (proc == NULL) { + kprintf("[PROCESS] Process %d not found\n", pid); + return -1; + } + + /* カーネルプロセスは終了できない */ + if (pid == 0) { + kprintf("[PROCESS] Cannot kill kernel process\n"); + return -1; + } + + kprintf("[PROCESS] Killing process %d with signal %d\n", pid, signal); + + /* TODO: シグナル処理の実装 */ + /* 現在は強制終了のみ */ + + /* 既に終了している場合 */ + if (proc->state == PROCESS_STATE_TERMINATED || + proc->state == PROCESS_STATE_UNUSED) { + kprintf("[PROCESS] Process %d already terminated\n", pid); + return -1; + } + + /* レディキューから削除 (状態変更前に実行) */ + if (proc->state == PROCESS_STATE_READY) { + scheduler_remove_ready(proc); + } + + /* プロセスを強制終了 */ + proc->exit_code = -signal; + proc->state = PROCESS_STATE_TERMINATED; + + /* リソースを解放 */ + if (proc->stack_base) { + kfree(proc->stack_base); + proc->stack_base = NULL; + } + + if (proc->heap_base) { + kfree(proc->heap_base); + proc->heap_base = NULL; + } + + /* プロセススロットを解放 */ + proc->state = PROCESS_STATE_UNUSED; + proc->pid = -1; + + g_process_table.process_count--; + + return 0; +} + +/** + * 現在実行中のプロセスを取得 + */ +struct process *process_get_current(void) { + return g_process_table.current; +} + +/** + * PIDからプロセスを検索 + */ +struct process *process_find(pid_t pid) { + if (pid < 0 || pid >= MAX_PROCESSES) { + return NULL; + } + + struct process *proc = &g_process_table.processes[pid]; + if (proc->state == PROCESS_STATE_UNUSED) { + return NULL; + } + + return proc; +} + +/** + * プロセステーブルをダンプ (デバッグ用) + */ +void process_dump_table(void) { + kprintf("[PROCESS] Process table dump:\n"); + kprintf("PID PPID STATE NAME\n"); + kprintf("--- ---- --------- ----------------\n"); + + for (int i = 0; i < MAX_PROCESSES; i++) { + struct process *proc = &g_process_table.processes[i]; + if (proc->state != PROCESS_STATE_UNUSED) { + const char *state_str; + switch (proc->state) { + case PROCESS_STATE_INIT: state_str = "INIT "; break; + case PROCESS_STATE_READY: state_str = "READY "; break; + case PROCESS_STATE_RUNNING: state_str = "RUNNING "; break; + case PROCESS_STATE_WAITING: state_str = "WAITING "; break; + case PROCESS_STATE_ZOMBIE: state_str = "ZOMBIE "; break; + case PROCESS_STATE_TERMINATED: state_str = "TERM "; break; + default: state_str = "UNKNOWN "; break; + } + kprintf("%-3d %-4d %s %s\n", + proc->pid, proc->ppid, state_str, proc->name); + } + } + kprintf("Total processes: %d\n", g_process_table.process_count); +} \ No newline at end of file diff --git a/kernel/process/scheduler.c b/kernel/process/scheduler.c new file mode 100644 index 0000000..491acbe --- /dev/null +++ b/kernel/process/scheduler.c @@ -0,0 +1,239 @@ +/* + * WebVM プロセススケジューラ実装 + */ + +#include "../include/process.h" +#include "../include/kernel.h" +#include "../include/wasi_syscalls.h" + +/* スケジューラの状態 */ +static struct { + struct process *ready_head; /* レディキューの先頭 */ + struct process *ready_tail; /* レディキューの末尾 */ + uint64_t tick_count; /* ティックカウント */ + uint32_t time_slice; /* タイムスライス (ミリ秒) */ + bool initialized; /* 初期化フラグ */ +} scheduler_state = { + .ready_head = NULL, + .ready_tail = NULL, + .tick_count = 0, + .time_slice = 10, /* 10ms */ + .initialized = false +}; + +/* 外部関数宣言 */ +int kprintf(const char *format, ...); +extern struct process *process_get_current(void); +extern struct process *process_find(pid_t pid); + +/* 外部変数宣言 */ +extern struct process_table g_process_table; + +/** + * スケジューラの初期化 + */ +void scheduler_init(void) { + kprintf("[SCHEDULER] Initializing scheduler...\n"); + + scheduler_state.ready_head = NULL; + scheduler_state.ready_tail = NULL; + scheduler_state.tick_count = 0; + scheduler_state.initialized = true; + + kprintf("[SCHEDULER] Scheduler initialized\n"); +} + +/** + * レディキューにプロセスを追加 + */ +void scheduler_add_ready(struct process *proc) { + if (proc == NULL || proc->state != PROCESS_STATE_READY) { + return; + } + + /* リンクをクリア */ + proc->next = NULL; + proc->prev = NULL; + + /* キューが空の場合 */ + if (scheduler_state.ready_head == NULL) { + scheduler_state.ready_head = proc; + scheduler_state.ready_tail = proc; + } else { + /* キューの末尾に追加 */ + scheduler_state.ready_tail->next = proc; + proc->prev = scheduler_state.ready_tail; + scheduler_state.ready_tail = proc; + } + + kprintf("[SCHEDULER] Added process %d to ready queue\n", proc->pid); +} + +/** + * レディキューからプロセスを削除 + */ +void scheduler_remove_ready(struct process *proc) { + if (proc == NULL) { + return; + } + + /* 前のプロセスがある場合 */ + if (proc->prev) { + proc->prev->next = proc->next; + } else { + /* 先頭の場合 */ + scheduler_state.ready_head = proc->next; + } + + /* 次のプロセスがある場合 */ + if (proc->next) { + proc->next->prev = proc->prev; + } else { + /* 末尾の場合 */ + scheduler_state.ready_tail = proc->prev; + } + + proc->next = NULL; + proc->prev = NULL; + + kprintf("[SCHEDULER] Removed process %d from ready queue\n", proc->pid); +} + +/** + * 次に実行するプロセスを選択 + */ +static struct process *scheduler_select_next(void) { + struct process *next = scheduler_state.ready_head; + + if (next == NULL) { + /* レディキューが空の場合はカーネルプロセス */ + return process_find(0); + } + + /* レディキューから取り出す */ + scheduler_remove_ready(next); + + return next; +} + +/** + * コンテキストスイッチ (簡易実装) + * + * 注意: WebAssemblyの制約により、真のコンテキストスイッチは不可能 + * ここでは協調的マルチタスキングを実装 + */ +static void context_switch(struct process *from, struct process *to) { + if (from == to) { + return; + } + + kprintf("[SCHEDULER] Context switch: %d -> %d\n", + from ? from->pid : -1, to ? to->pid : -1); + + /* 現在のプロセスの状態を保存 */ + if (from && from->state == PROCESS_STATE_RUNNING) { + from->state = PROCESS_STATE_READY; + scheduler_add_ready(from); + } + + /* 新しいプロセスを実行状態にする */ + to->state = PROCESS_STATE_RUNNING; + + /* カレントプロセスを更新 */ + extern struct process_table g_process_table; + g_process_table.current = to; + + /* + * WebAssemblyではレジスタの直接操作ができないため、 + * 協調的マルチタスキングとして実装 + * プロセスは自発的にyieldを呼ぶ必要がある + */ +} + +/** + * スケジューラティック + * 定期的に呼ばれることを想定 + */ +void scheduler_tick(void) { + struct process *current; + struct process *next; + + if (!scheduler_state.initialized) { + return; + } + + scheduler_state.tick_count++; + + /* 現在のプロセスを取得 */ + current = process_get_current(); + if (current == NULL) { + return; + } + + /* CPU時間を更新 */ + current->cpu_time++; + + /* タイムスライスをチェック */ + if (scheduler_state.tick_count % scheduler_state.time_slice == 0) { + /* 次のプロセスを選択 */ + next = scheduler_select_next(); + if (next && next != current) { + context_switch(current, next); + } + } +} + +/** + * CPUを自発的に譲る + */ +void scheduler_yield(void) { + struct process *current; + struct process *next; + + if (!scheduler_state.initialized) { + return; + } + + /* 現在のプロセスを取得 */ + current = process_get_current(); + if (current == NULL) { + return; + } + + kprintf("[SCHEDULER] Process %d yielding CPU\n", current->pid); + + /* 次のプロセスを選択 */ + next = scheduler_select_next(); + if (next == NULL) { + /* 実行可能なプロセスがない */ + kprintf("[SCHEDULER] No runnable processes\n"); + return; + } + + /* コンテキストスイッチ */ + context_switch(current, next); + + /* + * 注意: WebAssemblyの制約により、ここで実際の制御移譲は行われない + * 呼び出し元が協調的に処理を終了する必要がある + */ +} + +/** + * アイドルループ + * レディキューが空の時に実行される + */ +void scheduler_idle(void) { + kprintf("[SCHEDULER] Entering idle loop\n"); + + while (1) { + /* レディキューをチェック */ + if (scheduler_state.ready_head != NULL) { + scheduler_yield(); + break; + } + + /* 少し待機 (WebAssemblyでは実際のスリープは不可能) */ + /* TODO: Web Workersを使った実装を検討 */ + } +} \ No newline at end of file diff --git a/kernel/process/spawn.c b/kernel/process/spawn.c new file mode 100644 index 0000000..2163a7e --- /dev/null +++ b/kernel/process/spawn.c @@ -0,0 +1,238 @@ +/* + * WebVM POSIX spawn実装 + * + * fork()がWebAssemblyで実装できないため、posix_spawnを使用 + */ + +#include "../include/process.h" +#include "../include/kernel.h" +#include "../include/fs.h" +#include "../include/mm.h" + +/* 外部関数宣言 */ +int kprintf(const char *format, ...); + +/* 文字列関数 */ +static int strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *(unsigned char *)s1 - *(unsigned char *)s2; +} + +static size_t strlen(const char *s) { + size_t len = 0; + while (s[len]) + len++; + return len; +} + +static char *strcpy(char *dest, const char *src) { + char *d = dest; + while ((*d++ = *src++)) + ; + return dest; +} + +static char *strrchr(const char *s, int c) { + const char *last = NULL; + while (*s) { + if (*s == c) { + last = s; + } + s++; + } + return (char *)last; +} + +/** + * 実行可能ファイルのエントリポイントを解決 + * + * 注意: 現在はシェルビルトインコマンドのみサポート + * 将来的にELFローダーを実装予定 + */ +static int (*resolve_entry_point(const char *path))(int, char**) { + /* TODO: ファイルシステムから実行可能ファイルを読み込む */ + /* TODO: ELFパーサーを実装 */ + /* TODO: WebAssemblyモジュールのロードを実装 */ + + /* 現在はビルトインコマンドのマッピングのみ */ + struct builtin_cmd { + const char *name; + int (*func)(int, char**); + }; + + /* ビルトインコマンドのリスト (将来的に拡張) */ + static struct builtin_cmd builtins[] = { + /* シェルコマンドをここに追加 */ + {NULL, NULL} + }; + + /* パスからコマンド名を抽出 */ + const char *cmd_name = strrchr(path, '/'); + if (cmd_name) { + cmd_name++; + } else { + cmd_name = path; + } + + /* ビルトインコマンドを検索 */ + for (int i = 0; builtins[i].name != NULL; i++) { + if (strcmp(cmd_name, builtins[i].name) == 0) { + return builtins[i].func; + } + } + + return NULL; +} + +/** + * 引数配列をコピー + */ +static char **copy_argv(char *const argv[]) { + int argc = 0; + char **new_argv; + + /* 引数カウント */ + if (argv) { + while (argv[argc] != NULL) { + argc++; + } + } + + /* 配列を割り当て */ + new_argv = (char **)kmalloc((argc + 1) * sizeof(char *)); + if (new_argv == NULL) { + return NULL; + } + + /* 各引数をコピー */ + for (int i = 0; i < argc; i++) { + size_t len = strlen(argv[i]) + 1; + new_argv[i] = (char *)kmalloc(len); + if (new_argv[i] == NULL) { + /* エラー時はクリーンアップ */ + for (int j = 0; j < i; j++) { + kfree(new_argv[j]); + } + kfree(new_argv); + return NULL; + } + strcpy(new_argv[i], argv[i]); + } + + new_argv[argc] = NULL; + return new_argv; +} + +/** + * 引数配列を解放 + */ +static void free_argv(char **argv) { + if (argv == NULL) { + return; + } + + for (int i = 0; argv[i] != NULL; i++) { + kfree(argv[i]); + } + kfree(argv); +} + +/** + * プロセスラッパー関数 + * 新しいプロセスのエントリポイントから呼ばれる + */ +static int process_wrapper(int argc, char **argv) { + struct process *proc = process_get_current(); + int ret = 0; + + kprintf("[SPAWN] Process %d started: %s\n", proc->pid, proc->name); + + /* エントリポイントを実行 */ + if (proc->entry) { + ret = proc->entry(argc, argv); + } + + /* プロセスを終了 */ + process_exit(ret); + + /* ここには到達しない */ + return ret; +} + +/** + * POSIX spawn実装 + */ +int posix_spawn(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) { + pid_t new_pid; + int (*entry_point)(int, char**); + char **new_argv = NULL; + int argc = 0; + + kprintf("[SPAWN] posix_spawn: %s\n", path); + + /* パスをチェック */ + if (path == NULL) { + kprintf("[SPAWN] Invalid path\n"); + return -1; + } + + /* エントリポイントを解決 */ + entry_point = resolve_entry_point(path); + if (entry_point == NULL) { + kprintf("[SPAWN] Failed to resolve entry point for %s\n", path); + return -1; + } + + /* 引数をコピー */ + if (argv) { + new_argv = copy_argv(argv); + if (new_argv == NULL) { + kprintf("[SPAWN] Failed to copy arguments\n"); + return -1; + } + while (argv[argc] != NULL) { + argc++; + } + } + + /* TODO: file_actionsの処理 */ + /* TODO: attrpの処理 */ + /* TODO: envpの処理 */ + + /* プロセスを作成 */ + new_pid = process_create(path, entry_point, argc, new_argv); + if (new_pid < 0) { + kprintf("[SPAWN] Failed to create process\n"); + if (new_argv) { + free_argv(new_argv); + } + return -1; + } + + /* PIDを返す */ + if (pid) { + *pid = new_pid; + } + + kprintf("[SPAWN] Created new process with PID %d\n", new_pid); + return 0; +} + +/** + * 簡易版spawn (テスト用) + */ +pid_t spawn_simple(const char *name, int (*func)(int, char**)) { + char *argv[] = {(char *)name, NULL}; + pid_t pid; + + /* 直接エントリポイントを指定してプロセスを作成 */ + pid = process_create(name, func, 1, argv); + + return pid; +} \ No newline at end of file diff --git a/kernel/shell/shell.c b/kernel/shell/shell.c index bfafa2c..b513ddf 100644 --- a/kernel/shell/shell.c +++ b/kernel/shell/shell.c @@ -6,11 +6,14 @@ #include "../include/kernel.h" #include "../include/wasi_syscalls.h" +#include "../include/process.h" +#include "../include/ipc.h" /* 外部関数宣言 */ int kprintf(const char *format, ...); int kputs(const char *str); int kfprintf(int fd, const char *format, ...); +extern pid_t spawn_simple(const char *name, int (*func)(int, char**)); /* 文字列関数 */ static int strcmp(const char *s1, const char *s2) { @@ -46,6 +49,31 @@ static char *strcpy(char *dest, const char *src) { return dest; } +static int atoi(const char *str) { + int result = 0; + int sign = 1; + + /* スキップ空白 */ + while (*str == ' ' || *str == '\t') + str++; + + /* 符号チェック */ + if (*str == '-') { + sign = -1; + str++; + } else if (*str == '+') { + str++; + } + + /* 数字を変換 */ + while (*str >= '0' && *str <= '9') { + result = result * 10 + (*str - '0'); + str++; + } + + return result * sign; +} + /* コマンドバッファ */ #define CMD_BUFFER_SIZE 256 static char cmd_buffer[CMD_BUFFER_SIZE]; @@ -56,7 +84,9 @@ static void cmd_help(void) { kputs(" help - Show this help message"); kputs(" clear - Clear the terminal"); kputs(" echo - Echo arguments to stdout"); - kputs(" ps - List processes (stub)"); + kputs(" ps - List running processes"); + kputs(" kill - Terminate a process (kill )"); + kputs(" spawn - Spawn a test process"); kputs(" ls - List files (stub)"); kputs(" cat - Display file contents (stub)"); kputs(" exit - Exit the shell"); @@ -88,9 +118,8 @@ static void cmd_about(void) { } static void cmd_ps(void) { - kputs("PID TTY TIME CMD"); - kputs("1 tty0 00:00:00 kernel"); - kputs("2 tty0 00:00:00 shell"); + /* プロセステーブルをダンプ */ + process_dump_table(); } static void cmd_ls(void) { kputs("bin dev etc home proc tmp usr var"); } @@ -112,6 +141,67 @@ static void cmd_cat(const char *args) { } } +static void cmd_kill(const char *args) { + pid_t pid; + int result; + + if (!args || !*args) { + kputs("kill: usage: kill "); + return; + } + + /* PIDを解析 */ + pid = atoi(args); + if (pid < 0) { + kprintf("kill: invalid pid: %s\n", args); + return; + } + + /* 現在のシェルプロセスは終了できない */ + if (pid == 1) { + kputs("kill: cannot kill current shell"); + return; + } + + /* プロセスを終了 */ + result = process_kill(pid, 9); /* SIGKILL */ + if (result < 0) { + kprintf("kill: failed to kill process %d\n", pid); + } else { + kprintf("Process %d terminated\n", pid); + } +} + +/* テストプロセスのエントリポイント */ +static int test_process_entry(int argc, char **argv) { + int count = 0; + kprintf("[TEST] Test process started (pid=%d)\n", process_get_current()->pid); + + /* 簡単なループ */ + while (count < 5) { + kprintf("[TEST] Test process running... count=%d\n", count); + count++; + + /* CPUを譲る */ + scheduler_yield(); + } + + kprintf("[TEST] Test process exiting\n"); + return 0; +} + +static void cmd_spawn(const char *args) { + pid_t pid; + + /* テストプロセスを生成 */ + pid = spawn_simple("test_process", test_process_entry); + if (pid < 0) { + kputs("spawn: failed to create process"); + } else { + kprintf("Spawned test process with PID %d\n", pid); + } +} + /* コマンドを解析して実行 */ void execute_command(char *cmd) { char *args = NULL; @@ -139,13 +229,18 @@ void execute_command(char *cmd) { cmd_about(); } else if (strcmp(cmd, "ps") == 0) { cmd_ps(); + } else if (strcmp(cmd, "kill") == 0) { + cmd_kill(args); + } else if (strcmp(cmd, "spawn") == 0) { + cmd_spawn(args); } else if (strcmp(cmd, "ls") == 0) { cmd_ls(); } else if (strcmp(cmd, "cat") == 0) { cmd_cat(args); } else if (strcmp(cmd, "exit") == 0) { kputs("Goodbye!"); - wasi_exit(0); + /* WebAssembly環境では実際の終了は行えない */ + /* JavaScriptから制御を切断する必要がある */ } else if (*cmd) { /* 空コマンドは無視 */ kprintf("sh: %s: command not found\n", cmd); } From 8dd631ebf9f7fbe516563ceef9948cfcadea1614 Mon Sep 17 00:00:00 2001 From: t3tra-dev Date: Thu, 19 Jun 2025 12:02:47 +0900 Subject: [PATCH 2/2] update --- kernel/kernel.wat | 4801 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 3791 insertions(+), 1010 deletions(-) diff --git a/kernel/kernel.wat b/kernel/kernel.wat index 5e2d2a7..d9ca8d8 100644 --- a/kernel/kernel.wat +++ b/kernel/kernel.wat @@ -2,18 +2,21 @@ (type (;0;) (func (result i32))) (type (;1;) (func (param i32 i32 i32 i32) (result i32))) (type (;2;) (func (param i32))) - (type (;3;) (func)) - (type (;4;) (func (param i32) (result i32))) - (type (;5;) (func (param i32 i32) (result i32))) - (type (;6;) (func (param i32 i32 i32) (result i32))) + (type (;3;) (func (param i32 i64 i32) (result i32))) + (type (;4;) (func)) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32 i32) (result i32))) + (type (;7;) (func (param i32 i32 i32) (result i32))) + (type (;8;) (func (result i64))) (import "env" "memory" (memory (;0;) 529 2048 shared)) (import "wasi_snapshot_preview1" "fd_write" (func $__wasi_fd_write (type 1))) (import "wasi_snapshot_preview1" "proc_exit" (func $__wasi_proc_exit (type 2))) - (func $__wasm_init_memory (type 3) + (import "wasi_snapshot_preview1" "clock_time_get" (func $__wasi_clock_time_get (type 3))) + (func $__wasm_init_memory (type 4) block ;; label = @1 block ;; label = @2 block ;; label = @3 - i32.const 33560320 + i32.const 33570152 i32.const 0 i32.const 1 i32.atomic.rmw.cmpxchg @@ -21,49 +24,49 @@ end i32.const 1024 i32.const 0 - i32.const 1746 + i32.const 3360 memory.init $.rodata - i32.const 2784 + i32.const 4384 i32.const 0 - i32.const 33557536 + i32.const 33565768 memory.fill - i32.const 33560320 + i32.const 33570152 i32.const 2 i32.atomic.store - i32.const 33560320 + i32.const 33570152 i32.const -1 memory.atomic.notify drop br 1 (;@1;) end - i32.const 33560320 + i32.const 33570152 i32.const 1 i64.const -1 memory.atomic.wait32 drop end data.drop $.rodata) - (func $kernel_main (type 3) + (func $kernel_main (type 4) (local i32) - i32.const 1642 + i32.const 1866 call $kputs drop - i32.const 1838 + i32.const 2023 call $kputs drop - i32.const 1931 + i32.const 2116 call $kputs drop - i32.const 1764 + i32.const 1957 call $kputs drop - i32.const 1838 + i32.const 2023 call $kputs drop - i32.const 2769 + i32.const 4156 call $kputs drop - i32.const 2093 + i32.const 2278 call $kputs drop block ;; label = @1 @@ -74,11 +77,11 @@ i32.const 0 i32.ge_s br_if 0 (;@4;) - i32.const 2406 + i32.const 2631 local.set 0 br 1 (;@3;) end - i32.const 1541 + i32.const 1675 call $kputs drop block ;; label = @4 @@ -86,18 +89,46 @@ i32.const 0 i32.ge_s br_if 0 (;@4;) - i32.const 2566 + i32.const 2989 local.set 0 br 1 (;@3;) end - i32.const 1612 + i32.const 1813 call $kputs drop - call $drivers_init + block ;; label = @4 + call $drivers_init + i32.const 0 + i32.ge_s + br_if 0 (;@4;) + i32.const 2764 + local.set 0 + br 1 (;@3;) + end + i32.const 1750 + call $kputs + drop + block ;; label = @4 + call $process_init + i32.const 0 + i32.ge_s + br_if 0 (;@4;) + i32.const 2678 + local.set 0 + br 1 (;@3;) + end + i32.const 1712 + call $kputs + drop + call $scheduler_init + i32.const 1784 + call $kputs + drop + call $ipc_init i32.const 0 i32.ge_s br_if 1 (;@2;) - i32.const 2453 + i32.const 3818 local.set 0 end i32.const 2 @@ -106,7 +137,7 @@ call $kfprintf drop i32.const 2 - i32.const 2695 + i32.const 3882 i32.const 0 call $kfprintf drop @@ -114,49 +145,229 @@ call $wasi_exit br 1 (;@1;) end - i32.const 1578 + i32.const 1843 call $kputs drop - i32.const 1422 + i32.const 1556 call $kputs drop end - i32.const 2062 - call $kputs - drop - i32.const 2175 - call $kputs - drop - call $shell_main - i32.const 2134 + i32.const 2247 call $kputs drop - i32.const 1693 + i32.const 2319 call $kputs drop - i32.const 0 - call $wasi_exit) - (func $_start (type 3) + call $shell_main) + (func $_start (type 4) call $kernel_main) (func $mm_init (type 0) (result i32) i32.const 0 i64.const 0 - i64.store offset=2792 + i64.store offset=4392 i32.const 0 i64.const 4328521712 - i64.store offset=2784 + i64.store offset=4384 i32.const 0 - i32.const 2784 - i32.store offset=33557216 + i32.const 4384 + i32.store offset=33558816 i32.const 0 i32.const 16 - i32.store offset=33557220 + i32.store offset=33558820 + i32.const 0) + (func $kmalloc (type 5) (param i32) (result i32) + (local i32 i32 i32 i32) + block ;; label = @1 + i32.const 0 + i32.load offset=33558816 + local.tee 1 + i32.eqz + br_if 0 (;@1;) + local.get 0 + i32.const 7 + i32.add + i32.const -8 + i32.and + local.set 0 + loop ;; label = @2 + block ;; label = @3 + local.get 1 + i32.load offset=4 + i32.eqz + br_if 0 (;@3;) + local.get 1 + i32.load + local.tee 2 + local.get 0 + i32.lt_u + br_if 0 (;@3;) + block ;; label = @4 + local.get 2 + local.get 0 + i32.const 80 + i32.add + i32.le_u + br_if 0 (;@4;) + local.get 1 + local.get 0 + i32.add + local.tee 3 + i32.const 1 + i32.store offset=20 + local.get 3 + local.get 1 + i32.store offset=28 + local.get 3 + local.get 1 + i32.load offset=8 + local.tee 4 + i32.store offset=24 + local.get 3 + local.get 2 + local.get 0 + i32.sub + i32.const -16 + i32.add + i32.store offset=16 + local.get 3 + i32.const 16 + i32.add + local.set 2 + block ;; label = @5 + local.get 4 + i32.eqz + br_if 0 (;@5;) + local.get 4 + local.get 2 + i32.store offset=12 + end + local.get 1 + local.get 2 + i32.store offset=8 + local.get 1 + local.get 0 + i32.store + end + local.get 1 + i32.const 0 + i32.store offset=4 + i32.const 0 + i32.const 0 + i32.load offset=33558820 + local.get 0 + i32.add + i32.store offset=33558820 + local.get 1 + i32.const 16 + i32.add + return + end + local.get 1 + i32.load offset=8 + local.tee 1 + br_if 0 (;@2;) + end + end i32.const 0) + (func $kfree (type 2) (param i32) + (local i32 i32 i32 i32) + block ;; label = @1 + local.get 0 + i32.eqz + br_if 0 (;@1;) + local.get 0 + i32.const -12 + i32.add + i32.const 1 + i32.store + i32.const 0 + i32.const 0 + i32.load offset=33558820 + local.get 0 + i32.const -16 + i32.add + local.tee 1 + i32.load + local.tee 2 + i32.sub + i32.store offset=33558820 + block ;; label = @2 + local.get 0 + i32.const -4 + i32.add + local.tee 3 + i32.load + local.tee 4 + i32.eqz + br_if 0 (;@2;) + local.get 4 + i32.load offset=4 + i32.eqz + br_if 0 (;@2;) + local.get 4 + local.get 0 + i32.const -8 + i32.add + i32.load + local.tee 0 + i32.store offset=8 + local.get 4 + local.get 2 + local.get 4 + i32.load + i32.add + i32.const 16 + i32.add + i32.store + block ;; label = @3 + local.get 0 + br_if 0 (;@3;) + local.get 4 + local.set 1 + br 1 (;@2;) + end + local.get 0 + local.get 4 + i32.store offset=12 + local.get 3 + i32.load + local.set 1 + end + local.get 1 + i32.load offset=8 + local.tee 0 + i32.eqz + br_if 0 (;@1;) + local.get 0 + i32.load offset=4 + i32.eqz + br_if 0 (;@1;) + local.get 1 + local.get 0 + i32.load offset=8 + local.tee 4 + i32.store offset=8 + local.get 1 + local.get 0 + i32.load + local.get 1 + i32.load + i32.add + i32.const 16 + i32.add + i32.store + local.get 4 + i32.eqz + br_if 0 (;@1;) + local.get 4 + local.get 1 + i32.store offset=12 + end) (func $fs_init (type 0) (result i32) (local i32 i32 i32 i32 i32 i32 i32) block ;; label = @1 i32.const 0 - i32.load offset=33559872 + i32.load offset=33561472 local.tee 0 i32.const 9 i32.gt_s @@ -166,11 +377,11 @@ i32.const 1 i32.add local.tee 1 - i32.store offset=33559872 + i32.store offset=33561472 local.get 0 i32.const 264 i32.mul - i32.const 33557232 + i32.const 33558832 i32.add local.tee 2 i32.const 47 @@ -200,11 +411,11 @@ i32.const 0 i32.store8 offset=255 i32.const 0 - i32.load offset=33559876 + i32.load offset=33561476 local.set 3 i32.const 0 local.get 2 - i32.store offset=33559876 + i32.store offset=33561476 local.get 2 local.get 3 i32.store offset=260 @@ -219,11 +430,11 @@ i32.const 2 i32.add local.tee 4 - i32.store offset=33559872 + i32.store offset=33561472 local.get 1 i32.const 264 i32.mul - i32.const 33557232 + i32.const 33558832 i32.add local.tee 5 i32.const 1986356271 @@ -231,7 +442,7 @@ local.get 0 i32.const 264 i32.mul - i32.const 33557232 + i32.const 33558832 i32.add local.set 6 i32.const -248 @@ -271,7 +482,7 @@ end end i32.const 2 - i32.const 2379 + i32.const 2604 i32.const 0 call $kfprintf drop @@ -289,7 +500,7 @@ i32.store8 offset=255 i32.const 0 local.get 5 - i32.store offset=33559876 + i32.store offset=33561476 block ;; label = @2 local.get 0 i32.const 7 @@ -299,17 +510,17 @@ local.get 0 i32.const 3 i32.add - i32.store offset=33559872 + i32.store offset=33561472 local.get 4 i32.const 264 i32.mul local.tee 3 - i32.const 33557236 + i32.const 33558836 i32.add i32.const 99 i32.store8 local.get 3 - i32.const 33557232 + i32.const 33558832 i32.add local.tee 6 i32.const 1869770799 @@ -317,7 +528,7 @@ local.get 0 i32.const 264 i32.mul - i32.const 33557232 + i32.const 33558832 i32.add local.set 2 i32.const -250 @@ -353,12 +564,12 @@ i32.store8 offset=255 i32.const 0 local.get 6 - i32.store offset=33559876 + i32.store offset=33561476 i32.const 0 return end i32.const 2 - i32.const 2667 + i32.const 3725 i32.const 0 call $kfprintf drop @@ -366,7 +577,7 @@ return end i32.const 2 - i32.const 2528 + i32.const 2951 i32.const 0 call $kfprintf drop @@ -376,13 +587,13 @@ (func $drivers_init (type 0) (result i32) (local i32 i32) i32.const 0 - i32.load offset=33560052 + i32.load offset=33561652 local.set 0 block ;; label = @1 block ;; label = @2 block ;; label = @3 i32.const 0 - i32.load offset=33560048 + i32.load offset=33561648 local.tee 1 i32.const 9 i32.gt_s @@ -391,34 +602,34 @@ local.get 1 i32.const 1 i32.add - i32.store offset=33560048 + i32.store offset=33561648 local.get 1 i32.const 4 i32.shl local.tee 1 - i32.const 33559900 + i32.const 33561500 i32.add local.get 0 i32.store local.get 1 - i32.const 33559896 + i32.const 33561496 i32.add i32.const 0 i32.store local.get 1 - i32.const 33559892 + i32.const 33561492 i32.add i32.const 1 i32.store local.get 1 - i32.const 33559888 + i32.const 33561488 i32.add local.tee 0 - i32.const 1460 + i32.const 1594 i32.store i32.const 0 local.get 0 - i32.store offset=33560052 + i32.store offset=33561652 br 1 (;@2;) end local.get 0 @@ -426,7 +637,7 @@ br_if 1 (;@1;) end loop ;; label = @2 - i32.const 2737 + i32.const 3970 i32.const 0 call $kprintf drop @@ -443,7 +654,7 @@ i32.gt_s br_if 0 (;@3;) i32.const 2 - i32.const 2490 + i32.const 2913 i32.const 0 call $kfprintf drop @@ -456,12 +667,12 @@ br_if 0 (;@2;) end end - i32.const 2633 + i32.const 3296 i32.const 0 call $kprintf drop i32.const 0) - (func $kputs (type 4) (param i32) (result i32) + (func $kputs (type 5) (param i32) (result i32) (local i32 i32 i32) i32.const 0 local.set 1 @@ -487,18 +698,21 @@ call $wasi_write drop i32.const 1 - i32.const 2768 + i32.const 4155 i32.const 1 call $wasi_write drop local.get 3) - (func $kprintf (type 5) (param i32 i32) (result i32) - (local i32 i32 i32 i32 i32 i32 i32 i32) + (func $kprintf (type 6) (param i32 i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) global.get $__stack_pointer - i32.const 1056 + i32.const 1072 i32.sub local.tee 2 global.set $__stack_pointer + local.get 2 + local.get 1 + i32.store offset=44 block ;; label = @1 block ;; label = @2 local.get 0 @@ -509,126 +723,730 @@ local.set 4 br 1 (;@1;) end - i32.const 0 - local.set 4 local.get 0 + i32.const 1 + i32.add local.set 5 - i32.const 0 + local.get 2 + i32.const -1 + i32.add local.set 6 - loop ;; label = @2 - block ;; label = @3 + i32.const 0 + local.set 1 + i32.const 0 + local.set 7 + i32.const 0 + local.set 4 + block ;; label = @2 + loop ;; label = @3 block ;; label = @4 block ;; label = @5 - local.get 3 - i32.const 255 - i32.and - i32.const 37 - i32.ne - br_if 0 (;@5;) block ;; label = @6 block ;; label = @7 block ;; label = @8 block ;; label = @9 block ;; label = @10 - local.get 5 - i32.const 1 + block ;; label = @11 + local.get 3 + i32.const 255 + i32.and + i32.const 37 + i32.ne + br_if 0 (;@11;) + local.get 0 + local.get 7 + i32.const 1 + i32.add + local.tee 8 + i32.add + i32.load8_u + local.tee 9 + i32.eqz + br_if 0 (;@11;) + i32.const 0 + local.set 10 + block ;; label = @12 + block ;; label = @13 + local.get 0 + local.get 7 + i32.const 2 + i32.add + local.get 8 + local.get 9 + i32.const 45 + i32.eq + local.tee 11 + select + local.tee 3 + i32.add + i32.load8_u + local.tee 8 + i32.const -48 + i32.add + i32.const 255 + i32.and + i32.const 9 + i32.le_u + br_if 0 (;@13;) + local.get 3 + local.set 7 + br 1 (;@12;) + end + i32.const 0 + local.set 10 + loop ;; label = @13 + local.get 10 + i32.const 10 + i32.mul + local.get 8 + i32.const -48 + i32.add + i32.const 255 + i32.and + i32.add + local.set 10 + local.get 5 + local.get 3 + i32.add + local.set 8 + local.get 3 + i32.const 1 + i32.add + local.tee 7 + local.set 3 + local.get 8 + i32.load8_u + local.tee 8 + i32.const -48 + i32.add + i32.const 255 + i32.and + i32.const 10 + i32.lt_u + br_if 0 (;@13;) + end + end + block ;; label = @12 + block ;; label = @13 + block ;; label = @14 + local.get 8 + i32.const 255 + i32.and + local.tee 3 + i32.const -100 + i32.add + br_table 1 (;@13;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 0 (;@14;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 5 (;@9;) 7 (;@7;) 4 (;@10;) + end + block ;; label = @14 + local.get 1 + i32.const 1 + i32.lt_s + br_if 0 (;@14;) + i32.const 1 + local.get 2 + i32.const 48 + i32.add + local.get 1 + call $wasi_write + drop + local.get 1 + local.get 4 + i32.add + local.set 4 + end + local.get 2 + local.get 2 + i32.load offset=44 + local.tee 1 + i32.const 4 + i32.add + i32.store offset=44 + local.get 1 + i32.load + local.tee 1 + i32.const 2346 + local.get 1 + select + local.set 12 + i32.const -1 + local.set 1 + local.get 10 + local.set 3 + loop ;; label = @14 + local.get 3 + local.tee 8 + i32.const -1 + i32.add + local.set 3 + local.get 12 + local.get 1 + i32.add + local.set 13 + local.get 1 + i32.const 1 + i32.add + local.tee 14 + local.set 1 + local.get 13 + i32.const 1 + i32.add + i32.load8_u + br_if 0 (;@14;) + end + block ;; label = @14 + local.get 11 + br_if 0 (;@14;) + local.get 10 + local.get 14 + i32.le_s + br_if 0 (;@14;) + local.get 8 + local.set 1 + loop ;; label = @15 + i32.const 1 + i32.const 2566 + i32.const 1 + call $wasi_write + drop + local.get 4 + i32.const 1 + i32.add + local.set 4 + local.get 1 + i32.const -1 + i32.add + local.tee 1 + br_if 0 (;@15;) + end + end + i32.const 1 + local.get 12 + local.get 14 + call $wasi_write + drop + local.get 4 + local.get 14 + i32.add + local.set 3 + i32.const 0 + local.set 1 + block ;; label = @14 + local.get 9 + i32.const 45 + i32.eq + br_if 0 (;@14;) + local.get 3 + local.set 4 + br 10 (;@4;) + end + local.get 10 + local.get 14 + i32.gt_s + br_if 1 (;@12;) + local.get 3 + local.set 4 + br 9 (;@4;) + end + local.get 2 + local.get 2 + i32.load offset=44 + local.tee 3 + i32.const 4 + i32.add + i32.store offset=44 + local.get 3 + i32.load + local.tee 12 + local.get 12 + i32.const 31 + i32.shr_s + local.tee 3 + i32.xor + local.get 3 + i32.sub + local.set 3 + local.get 2 + local.set 8 + loop ;; label = @13 + local.get 8 + local.get 3 + local.get 3 + i32.const 10 + i32.div_u + local.tee 13 + i32.const 10 + i32.mul + i32.sub + i32.const 1024 + i32.add + i32.load8_u + i32.store8 + local.get 8 + i32.const 1 + i32.add + local.set 8 + local.get 3 + i32.const 9 + i32.gt_u + local.set 14 + local.get 13 + local.set 3 + local.get 14 + br_if 0 (;@13;) + end + block ;; label = @13 + local.get 12 + i32.const -1 + i32.gt_s + br_if 0 (;@13;) + local.get 8 + i32.const 45 + i32.store8 + local.get 8 + i32.const 1 + i32.add + local.set 8 + end + local.get 8 + i32.const 0 + i32.store8 + block ;; label = @13 + local.get 2 + local.get 8 + i32.const -1 + i32.add + local.tee 3 + i32.ge_u + br_if 0 (;@13;) + local.get 2 + local.set 8 + loop ;; label = @14 + local.get 3 + i32.load8_u + local.set 13 + local.get 3 + local.get 8 + i32.load8_u + i32.store8 + local.get 8 + local.get 13 + i32.store8 + local.get 8 + i32.const 1 + i32.add + local.tee 8 + local.get 3 + i32.const -1 + i32.add + local.tee 3 + i32.lt_u + br_if 0 (;@14;) + end + end + local.get 10 + i32.const 1 + i32.add + local.set 8 + i32.const 0 + local.set 3 + loop ;; label = @13 + local.get 8 + i32.const -1 + i32.add + local.set 8 + local.get 3 + local.tee 13 + i32.const 1 + i32.add + local.set 3 + local.get 2 + local.get 13 + i32.add + i32.load8_u + br_if 0 (;@13;) + end + local.get 3 + i32.const -1 + i32.add + local.set 15 + block ;; label = @13 + local.get 11 + br_if 0 (;@13;) + local.get 10 + local.get 15 + i32.le_s + br_if 0 (;@13;) + block ;; label = @14 + i32.const 0 + local.get 8 + i32.sub + i32.const -4 + i32.gt_u + br_if 0 (;@14;) + local.get 10 + local.get 13 + i32.sub + i32.const -4 + i32.and + local.set 11 + loop ;; label = @15 + i32.const 1023 + local.set 14 + i32.const 1023 + local.set 12 + block ;; label = @16 + local.get 1 + i32.const 1022 + i32.gt_u + br_if 0 (;@16;) + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + i32.const 32 + i32.store8 + local.get 1 + i32.const 1 + i32.add + local.set 12 + end + block ;; label = @16 + local.get 12 + i32.const 1022 + i32.gt_u + br_if 0 (;@16;) + local.get 2 + i32.const 48 + i32.add + local.get 12 + i32.add + i32.const 32 + i32.store8 + local.get 12 + i32.const 1 + i32.add + local.set 14 + end + i32.const 1023 + local.set 1 + i32.const 1023 + local.set 12 + block ;; label = @16 + local.get 14 + i32.const 1022 + i32.gt_u + br_if 0 (;@16;) + local.get 2 + i32.const 48 + i32.add + local.get 14 + i32.add + i32.const 32 + i32.store8 + local.get 14 + i32.const 1 + i32.add + local.set 12 + end + block ;; label = @16 + local.get 12 + i32.const 1022 + i32.gt_u + br_if 0 (;@16;) + local.get 2 + i32.const 48 + i32.add + local.get 12 + i32.add + i32.const 32 + i32.store8 + local.get 12 + i32.const 1 + i32.add + local.set 1 + end + local.get 11 + i32.const -4 + i32.add + local.tee 11 + br_if 0 (;@15;) + end + end + local.get 8 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@13;) + local.get 10 + local.get 13 + i32.sub + i32.const 3 + i32.and + local.set 12 + local.get 1 + local.set 14 + loop ;; label = @14 + i32.const 1023 + local.set 1 + block ;; label = @15 + local.get 14 + i32.const 1022 + i32.gt_u + br_if 0 (;@15;) + local.get 2 + i32.const 48 + i32.add + local.get 14 + i32.add + i32.const 32 + i32.store8 + local.get 14 + i32.const 1 + i32.add + local.set 1 + end + local.get 1 + local.set 14 + local.get 12 + i32.const -1 + i32.add + local.tee 12 + br_if 0 (;@14;) + end + end + local.get 3 + i32.const 1 + i32.eq + br_if 7 (;@5;) + local.get 1 + i32.const 1022 + i32.gt_u + br_if 7 (;@5;) + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + local.set 11 + i32.const 0 + local.set 3 + loop ;; label = @13 + local.get 11 + local.get 3 + i32.add + local.get 2 + local.get 3 + i32.add + i32.load8_u + i32.store8 + local.get 3 + i32.const 1 + i32.add + local.tee 14 + local.get 15 + i32.ge_u + br_if 7 (;@6;) + local.get 1 + local.get 3 + i32.add + local.set 12 + local.get 14 + local.set 3 + local.get 12 + i32.const 1022 + i32.lt_u + br_if 0 (;@13;) + br 7 (;@6;) + end + end + loop ;; label = @12 + i32.const 1 + i32.const 2566 + i32.const 1 + call $wasi_write + drop + local.get 8 + i32.const -1 + i32.add + local.tee 8 + br_if 0 (;@12;) + end + local.get 4 + local.get 10 + i32.add + local.set 4 + br 7 (;@4;) + end + local.get 2 + i32.const 48 i32.add - i32.load8_u - local.tee 5 - i32.const -100 + local.get 1 i32.add - br_table 2 (;@8;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 1 (;@9;) 0 (;@10;) + local.get 3 + i32.store8 + local.get 1 + i32.const 1 + i32.add + local.set 1 + br 6 (;@4;) end - local.get 5 - i32.eqz - br_if 4 (;@5;) - local.get 5 - i32.const 37 - i32.ne - br_if 2 (;@7;) - local.get 2 - i32.const 32 - i32.add - local.get 4 - i32.add + local.get 3 i32.const 37 - i32.store8 - local.get 4 - i32.const 1 - i32.add - local.set 4 - local.get 6 - i32.const 2 - i32.add - local.set 6 - br 6 (;@3;) + i32.eq + br_if 1 (;@8;) end + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + i32.const 37 + i32.store8 block ;; label = @9 - local.get 4 - i32.eqz + local.get 1 + i32.const 1021 + i32.le_u br_if 0 (;@9;) - i32.const 1 - local.get 2 - i32.const 32 - i32.add - local.get 4 - call $wasi_write - drop + i32.const 1023 + local.set 1 + br 7 (;@2;) end - i32.const 1 - i32.const 1798 - i32.const 4 - call $wasi_write - drop - i32.const 0 - local.set 4 - local.get 6 + local.get 1 + local.get 2 + i32.const 48 + i32.add + i32.add + local.get 8 + i32.store8 offset=1 + local.get 1 i32.const 2 i32.add - local.set 6 - br 5 (;@3;) + local.set 1 + br 4 (;@4;) end local.get 2 i32.const 48 - i32.store16 - i32.const 0 - local.set 3 + i32.add + local.get 1 + i32.add + i32.const 37 + i32.store8 + local.get 1 + i32.const 1 + i32.add + local.set 1 + br 3 (;@4;) + end + local.get 2 + local.get 2 + i32.load offset=44 + local.tee 3 + i32.const 4 + i32.add + i32.store offset=44 + local.get 3 + i32.load + local.set 10 + local.get 6 + local.set 3 + loop ;; label = @7 + local.get 3 + i32.const 1 + i32.add + local.tee 3 + local.get 10 + i32.const 15 + i32.and + i32.const 1024 + i32.add + i32.load8_u + i32.store8 + local.get 10 + i32.const 15 + i32.gt_u + local.set 8 + local.get 10 + i32.const 4 + i32.shr_u + local.set 10 + local.get 8 + br_if 0 (;@7;) + end + local.get 3 + i32.const 1 + i32.add + i32.const 0 + i32.store8 + block ;; label = @7 + local.get 2 + local.get 3 + i32.ge_u + br_if 0 (;@7;) + local.get 2 + local.set 10 loop ;; label = @8 - local.get 2 local.get 3 - i32.add - local.set 5 + i32.load8_u + local.set 8 local.get 3 + local.get 10 + i32.load8_u + i32.store8 + local.get 10 + local.get 8 + i32.store8 + local.get 10 i32.const 1 i32.add - local.tee 7 - local.set 3 - local.get 5 - i32.load8_u + local.tee 10 + local.get 3 + i32.const -1 + i32.add + local.tee 3 + i32.lt_u br_if 0 (;@8;) end - local.get 7 - i32.const 1 - i32.eq - br_if 1 (;@6;) - local.get 4 - i32.const 1022 - i32.gt_u - br_if 1 (;@6;) - local.get 7 - i32.const -1 - i32.add - local.set 8 + end + i32.const 0 + local.set 3 + loop ;; label = @7 local.get 2 - i32.const 32 + local.get 3 i32.add - local.get 4 + local.set 10 + local.get 3 + i32.const 1 i32.add - local.set 9 - i32.const 0 + local.tee 8 local.set 3 + local.get 10 + i32.load8_u + br_if 0 (;@7;) + end + local.get 8 + i32.const 1 + i32.eq + br_if 2 (;@4;) + local.get 1 + i32.const 1022 + i32.gt_u + br_if 2 (;@4;) + local.get 8 + i32.const -1 + i32.add + local.set 13 + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + local.set 14 + i32.const 0 + local.set 3 + block ;; label = @7 loop ;; label = @8 - local.get 9 + local.get 14 local.get 3 i32.add local.get 2 @@ -639,960 +1457,2923 @@ local.get 3 i32.const 1 i32.add - local.tee 5 - local.get 8 + local.tee 10 + local.get 13 i32.ge_u - br_if 4 (;@4;) - local.get 4 + br_if 1 (;@7;) + local.get 1 local.get 3 i32.add - local.set 7 - local.get 5 + local.set 8 + local.get 10 local.set 3 - local.get 7 + local.get 8 i32.const 1022 i32.lt_u br_if 0 (;@8;) - br 4 (;@4;) end end - local.get 2 - i32.const 32 + local.get 1 + local.get 10 i32.add - local.get 4 + local.set 1 + br 2 (;@4;) + end + local.get 1 + local.get 14 + i32.add + local.set 1 + end + local.get 9 + i32.const 45 + i32.ne + br_if 0 (;@4;) + local.get 10 + local.get 15 + i32.le_s + br_if 0 (;@4;) + block ;; label = @5 + i32.const 0 + local.get 8 + i32.sub + i32.const -4 + i32.gt_u + br_if 0 (;@5;) + local.get 10 + local.get 13 + i32.sub + i32.const -4 + i32.and + local.set 3 + loop ;; label = @6 + block ;; label = @7 + local.get 1 + i32.const 1022 + i32.gt_u + br_if 0 (;@7;) + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + i32.const 32 + i32.store8 + local.get 1 + i32.const 1 + i32.add + local.set 1 + end + block ;; label = @7 + local.get 1 + i32.const 1022 + i32.gt_u + br_if 0 (;@7;) + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + i32.const 32 + i32.store8 + local.get 1 + i32.const 1 + i32.add + local.set 1 + end + block ;; label = @7 + local.get 1 + i32.const 1022 + i32.gt_u + br_if 0 (;@7;) + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + i32.const 32 + i32.store8 + local.get 1 + i32.const 1 + i32.add + local.set 1 + end + block ;; label = @7 + local.get 1 + i32.const 1022 + i32.gt_u + br_if 0 (;@7;) + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + i32.const 32 + i32.store8 + local.get 1 + i32.const 1 + i32.add + local.set 1 + end + local.get 3 + i32.const -4 i32.add local.tee 3 - local.get 5 - i32.store8 offset=1 - local.get 3 - i32.const 37 + br_if 0 (;@6;) + end + end + local.get 8 + i32.const 3 + i32.and + i32.eqz + br_if 0 (;@4;) + local.get 10 + local.get 13 + i32.sub + i32.const 3 + i32.and + local.set 3 + loop ;; label = @5 + block ;; label = @6 + local.get 1 + i32.const 1022 + i32.gt_u + br_if 0 (;@6;) + local.get 2 + i32.const 48 + i32.add + local.get 1 + i32.add + i32.const 32 i32.store8 - local.get 4 - i32.const 2 + local.get 1 + i32.const 1 i32.add - local.set 4 + local.set 1 end - local.get 6 - i32.const 2 + local.get 3 + i32.const -1 i32.add - local.set 6 - br 2 (;@3;) + local.tee 3 + br_if 0 (;@5;) end - local.get 2 - i32.const 32 - i32.add - local.get 4 - i32.add - local.get 3 - i32.store8 - local.get 4 + end + block ;; label = @4 + local.get 0 + local.get 7 i32.const 1 i32.add - local.set 4 - local.get 6 - i32.const 1 + local.tee 7 i32.add - local.set 6 - br 1 (;@3;) + i32.load8_u + local.tee 3 + i32.eqz + br_if 0 (;@4;) + local.get 1 + i32.const 1023 + i32.lt_u + br_if 1 (;@3;) end - local.get 4 - local.get 5 - i32.add - local.set 4 - local.get 6 - i32.const 2 - i32.add - local.set 6 - end - block ;; label = @3 - local.get 0 - local.get 6 - i32.add - local.tee 5 - i32.load8_u - local.tee 3 - i32.eqz - br_if 0 (;@3;) - local.get 4 - i32.const 1023 - i32.lt_u - br_if 1 (;@2;) end + local.get 1 + i32.const 1 + i32.lt_s + br_if 1 (;@1;) end - local.get 4 - i32.const 1 - i32.lt_s - br_if 0 (;@1;) i32.const 1 local.get 2 - i32.const 32 + i32.const 48 i32.add - local.get 4 + local.get 1 call $wasi_write drop + local.get 1 + local.get 4 + i32.add + local.set 4 end local.get 2 - i32.const 1056 + i32.const 1072 i32.add global.set $__stack_pointer local.get 4) - (func $kfprintf (type 6) (param i32 i32 i32) (result i32) - (local i32 i32 i32) - i32.const 0 - local.set 3 - loop ;; label = @1 - local.get 1 - local.get 3 - i32.add - local.set 4 - local.get 3 - i32.const 1 - i32.add - local.tee 5 - local.set 3 - local.get 4 - i32.load8_u - br_if 0 (;@1;) - end - local.get 0 - local.get 1 - local.get 5 - i32.const -1 - i32.add - local.tee 3 - call $wasi_write - drop - local.get 3) - (func $wasi_write (type 6) (param i32 i32 i32) (result i32) - (local i32) + (func $kfprintf (type 7) (param i32 i32 i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i32) global.get $__stack_pointer - i32.const 16 + i32.const 1072 i32.sub local.tee 3 global.set $__stack_pointer local.get 3 local.get 2 - i32.store offset=12 - local.get 3 - local.get 1 - i32.store offset=8 - local.get 0 - local.get 3 - i32.const 8 - i32.add - i32.const 1 - local.get 3 - i32.const 4 - i32.add - call $__wasi_fd_write - local.set 2 - local.get 3 - i32.const 16 - i32.add - global.set $__stack_pointer - local.get 2) - (func $wasi_exit (type 2) (param i32) - local.get 0 - call $__wasi_proc_exit) - (func $execute_command (type 2) (param i32) - (local i32 i32 i32 i32 i32 i32 i32) - global.get $__stack_pointer - i32.const 32 - i32.sub - local.tee 1 - global.set $__stack_pointer - local.get 0 - local.set 2 + i32.store offset=44 block ;; label = @1 block ;; label = @2 - loop ;; label = @3 - local.get 2 - i32.load8_u - local.tee 3 - i32.eqz - br_if 1 (;@2;) - block ;; label = @4 - local.get 3 - i32.const 32 - i32.eq - br_if 0 (;@4;) - local.get 2 - i32.const 1 - i32.add - local.set 2 - br 1 (;@3;) - end - end - local.get 2 + local.get 1 + i32.load8_u + local.tee 2 + br_if 0 (;@2;) i32.const 0 - i32.store8 - loop ;; label = @3 - local.get 2 - i32.const 1 - i32.add - local.tee 2 - i32.load8_u - i32.const 32 - i32.eq - br_if 0 (;@3;) - br 2 (;@1;) - end + local.set 4 + br 1 (;@1;) end + local.get 1 + local.set 5 i32.const 0 - local.set 2 - end - block ;; label = @1 - block ;; label = @2 + local.set 6 + i32.const 0 + local.set 7 + i32.const 0 + local.set 4 + loop ;; label = @2 block ;; label = @3 block ;; label = @4 block ;; label = @5 + local.get 2 + i32.const 255 + i32.and + i32.const 37 + i32.ne + br_if 0 (;@5;) block ;; label = @6 block ;; label = @7 block ;; label = @8 block ;; label = @9 block ;; label = @10 - block ;; label = @11 - local.get 0 - i32.load8_u - local.tee 4 - br_if 0 (;@11;) - i32.const 0 - local.set 5 - i32.const 1061 - local.set 3 - br 1 (;@10;) - end - local.get 0 - i32.const 1 - i32.add - local.set 6 - i32.const 0 - local.set 3 - local.get 4 - local.set 5 - block ;; label = @11 - loop ;; label = @12 - local.get 5 - i32.const 255 - i32.and - local.get 3 - i32.const 1129 - i32.add - i32.load8_u - local.tee 7 - i32.ne - br_if 1 (;@11;) - local.get 6 - local.get 3 - i32.add - local.set 5 - local.get 3 - i32.const 1 - i32.add - local.tee 7 - local.set 3 - local.get 5 - i32.load8_u - local.tee 5 - br_if 0 (;@12;) - end - local.get 7 - i32.const 1129 - i32.add - i32.load8_u - local.set 7 - i32.const 0 - local.set 5 - end local.get 5 - i32.const 255 - i32.and - local.get 7 - i32.const 255 - i32.and - i32.eq - br_if 3 (;@7;) - local.get 0 i32.const 1 i32.add - local.set 7 - i32.const 1123 - local.set 5 - local.get 4 - local.set 3 - block ;; label = @11 - loop ;; label = @12 - local.get 3 - i32.const 255 - i32.and - local.get 5 - i32.load8_u - i32.ne - br_if 1 (;@11;) - local.get 5 - i32.const 1 - i32.add - local.set 5 - local.get 7 - i32.load8_u - local.set 3 - local.get 7 - i32.const 1 - i32.add - local.set 7 - local.get 3 - br_if 0 (;@12;) - end - i32.const 0 - local.set 3 - end - local.get 3 - i32.const 255 - i32.and - local.get 5 i32.load8_u - i32.eq - br_if 4 (;@6;) - local.get 0 - i32.const 1 - i32.add - local.set 6 - i32.const 0 - local.set 3 - local.get 4 - local.set 5 - block ;; label = @11 - loop ;; label = @12 - local.get 5 - i32.const 255 - i32.and - local.get 3 - i32.const 1134 - i32.add - i32.load8_u - local.tee 7 - i32.ne - br_if 1 (;@11;) - local.get 6 - local.get 3 - i32.add - local.set 5 - local.get 3 - i32.const 1 - i32.add - local.tee 7 - local.set 3 - local.get 5 - i32.load8_u - local.tee 5 - br_if 0 (;@12;) - end - local.get 7 - i32.const 1134 - i32.add - i32.load8_u - local.set 7 - i32.const 0 - local.set 5 - end - local.get 5 - i32.const 255 - i32.and - local.get 7 - i32.const 255 - i32.and - i32.eq - br_if 1 (;@9;) - local.get 0 - i32.const 1 + local.tee 5 + i32.const -100 i32.add - local.set 7 - i32.const 1061 - local.set 3 - local.get 4 - local.set 5 - block ;; label = @11 - loop ;; label = @12 - local.get 5 - i32.const 255 - i32.and - local.get 3 - i32.load8_u - i32.ne - br_if 1 (;@11;) - local.get 3 - i32.const 1 - i32.add - local.set 3 - local.get 7 - i32.load8_u - local.set 5 - local.get 7 - i32.const 1 - i32.add - local.set 7 - local.get 5 - br_if 0 (;@12;) - end - i32.const 0 - local.set 5 - end - local.get 5 - i32.const 255 - i32.and - local.set 5 + br_table 2 (;@8;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 3 (;@7;) 1 (;@9;) 0 (;@10;) end local.get 5 - local.get 3 - i32.load8_u + i32.eqz + br_if 4 (;@5;) + local.get 5 + i32.const 37 i32.ne - br_if 1 (;@8;) - i32.const 1724 - call $kputs - drop - i32.const 1973 - call $kputs - drop - i32.const 1910 - call $kputs - drop - i32.const 1672 - call $kputs - drop - i32.const 2769 - call $kputs - drop - i32.const 1189 - call $kputs - drop - i32.const 2024 - call $kputs - drop - br 8 (;@1;) + br_if 2 (;@7;) + local.get 3 + i32.const 48 + i32.add + local.get 6 + i32.add + i32.const 37 + i32.store8 + local.get 6 + i32.const 1 + i32.add + local.set 6 + local.get 7 + i32.const 2 + i32.add + local.set 7 + br 6 (;@3;) end block ;; label = @9 - block ;; label = @10 - local.get 2 - i32.eqz - br_if 0 (;@10;) - local.get 2 - i32.load8_u - br_if 1 (;@9;) - end - i32.const 2769 - local.set 2 + local.get 6 + i32.eqz + br_if 0 (;@9;) + local.get 0 + local.get 3 + i32.const 48 + i32.add + local.get 6 + call $wasi_write + drop end + local.get 3 + local.get 3 + i32.load offset=44 + local.tee 2 + i32.const 4 + i32.add + i32.store offset=44 local.get 2 - call $kputs + i32.load + local.tee 2 + i32.const 2346 + local.get 2 + select + local.set 8 + i32.const 0 + local.set 2 + loop ;; label = @9 + local.get 8 + local.get 2 + i32.add + local.set 5 + local.get 2 + i32.const 1 + i32.add + local.tee 9 + local.set 2 + local.get 5 + i32.load8_u + br_if 0 (;@9;) + end + local.get 0 + local.get 8 + local.get 9 + i32.const -1 + i32.add + local.tee 2 + call $wasi_write drop - br 7 (;@1;) + local.get 2 + local.get 6 + local.get 4 + i32.add + i32.add + local.set 4 + i32.const 0 + local.set 6 + local.get 7 + i32.const 2 + i32.add + local.set 7 + br 5 (;@3;) + end + local.get 3 + local.get 3 + i32.load offset=44 + local.tee 2 + i32.const 4 + i32.add + i32.store offset=44 + local.get 2 + i32.load + local.tee 10 + local.get 10 + i32.const 31 + i32.shr_s + local.tee 2 + i32.xor + local.get 2 + i32.sub + local.set 2 + local.get 3 + local.set 5 + loop ;; label = @8 + local.get 5 + local.get 2 + local.get 2 + i32.const 10 + i32.div_u + local.tee 8 + i32.const 10 + i32.mul + i32.sub + i32.const 1024 + i32.add + i32.load8_u + i32.store8 + local.get 5 + i32.const 1 + i32.add + local.set 5 + local.get 2 + i32.const 9 + i32.gt_u + local.set 9 + local.get 8 + local.set 2 + local.get 9 + br_if 0 (;@8;) end block ;; label = @8 - block ;; label = @9 - block ;; label = @10 - block ;; label = @11 - local.get 4 - br_if 0 (;@11;) - i32.const 0 - local.set 3 - i32.const 1067 - local.set 2 - br 1 (;@10;) - end - local.get 0 - i32.const 1 - i32.add - local.set 6 - i32.const 0 - local.set 3 - local.get 4 - local.set 5 - block ;; label = @11 - loop ;; label = @12 - local.get 5 - i32.const 255 - i32.and - local.get 3 - i32.const 1076 - i32.add - i32.load8_u - local.tee 7 - i32.ne - br_if 1 (;@11;) - local.get 6 - local.get 3 - i32.add - local.set 5 - local.get 3 - i32.const 1 - i32.add - local.tee 7 - local.set 3 - local.get 5 - i32.load8_u - local.tee 5 - br_if 0 (;@12;) - end - local.get 7 - i32.const 1076 - i32.add - i32.load8_u - local.set 7 - i32.const 0 - local.set 5 - end - local.get 5 - i32.const 255 - i32.and - local.get 7 - i32.const 255 - i32.and - i32.eq - br_if 5 (;@5;) - local.get 0 - i32.const 1 - i32.add - local.set 7 - i32.const 1079 - local.set 5 - local.get 4 - local.set 3 - block ;; label = @11 - loop ;; label = @12 - local.get 3 - i32.const 255 - i32.and - local.get 5 - i32.load8_u - i32.ne - br_if 1 (;@11;) - local.get 5 - i32.const 1 - i32.add - local.set 5 - local.get 7 - i32.load8_u - local.set 3 - local.get 7 - i32.const 1 - i32.add - local.set 7 - local.get 3 - br_if 0 (;@12;) - end - i32.const 0 - local.set 3 - end - local.get 3 - i32.const 255 - i32.and - local.get 5 - i32.load8_u - i32.eq - br_if 6 (;@4;) - local.get 0 - i32.const 1 - i32.add - local.set 6 - i32.const 0 - local.set 3 - local.get 4 - local.set 5 - block ;; label = @11 - loop ;; label = @12 - local.get 5 - i32.const 255 - i32.and - local.get 3 - i32.const 1072 - i32.add - i32.load8_u - local.tee 7 - i32.ne - br_if 1 (;@11;) - local.get 6 - local.get 3 - i32.add - local.set 5 - local.get 3 - i32.const 1 - i32.add - local.tee 7 - local.set 3 - local.get 5 - i32.load8_u - local.tee 5 - br_if 0 (;@12;) - end - local.get 7 - i32.const 1072 - i32.add - i32.load8_u - local.set 7 - i32.const 0 - local.set 5 - end - local.get 5 - i32.const 255 - i32.and - local.get 7 - i32.const 255 - i32.and - i32.eq - br_if 1 (;@9;) - local.get 0 - i32.const 1 - i32.add - local.set 5 - i32.const 1067 - local.set 2 - local.get 4 - local.set 3 - block ;; label = @11 - loop ;; label = @12 - local.get 3 - i32.const 255 - i32.and - local.get 2 - i32.load8_u - i32.ne - br_if 1 (;@11;) - local.get 2 - i32.const 1 - i32.add - local.set 2 - local.get 5 - i32.load8_u - local.set 3 - local.get 5 - i32.const 1 - i32.add - local.set 5 - local.get 3 - br_if 0 (;@12;) - end - i32.const 0 - local.set 3 - end - local.get 3 - i32.const 255 - i32.and - local.set 3 - end - local.get 3 + local.get 10 + i32.const -1 + i32.gt_s + br_if 0 (;@8;) + local.get 5 + i32.const 45 + i32.store8 + local.get 5 + i32.const 1 + i32.add + local.set 5 + end + local.get 5 + i32.const 0 + i32.store8 + block ;; label = @8 + local.get 3 + local.get 5 + i32.const -1 + i32.add + local.tee 2 + i32.ge_u + br_if 0 (;@8;) + local.get 3 + local.set 5 + loop ;; label = @9 local.get 2 i32.load8_u - i32.ne - br_if 1 (;@8;) - i32.const 2331 - call $kputs - drop - i32.const 0 - call $wasi_exit - br 8 (;@1;) + local.set 8 + local.get 2 + local.get 5 + i32.load8_u + i32.store8 + local.get 5 + local.get 8 + i32.store8 + local.get 5 + i32.const 1 + i32.add + local.tee 5 + local.get 2 + i32.const -1 + i32.add + local.tee 2 + i32.lt_u + br_if 0 (;@9;) end + end + i32.const 0 + local.set 2 + loop ;; label = @8 + local.get 3 local.get 2 - i32.eqz - br_if 5 (;@3;) - local.get 2 - i32.load8_u - local.tee 7 - i32.eqz - br_if 5 (;@3;) - i32.const 0 - local.set 3 - local.get 7 + i32.add local.set 5 - block ;; label = @9 - loop ;; label = @10 - local.get 5 - i32.const 255 - i32.and - local.get 3 - i32.const 1175 - i32.add - i32.load8_u - local.tee 6 - i32.ne - br_if 1 (;@9;) - local.get 2 - local.get 3 - i32.add - local.set 5 - local.get 3 - i32.const 1 - i32.add - local.tee 6 - local.set 3 - local.get 5 - i32.const 1 - i32.add - i32.load8_u - local.tee 5 - br_if 0 (;@10;) - end - local.get 6 - i32.const 1175 - i32.add - i32.load8_u - local.set 6 - i32.const 0 - local.set 5 - end + local.get 2 + i32.const 1 + i32.add + local.tee 8 + local.set 2 local.get 5 - i32.const 255 - i32.and + i32.load8_u + br_if 0 (;@8;) + end + local.get 8 + i32.const 1 + i32.eq + br_if 1 (;@6;) + local.get 6 + i32.const 1022 + i32.gt_u + br_if 1 (;@6;) + local.get 8 + i32.const -1 + i32.add + local.set 9 + local.get 3 + i32.const 48 + i32.add + local.get 6 + i32.add + local.set 10 + i32.const 0 + local.set 2 + loop ;; label = @8 + local.get 10 + local.get 2 + i32.add + local.get 3 + local.get 2 + i32.add + i32.load8_u + i32.store8 + local.get 2 + i32.const 1 + i32.add + local.tee 5 + local.get 9 + i32.ge_u + br_if 4 (;@4;) local.get 6 - i32.const 255 - i32.and - i32.eq - br_if 6 (;@2;) - i32.const 0 - local.set 3 - block ;; label = @9 - loop ;; label = @10 - local.get 7 - i32.const 255 - i32.and - local.get 3 - i32.const 1503 - i32.add - i32.load8_u - local.tee 5 - i32.ne - br_if 1 (;@9;) - local.get 2 - local.get 3 - i32.add - local.set 5 - local.get 3 - i32.const 1 - i32.add - local.tee 6 - local.set 3 - local.get 5 - i32.const 1 - i32.add - i32.load8_u - local.tee 7 - br_if 0 (;@10;) - end - local.get 6 - i32.const 1503 - i32.add - i32.load8_u - local.set 5 - i32.const 0 - local.set 7 - end - block ;; label = @9 - local.get 7 - i32.const 255 - i32.and - local.get 5 - i32.const 255 - i32.and - i32.ne - br_if 0 (;@9;) - i32.const 1351 - call $kputs - drop - i32.const 1381 - call $kputs - drop - br 8 (;@1;) - end - local.get 1 local.get 2 - i32.store offset=16 - i32.const 2343 - local.get 1 - i32.const 16 i32.add - call $kprintf - drop - br 7 (;@1;) + local.set 8 + local.get 5 + local.set 2 + local.get 8 + i32.const 1022 + i32.lt_u + br_if 0 (;@8;) + br 4 (;@4;) end - local.get 4 - i32.eqz - br_if 6 (;@1;) - local.get 1 - local.get 0 - i32.store - i32.const 2606 - local.get 1 - call $kprintf - drop - br 6 (;@1;) end - i32.const 1876 - call $kputs - drop - i32.const 1468 - call $kputs - drop - i32.const 1320 - call $kputs - drop - i32.const 1024 - call $kputs - drop - i32.const 2243 - call $kputs - drop - i32.const 2277 - call $kputs - drop - i32.const 2202 - call $kputs - drop - i32.const 1234 - call $kputs - drop - i32.const 1139 - call $kputs - drop - br 5 (;@1;) - end - i32.const 1 - i32.const 1803 - i32.const 7 - call $wasi_write - drop - br 4 (;@1;) - end - i32.const 1811 - call $kputs - drop - i32.const 1290 + local.get 3 + i32.const 48 + i32.add + local.get 6 + i32.add + i32.const 37 + i32.store8 + block ;; label = @7 + local.get 6 + i32.const 1021 + i32.le_u + br_if 0 (;@7;) + i32.const 1023 + local.set 6 + local.get 7 + i32.const 2 + i32.add + local.set 7 + br 4 (;@3;) + end + local.get 6 + local.get 3 + i32.const 48 + i32.add + i32.add + local.get 5 + i32.store8 offset=1 + local.get 6 + i32.const 2 + i32.add + local.set 6 + end + local.get 7 + i32.const 2 + i32.add + local.set 7 + br 2 (;@3;) + end + local.get 3 + i32.const 48 + i32.add + local.get 6 + i32.add + local.get 2 + i32.store8 + local.get 6 + i32.const 1 + i32.add + local.set 6 + local.get 7 + i32.const 1 + i32.add + local.set 7 + br 1 (;@3;) + end + local.get 6 + local.get 5 + i32.add + local.set 6 + local.get 7 + i32.const 2 + i32.add + local.set 7 + end + block ;; label = @3 + local.get 1 + local.get 7 + i32.add + local.tee 5 + i32.load8_u + local.tee 2 + i32.eqz + br_if 0 (;@3;) + local.get 6 + i32.const 1023 + i32.lt_u + br_if 1 (;@2;) + end + end + local.get 6 + i32.const 1 + i32.lt_s + br_if 0 (;@1;) + local.get 0 + local.get 3 + i32.const 48 + i32.add + local.get 6 + call $wasi_write + drop + local.get 6 + local.get 4 + i32.add + local.set 4 + end + local.get 3 + i32.const 1072 + i32.add + global.set $__stack_pointer + local.get 4) + (func $wasi_write (type 7) (param i32 i32 i32) (result i32) + (local i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 3 + global.set $__stack_pointer + local.get 3 + local.get 2 + i32.store offset=12 + local.get 3 + local.get 1 + i32.store offset=8 + local.get 0 + local.get 3 + i32.const 8 + i32.add + i32.const 1 + local.get 3 + i32.const 4 + i32.add + call $__wasi_fd_write + local.set 2 + local.get 3 + i32.const 16 + i32.add + global.set $__stack_pointer + local.get 2) + (func $wasi_exit (type 2) (param i32) + local.get 0 + call $__wasi_proc_exit) + (func $wasi_get_time_ns (type 8) (result i64) + (local i32 i64) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 0 + global.set $__stack_pointer + i32.const 0 + i64.const 1000000 + local.get 0 + i32.const 8 + i32.add + call $__wasi_clock_time_get + drop + local.get 0 + i64.load offset=8 + local.set 1 + local.get 0 + i32.const 16 + i32.add + global.set $__stack_pointer + local.get 1) + (func $execute_command (type 2) (param i32) + (local i32 i32 i32 i32 i32 i32 i32) + global.get $__stack_pointer + i32.const 80 + i32.sub + local.tee 1 + global.set $__stack_pointer + local.get 0 + local.set 2 + block ;; label = @1 + block ;; label = @2 + loop ;; label = @3 + local.get 2 + i32.load8_u + local.tee 3 + i32.eqz + br_if 1 (;@2;) + block ;; label = @4 + local.get 3 + i32.const 32 + i32.eq + br_if 0 (;@4;) + local.get 2 + i32.const 1 + i32.add + local.set 2 + br 1 (;@3;) + end + end + local.get 2 + i32.const 0 + i32.store8 + loop ;; label = @3 + local.get 2 + i32.const 1 + i32.add + local.tee 2 + i32.load8_u + i32.const 32 + i32.eq + br_if 0 (;@3;) + br 2 (;@1;) + end + end + i32.const 0 + local.set 2 + end + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + block ;; label = @7 + block ;; label = @8 + block ;; label = @9 + block ;; label = @10 + local.get 0 + i32.load8_u + local.tee 4 + br_if 0 (;@10;) + i32.const 0 + local.set 5 + i32.const 1098 + local.set 3 + br 1 (;@9;) + end + local.get 0 + i32.const 1 + i32.add + local.set 6 + i32.const 0 + local.set 3 + local.get 4 + local.set 5 + block ;; label = @10 + loop ;; label = @11 + local.get 5 + i32.const 255 + i32.and + local.get 3 + i32.const 1279 + i32.add + i32.load8_u + local.tee 7 + i32.ne + br_if 1 (;@10;) + local.get 6 + local.get 3 + i32.add + local.set 5 + local.get 3 + i32.const 1 + i32.add + local.tee 7 + local.set 3 + local.get 5 + i32.load8_u + local.tee 5 + br_if 0 (;@11;) + end + local.get 7 + i32.const 1279 + i32.add + i32.load8_u + local.set 7 + i32.const 0 + local.set 5 + end + local.get 5 + i32.const 255 + i32.and + local.get 7 + i32.const 255 + i32.and + i32.eq + br_if 3 (;@6;) + local.get 0 + i32.const 1 + i32.add + local.set 7 + i32.const 1273 + local.set 5 + local.get 4 + local.set 3 + block ;; label = @10 + loop ;; label = @11 + local.get 3 + i32.const 255 + i32.and + local.get 5 + i32.load8_u + i32.ne + br_if 1 (;@10;) + local.get 5 + i32.const 1 + i32.add + local.set 5 + local.get 7 + i32.load8_u + local.set 3 + local.get 7 + i32.const 1 + i32.add + local.set 7 + local.get 3 + br_if 0 (;@11;) + end + i32.const 0 + local.set 3 + end + local.get 3 + i32.const 255 + i32.and + local.get 5 + i32.load8_u + i32.eq + br_if 4 (;@5;) + local.get 0 + i32.const 1 + i32.add + local.set 6 + i32.const 0 + local.set 3 + local.get 4 + local.set 5 + block ;; label = @10 + loop ;; label = @11 + local.get 5 + i32.const 255 + i32.and + local.get 3 + i32.const 1284 + i32.add + i32.load8_u + local.tee 7 + i32.ne + br_if 1 (;@10;) + local.get 6 + local.get 3 + i32.add + local.set 5 + local.get 3 + i32.const 1 + i32.add + local.tee 7 + local.set 3 + local.get 5 + i32.load8_u + local.tee 5 + br_if 0 (;@11;) + end + local.get 7 + i32.const 1284 + i32.add + i32.load8_u + local.set 7 + i32.const 0 + local.set 5 + end + local.get 5 + i32.const 255 + i32.and + local.get 7 + i32.const 255 + i32.and + i32.eq + br_if 1 (;@8;) + local.get 0 + i32.const 1 + i32.add + local.set 7 + i32.const 1098 + local.set 3 + local.get 4 + local.set 5 + block ;; label = @10 + loop ;; label = @11 + local.get 5 + i32.const 255 + i32.and + local.get 3 + i32.load8_u + i32.ne + br_if 1 (;@10;) + local.get 3 + i32.const 1 + i32.add + local.set 3 + local.get 7 + i32.load8_u + local.set 5 + local.get 7 + i32.const 1 + i32.add + local.set 7 + local.get 5 + br_if 0 (;@11;) + end + i32.const 0 + local.set 5 + end + local.get 5 + i32.const 255 + i32.and + local.set 5 + end + local.get 5 + local.get 3 + i32.load8_u + i32.ne + br_if 1 (;@7;) + i32.const 1917 + call $kputs + drop + i32.const 2158 + call $kputs + drop + i32.const 2095 + call $kputs + drop + i32.const 1896 + call $kputs + drop + i32.const 4156 + call $kputs + drop + i32.const 1345 + call $kputs + drop + i32.const 2209 + call $kputs + drop + br 7 (;@1;) + end + block ;; label = @8 + block ;; label = @9 + local.get 2 + i32.eqz + br_if 0 (;@9;) + local.get 2 + i32.load8_u + br_if 1 (;@8;) + end + i32.const 4156 + local.set 2 + end + local.get 2 + call $kputs + drop + br 6 (;@1;) + end + block ;; label = @7 + block ;; label = @8 + block ;; label = @9 + block ;; label = @10 + block ;; label = @11 + local.get 4 + br_if 0 (;@11;) + i32.const 0 + local.set 5 + i32.const 1194 + local.set 3 + br 1 (;@10;) + end + local.get 0 + i32.const 1 + i32.add + local.set 6 + i32.const 0 + local.set 3 + local.get 4 + local.set 5 + block ;; label = @11 + loop ;; label = @12 + local.get 5 + i32.const 255 + i32.and + local.get 3 + i32.const 1191 + i32.add + i32.load8_u + local.tee 7 + i32.ne + br_if 1 (;@11;) + local.get 6 + local.get 3 + i32.add + local.set 5 + local.get 3 + i32.const 1 + i32.add + local.tee 7 + local.set 3 + local.get 5 + i32.load8_u + local.tee 5 + br_if 0 (;@12;) + end + local.get 7 + i32.const 1191 + i32.add + i32.load8_u + local.set 7 + i32.const 0 + local.set 5 + end + local.get 5 + i32.const 255 + i32.and + local.get 7 + i32.const 255 + i32.and + i32.eq + br_if 6 (;@4;) + local.get 0 + i32.const 1 + i32.add + local.set 7 + i32.const 1390 + local.set 5 + local.get 4 + local.set 3 + block ;; label = @11 + loop ;; label = @12 + local.get 3 + i32.const 255 + i32.and + local.get 5 + i32.load8_u + i32.ne + br_if 1 (;@11;) + local.get 5 + i32.const 1 + i32.add + local.set 5 + local.get 7 + i32.load8_u + local.set 3 + local.get 7 + i32.const 1 + i32.add + local.set 7 + local.get 3 + br_if 0 (;@12;) + end + i32.const 0 + local.set 3 + end + local.get 3 + i32.const 255 + i32.and + local.get 5 + i32.load8_u + i32.eq + br_if 1 (;@9;) + local.get 0 + i32.const 1 + i32.add + local.set 6 + i32.const 0 + local.set 3 + local.get 4 + local.set 5 + block ;; label = @11 + loop ;; label = @12 + local.get 5 + i32.const 255 + i32.and + local.get 3 + i32.const 1289 + i32.add + i32.load8_u + local.tee 7 + i32.ne + br_if 1 (;@11;) + local.get 6 + local.get 3 + i32.add + local.set 5 + local.get 3 + i32.const 1 + i32.add + local.tee 7 + local.set 3 + local.get 5 + i32.load8_u + local.tee 5 + br_if 0 (;@12;) + end + local.get 7 + i32.const 1289 + i32.add + i32.load8_u + local.set 7 + i32.const 0 + local.set 5 + end + local.get 5 + i32.const 255 + i32.and + local.get 7 + i32.const 255 + i32.and + i32.eq + br_if 2 (;@8;) + local.get 0 + i32.const 1 + i32.add + local.set 7 + i32.const 1194 + local.set 3 + local.get 4 + local.set 5 + block ;; label = @11 + loop ;; label = @12 + local.get 5 + i32.const 255 + i32.and + local.get 3 + i32.load8_u + i32.ne + br_if 1 (;@11;) + local.get 3 + i32.const 1 + i32.add + local.set 3 + local.get 7 + i32.load8_u + local.set 5 + local.get 7 + i32.const 1 + i32.add + local.set 7 + local.get 5 + br_if 0 (;@12;) + end + i32.const 0 + local.set 5 + end + local.get 5 + i32.const 255 + i32.and + local.set 5 + end + local.get 5 + local.get 3 + i32.load8_u + i32.ne + br_if 2 (;@7;) + i32.const 1232 + call $kputs + drop + br 8 (;@1;) + end + local.get 2 + i32.eqz + br_if 5 (;@3;) + local.get 2 + i32.load8_u + local.tee 5 + i32.eqz + br_if 5 (;@3;) + local.get 2 + i32.const 1 + i32.add + local.set 3 + block ;; label = @9 + block ;; label = @10 + block ;; label = @11 + block ;; label = @12 + loop ;; label = @13 + block ;; label = @14 + local.get 5 + i32.const 255 + i32.and + i32.const -9 + i32.add + br_table 0 (;@14;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 0 (;@14;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 3 (;@11;) 4 (;@10;) 3 (;@11;) 2 (;@12;) 3 (;@11;) + end + local.get 3 + i32.load8_u + local.set 5 + local.get 3 + i32.const 1 + i32.add + local.set 3 + br 0 (;@13;) + end + end + i32.const -1 + local.set 6 + br 2 (;@9;) + end + local.get 3 + i32.const -1 + i32.add + local.set 3 + end + i32.const 1 + local.set 6 + end + i32.const 0 + local.set 7 + block ;; label = @9 + local.get 3 + i32.load8_u + local.tee 5 + i32.const -48 + i32.add + i32.const 255 + i32.and + i32.const 9 + i32.gt_u + br_if 0 (;@9;) + local.get 3 + i32.const 1 + i32.add + local.set 3 + i32.const 0 + local.set 7 + loop ;; label = @10 + local.get 7 + i32.const 10 + i32.mul + local.get 5 + i32.const -48 + i32.add + i32.const 255 + i32.and + i32.add + local.set 7 + local.get 3 + i32.load8_u + local.set 5 + local.get 3 + i32.const 1 + i32.add + local.set 3 + local.get 5 + i32.const -48 + i32.add + i32.const 255 + i32.and + i32.const 10 + i32.lt_u + br_if 0 (;@10;) + end + end + block ;; label = @9 + local.get 7 + local.get 6 + i32.mul + local.tee 3 + i32.const -1 + i32.gt_s + br_if 0 (;@9;) + local.get 1 + local.get 2 + i32.store offset=16 + i32.const 2836 + local.get 1 + i32.const 16 + i32.add + call $kprintf + drop + br 8 (;@1;) + end + block ;; label = @9 + local.get 3 + i32.const 1 + i32.ne + br_if 0 (;@9;) + i32.const 1395 + call $kputs + drop + br 8 (;@1;) + end + block ;; label = @9 + local.get 3 + i32.const 9 + call $process_kill + i32.const -1 + i32.gt_s + br_if 0 (;@9;) + local.get 1 + local.get 3 + i32.store offset=32 + i32.const 3554 + local.get 1 + i32.const 32 + i32.add + call $kprintf + drop + br 8 (;@1;) + end + local.get 1 + local.get 3 + i32.store offset=48 + i32.const 3439 + local.get 1 + i32.const 48 + i32.add + call $kprintf + drop + br 7 (;@1;) + end + block ;; label = @8 + i32.const 1113 + i32.const 2 + call $spawn_simple + local.tee 2 + i32.const -1 + i32.gt_s + br_if 0 (;@8;) + i32.const 1159 + call $kputs + drop + br 7 (;@1;) + end + local.get 1 + local.get 2 + i32.store offset=64 + i32.const 3632 + local.get 1 + i32.const 64 + i32.add + call $kprintf + drop + br 6 (;@1;) + end + local.get 4 + i32.eqz + br_if 5 (;@1;) + i32.const 0 + local.set 3 + local.get 4 + local.set 5 + block ;; label = @7 + loop ;; label = @8 + local.get 5 + i32.const 255 + i32.and + local.get 3 + i32.const 1109 + i32.add + i32.load8_u + local.tee 7 + i32.ne + br_if 1 (;@7;) + local.get 0 + local.get 3 + i32.add + local.set 5 + local.get 3 + i32.const 1 + i32.add + local.tee 7 + local.set 3 + local.get 5 + i32.const 1 + i32.add + i32.load8_u + local.tee 5 + br_if 0 (;@8;) + end + local.get 7 + i32.const 1109 + i32.add + i32.load8_u + local.set 7 + i32.const 0 + local.set 5 + end + local.get 5 + i32.const 255 + i32.and + local.get 7 + i32.const 255 + i32.and + i32.eq + br_if 4 (;@2;) + i32.const 0 + local.set 2 + block ;; label = @7 + block ;; label = @8 + loop ;; label = @9 + local.get 4 + i32.const 255 + i32.and + local.get 2 + i32.const 1104 + i32.add + i32.load8_u + i32.ne + br_if 1 (;@8;) + local.get 0 + local.get 2 + i32.add + local.set 3 + local.get 2 + i32.const 1 + i32.add + local.tee 5 + local.set 2 + local.get 3 + i32.const 1 + i32.add + i32.load8_u + local.tee 4 + br_if 0 (;@9;) + end + local.get 5 + i32.const 1104 + i32.add + local.set 2 + i32.const 0 + local.set 4 + br 1 (;@7;) + end + local.get 2 + i32.const 1104 + i32.add + local.set 2 + end + block ;; label = @7 + local.get 4 + i32.const 255 + i32.and + local.get 2 + i32.load8_u + i32.ne + br_if 0 (;@7;) + i32.const 2493 + call $kputs + drop + br 6 (;@1;) + end + local.get 1 + local.get 0 + i32.store + i32.const 3195 + local.get 1 + call $kprintf + drop + br 5 (;@1;) + end + i32.const 2061 + call $kputs + drop + i32.const 1602 + call $kputs + drop + i32.const 1454 + call $kputs + drop + i32.const 1061 + call $kputs + drop + i32.const 1197 + call $kputs + drop + i32.const 2424 + call $kputs + drop + i32.const 1126 + call $kputs + drop + i32.const 2394 + call $kputs + drop + i32.const 2353 + call $kputs + drop + i32.const 1427 + call $kputs + drop + i32.const 1295 + call $kputs + drop + br 4 (;@1;) + end + i32.const 1 + i32.const 1991 + i32.const 7 + call $wasi_write + drop + br 3 (;@1;) + end + call $process_dump_table + br 2 (;@1;) + end + i32.const 1999 + call $kputs + drop + br 1 (;@1;) + end + local.get 2 + call $cmd_cat + end + local.get 1 + i32.const 80 + i32.add + global.set $__stack_pointer) + (func $test_process_entry (type 6) (param i32 i32) (result i32) + (local i32) + global.get $__stack_pointer + i32.const 96 + i32.sub + local.tee 2 + global.set $__stack_pointer + local.get 2 + call $process_get_current + i32.load + i32.store offset=80 + i32.const 4119 + local.get 2 + i32.const 80 + i32.add + call $kprintf + drop + local.get 2 + i32.const 0 + i32.store offset=64 + i32.const 3462 + local.get 2 + i32.const 64 + i32.add + call $kprintf + drop + call $scheduler_yield + local.get 2 + i32.const 1 + i32.store offset=48 + i32.const 3462 + local.get 2 + i32.const 48 + i32.add + call $kprintf + drop + call $scheduler_yield + local.get 2 + i32.const 2 + i32.store offset=32 + i32.const 3462 + local.get 2 + i32.const 32 + i32.add + call $kprintf + drop + call $scheduler_yield + local.get 2 + i32.const 3 + i32.store offset=16 + i32.const 3462 + local.get 2 + i32.const 16 + i32.add + call $kprintf + drop + call $scheduler_yield + local.get 2 + i32.const 4 + i32.store + i32.const 3462 + local.get 2 + call $kprintf + drop + call $scheduler_yield + i32.const 3029 + i32.const 0 + call $kprintf + drop + local.get 2 + i32.const 96 + i32.add + global.set $__stack_pointer + i32.const 0) + (func $cmd_cat (type 2) (param i32) + (local i32 i32 i32 i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 1 + global.set $__stack_pointer + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 0 + i32.eqz + br_if 0 (;@3;) + local.get 0 + i32.load8_u + local.tee 2 + i32.eqz + br_if 0 (;@3;) + i32.const 0 + local.set 3 + local.get 2 + local.set 4 + block ;; label = @4 + loop ;; label = @5 + local.get 4 + i32.const 255 + i32.and + local.get 3 + i32.const 1331 + i32.add + i32.load8_u + local.tee 5 + i32.ne + br_if 1 (;@4;) + local.get 0 + local.get 3 + i32.add + local.set 4 + local.get 3 + i32.const 1 + i32.add + local.tee 5 + local.set 3 + local.get 4 + i32.const 1 + i32.add + i32.load8_u + local.tee 4 + br_if 0 (;@5;) + end + local.get 5 + i32.const 1331 + i32.add + i32.load8_u + local.set 5 + i32.const 0 + local.set 4 + end + local.get 4 + i32.const 255 + i32.and + local.get 5 + i32.const 255 + i32.and + i32.eq + br_if 1 (;@2;) + i32.const 0 + local.set 3 + block ;; label = @4 + loop ;; label = @5 + local.get 2 + i32.const 255 + i32.and + local.get 3 + i32.const 1637 + i32.add + i32.load8_u + local.tee 4 + i32.ne + br_if 1 (;@4;) + local.get 0 + local.get 3 + i32.add + local.set 4 + local.get 3 + i32.const 1 + i32.add + local.tee 5 + local.set 3 + local.get 4 + i32.const 1 + i32.add + i32.load8_u + local.tee 2 + br_if 0 (;@5;) + end + local.get 5 + i32.const 1637 + i32.add + i32.load8_u + local.set 4 + i32.const 0 + local.set 2 + end + block ;; label = @4 + local.get 2 + i32.const 255 + i32.and + local.get 4 + i32.const 255 + i32.and + i32.ne + br_if 0 (;@4;) + i32.const 1485 call $kputs drop - i32.const 1261 + i32.const 1515 call $kputs drop br 3 (;@1;) end - i32.const 1082 - call $kputs + local.get 1 + local.get 0 + i32.store + i32.const 2568 + local.get 1 + call $kprintf + drop + br 2 (;@1;) + end + i32.const 1649 + call $kputs + drop + br 1 (;@1;) + end + i32.const 2138 + call $kputs + drop + end + local.get 1 + i32.const 16 + i32.add + global.set $__stack_pointer) + (func $shell_main (type 4) + i32.const 4156 + call $kputs + drop + i32.const 2469 + call $kputs + drop + i32.const 2173 + call $kputs + drop + i32.const 4156 + call $kputs + drop + i32.const 1 + i32.const 2529 + i32.const 2 + call $wasi_write + drop) + (func $handle_command (type 2) (param i32) + (local i32 i32 i32) + i32.const 2 + local.set 1 + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + loop ;; label = @4 + local.get 0 + local.get 1 + i32.add + local.tee 2 + i32.const -2 + i32.add + i32.load8_u + local.tee 3 + i32.eqz + br_if 2 (;@2;) + local.get 1 + i32.const 33561662 + i32.add + local.get 3 + i32.store8 + local.get 2 + i32.const -1 + i32.add + i32.load8_u + local.tee 3 + i32.eqz + br_if 1 (;@3;) + local.get 1 + i32.const 33561663 + i32.add + local.get 3 + i32.store8 + local.get 2 + i32.load8_u + local.tee 2 + i32.eqz + br_if 3 (;@1;) + local.get 1 + i32.const 33561664 + i32.add + local.get 2 + i32.store8 + local.get 1 + i32.const 3 + i32.add + local.tee 1 + i32.const 257 + i32.ne + br_if 0 (;@4;) + end + i32.const 255 + local.set 1 + br 2 (;@1;) + end + local.get 1 + i32.const -1 + i32.add + local.set 1 + br 1 (;@1;) + end + local.get 1 + i32.const -2 + i32.add + local.set 1 + end + local.get 1 + i32.const 33561664 + i32.add + i32.const 0 + i32.store8 + i32.const 33561664 + call $execute_command + i32.const 1 + i32.const 2529 + i32.const 2 + call $wasi_write + drop) + (func $process_init (type 0) (result i32) + (local i32) + i32.const 3924 + i32.const 0 + call $kprintf + drop + i32.const -7184 + local.set 0 + loop ;; label = @1 + local.get 0 + i32.const 33569104 + i32.add + i64.const 0 + i64.store align=1 + local.get 0 + i32.const 8 + i32.add + local.tee 0 + br_if 0 (;@1;) + end + i32.const -7168 + local.set 0 + loop ;; label = @1 + local.get 0 + i32.const 33569240 + i32.add + i32.const 0 + i32.store + local.get 0 + i32.const 33569088 + i32.add + i32.const -1 + i32.store + local.get 0 + i32.const 33569128 + i32.add + i32.const 0 + i32.store + local.get 0 + i32.const 33569352 + i32.add + i32.const 0 + i32.store + local.get 0 + i32.const 33569200 + i32.add + i32.const -1 + i32.store + local.get 0 + i32.const 33569464 + i32.add + i32.const 0 + i32.store + local.get 0 + i32.const 33569312 + i32.add + i32.const -1 + i32.store + local.get 0 + i32.const 33569424 + i32.add + i32.const -1 + i32.store + local.get 0 + i32.const 448 + i32.add + local.tee 0 + br_if 0 (;@1;) + end + block ;; label = @1 + i32.const 112 + i32.eqz + local.tee 0 + br_if 0 (;@1;) + i32.const 33561920 + i32.const 4160 + i32.const 112 + memory.copy + end + block ;; label = @1 + local.get 0 + br_if 0 (;@1;) + i32.const 33562032 + i32.const 4272 + i32.const 112 + memory.copy + end + i32.const 0 + i32.const 33562032 + i32.store offset=33569088 + i32.const 0 + i64.const 8589934594 + i64.store offset=33569096 + i32.const 3254 + i32.const 0 + call $kprintf + drop + i32.const 0) + (func $process_create (type 1) (param i32 i32 i32 i32) (result i32) + (local i32 i32 i32 i32 i32 i32 i32 i64) + global.get $__stack_pointer + i32.const 32 + i32.sub + local.tee 4 + global.set $__stack_pointer + i32.const 0 + local.set 5 + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + loop ;; label = @7 + local.get 5 + i32.const 33562072 + i32.add + i32.load + i32.eqz + br_if 1 (;@6;) + local.get 5 + i32.const 33562184 + i32.add + i32.load + i32.eqz + br_if 2 (;@5;) + local.get 5 + i32.const 33562296 + i32.add + i32.load + i32.eqz + br_if 3 (;@4;) + local.get 5 + i32.const 336 + i32.add + local.tee 5 + i32.const 7056 + i32.eq + br_if 5 (;@2;) + br 0 (;@7;) + end + end + local.get 5 + i32.const 33562032 + i32.add + local.set 6 + br 2 (;@3;) + end + local.get 5 + i32.const 33562144 + i32.add + local.set 6 + br 1 (;@3;) + end + local.get 5 + i32.const 33562256 + i32.add + local.set 6 + end + i32.const 0 + local.set 5 + local.get 6 + i32.const 0 + i32.load offset=33569096 + local.tee 7 + i32.store + i32.const 0 + local.get 7 + i32.const 1 + i32.add + i32.store offset=33569096 + i32.const 0 + local.set 7 + block ;; label = @3 + i32.const 0 + i32.load offset=33569088 + local.tee 8 + i32.eqz + br_if 0 (;@3;) + local.get 8 + i32.load + local.set 7 + end + local.get 6 + local.get 7 + i32.store offset=4 + local.get 6 + i32.const 8 + i32.add + local.set 9 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + loop ;; label = @7 + local.get 0 + local.get 5 + i32.add + local.tee 7 + i32.load8_u + local.tee 10 + i32.eqz + br_if 3 (;@4;) + local.get 6 + local.get 5 + i32.add + local.tee 8 + i32.const 8 + i32.add + local.get 10 + i32.store8 + block ;; label = @8 + local.get 7 + i32.const 1 + i32.add + i32.load8_u + local.tee 10 + i32.eqz + br_if 0 (;@8;) + local.get 8 + i32.const 9 + i32.add + local.get 10 + i32.store8 + local.get 7 + i32.const 2 + i32.add + i32.load8_u + local.tee 10 + i32.eqz + br_if 2 (;@6;) + local.get 8 + i32.const 10 + i32.add + local.get 10 + i32.store8 + local.get 5 + i32.const 28 + i32.eq + br_if 5 (;@3;) + local.get 7 + i32.const 3 + i32.add + i32.load8_u + local.tee 7 + i32.eqz + br_if 3 (;@5;) + local.get 8 + i32.const 11 + i32.add + local.get 7 + i32.store8 + local.get 5 + i32.const 4 + i32.add + local.set 5 + br 1 (;@7;) + end + end + local.get 5 + i32.const 1 + i32.add + local.set 5 + br 2 (;@4;) + end + local.get 5 + i32.const 2 + i32.add + local.set 5 + br 1 (;@4;) + end + local.get 5 + i32.const 3 + i32.add + local.set 5 + end + local.get 5 + i32.const 30 + i32.gt_u + br_if 0 (;@3;) + local.get 5 + local.set 7 + block ;; label = @4 + local.get 5 + i32.const 7 + i32.and + local.tee 8 + i32.const 7 + i32.eq + br_if 0 (;@4;) + local.get 9 + local.get 5 + i32.add + local.set 10 + i32.const 0 + local.set 7 + loop ;; label = @5 + local.get 10 + local.get 7 + i32.add + i32.const 0 + i32.store8 + local.get 8 + local.get 7 + i32.const 1 + i32.add + local.tee 7 + i32.xor + i32.const 7 + i32.ne + br_if 0 (;@5;) + end + local.get 5 + local.get 7 + i32.add + local.set 7 + end + local.get 5 + i32.const 23 + i32.gt_u + br_if 0 (;@3;) + i32.const 31 + local.set 8 + local.get 6 + local.set 5 + loop ;; label = @4 + local.get 5 + local.get 7 + i32.add + i32.const 8 + i32.add + i64.const 0 + i64.store align=1 + local.get 5 + i32.const 8 + i32.add + local.set 5 + local.get 7 + local.get 8 + i32.const -8 + i32.add + local.tee 8 + i32.ne + br_if 0 (;@4;) + end + end + local.get 6 + i32.const 65536 + i32.store offset=48 + local.get 6 + i32.const 1 + i32.store offset=40 + local.get 6 + i32.const 0 + i32.store8 offset=39 + local.get 6 + i32.const 65536 + call $kmalloc + local.tee 5 + i32.store offset=44 + block ;; label = @3 + local.get 5 + br_if 0 (;@3;) + local.get 4 + local.get 6 + i32.load + i32.store + i32.const 3503 + local.get 4 + call $kprintf + drop + local.get 6 + i32.const 0 + i32.store offset=40 + i32.const -1 + local.set 5 + br 2 (;@1;) + end + local.get 6 + local.get 3 + i32.store offset=80 + local.get 6 + local.get 2 + i32.store offset=76 + local.get 6 + local.get 1 + i32.store offset=72 + local.get 6 + local.get 1 + i32.store offset=64 + local.get 6 + local.get 5 + local.get 6 + i32.load offset=48 + i32.add + i32.store offset=60 + call $wasi_get_time_ns + local.set 11 + local.get 6 + i64.const 0 + i64.store offset=96 + local.get 6 + local.get 11 + i64.store offset=88 + local.get 6 + i32.const 2 + i32.store offset=40 + local.get 6 + call $scheduler_add_ready + i32.const 0 + i32.const 0 + i32.load offset=33569100 + i32.const 1 + i32.add + i32.store offset=33569100 + local.get 4 + local.get 6 + i32.load + i32.store offset=16 + local.get 4 + local.get 9 + i32.store offset=20 + i32.const 2859 + local.get 4 + i32.const 16 + i32.add + call $kprintf + drop + local.get 6 + i32.load + local.set 5 + br 1 (;@1;) + end + i32.const 3152 + i32.const 0 + call $kprintf + drop + i32.const -1 + local.set 5 + end + local.get 4 + i32.const 32 + i32.add + global.set $__stack_pointer + local.get 5) + (func $process_get_current (type 0) (result i32) + i32.const 0 + i32.load offset=33569088) + (func $process_find (type 5) (param i32) (result i32) + (local i32) + i32.const 0 + local.set 1 + block ;; label = @1 + local.get 0 + i32.const 63 + i32.gt_u + br_if 0 (;@1;) + local.get 0 + i32.const 112 + i32.mul + local.tee 0 + i32.const 33561920 + i32.add + i32.const 0 + local.get 0 + i32.const 33561960 + i32.add + i32.load + select + local.set 1 + end + local.get 1) + (func $process_kill (type 6) (param i32 i32) (result i32) + (local i32 i32) + global.get $__stack_pointer + i32.const 48 + i32.sub + local.tee 2 + global.set $__stack_pointer + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 0 + i32.const 63 + i32.gt_u + br_if 0 (;@3;) + local.get 0 + i32.const 112 + i32.mul + local.tee 3 + i32.const 33561960 + i32.add + i32.load + br_if 1 (;@2;) + end + local.get 2 + local.get 0 + i32.store + i32.const 3222 + local.get 2 + call $kprintf + drop + i32.const -1 + local.set 0 + br 1 (;@1;) + end + block ;; label = @2 + local.get 0 + br_if 0 (;@2;) + i32.const 2726 + i32.const 0 + call $kprintf + drop + i32.const -1 + local.set 0 + br 1 (;@1;) + end + local.get 2 + local.get 1 + i32.store offset=36 + local.get 2 + local.get 0 + i32.store offset=32 + i32.const 3587 + local.get 2 + i32.const 32 + i32.add + call $kprintf + drop + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + local.get 3 + i32.const 33561920 + i32.add + local.tee 3 + i32.load offset=40 + br_table 0 (;@4;) 2 (;@2;) 1 (;@3;) 2 (;@2;) 2 (;@2;) 2 (;@2;) 0 (;@4;) 2 (;@2;) + end + local.get 2 + local.get 0 + i32.store offset=16 + i32.const 3398 + local.get 2 + i32.const 16 + i32.add + call $kprintf drop + i32.const -1 + local.set 0 br 2 (;@1;) end - i32.const 1515 - call $kputs - drop - br 1 (;@1;) + local.get 3 + call $scheduler_remove_ready + end + local.get 3 + i32.const 6 + i32.store offset=40 + local.get 3 + i32.const 0 + local.get 1 + i32.sub + i32.store offset=84 + block ;; label = @2 + local.get 3 + i32.load offset=44 + local.tee 0 + i32.eqz + br_if 0 (;@2;) + local.get 0 + call $kfree + local.get 3 + i32.const 0 + i32.store offset=44 + end + block ;; label = @2 + local.get 3 + i32.load offset=52 + local.tee 0 + i32.eqz + br_if 0 (;@2;) + local.get 0 + call $kfree + local.get 3 + i32.const 0 + i32.store offset=52 + end + local.get 3 + i32.const -1 + i32.store + i32.const 0 + local.set 0 + local.get 3 + i32.const 0 + i32.store offset=40 + i32.const 0 + i32.const 0 + i32.load offset=33569100 + i32.const -1 + i32.add + i32.store offset=33569100 + end + local.get 2 + i32.const 48 + i32.add + global.set $__stack_pointer + local.get 0) + (func $process_dump_table (type 4) + (local i32 i32 i32 i64) + global.get $__stack_pointer + i32.const 32 + i32.sub + local.tee 0 + global.set $__stack_pointer + i32.const 0 + local.set 1 + i32.const 3851 + i32.const 0 + call $kprintf + drop + i32.const 3790 + i32.const 0 + call $kprintf + drop + i32.const 4079 + i32.const 0 + call $kprintf + drop + loop ;; label = @1 + i32.const 2550 + local.set 2 + block ;; label = @2 + block ;; label = @3 + block ;; label = @4 + block ;; label = @5 + block ;; label = @6 + block ;; label = @7 + block ;; label = @8 + block ;; label = @9 + local.get 1 + i32.const 33561960 + i32.add + i32.load + br_table 7 (;@2;) 6 (;@3;) 0 (;@9;) 1 (;@8;) 2 (;@7;) 3 (;@6;) 4 (;@5;) 5 (;@4;) + end + i32.const 2541 + local.set 2 + br 5 (;@3;) + end + i32.const 2520 + local.set 2 + br 4 (;@3;) + end + i32.const 2511 + local.set 2 + br 3 (;@3;) + end + i32.const 2532 + local.set 2 + br 2 (;@3;) + end + i32.const 2559 + local.set 2 + br 1 (;@3;) + end + i32.const 2502 + local.set 2 + end + local.get 1 + i32.const 33561920 + i32.add + i64.load + local.set 3 + local.get 0 + local.get 1 + i32.const 33561928 + i32.add + i32.store offset=28 + local.get 0 + local.get 2 + i32.store offset=24 + local.get 0 + local.get 3 + i64.store offset=16 + i32.const 2893 + local.get 0 + i32.const 16 + i32.add + call $kprintf + drop + end + local.get 1 + i32.const 112 + i32.add + local.tee 1 + i32.const 7168 + i32.ne + br_if 0 (;@1;) + end + local.get 0 + i32.const 0 + i32.load offset=33569100 + i32.store + i32.const 3704 + local.get 0 + call $kprintf + drop + local.get 0 + i32.const 32 + i32.add + global.set $__stack_pointer) + (func $scheduler_init (type 4) + i32.const 4003 + i32.const 0 + call $kprintf + drop + i32.const 0 + i64.const 0 + i64.store offset=33569112 + i32.const 0 + i32.const 1 + i32.store8 offset=33569120 + i32.const 0 + i32.const 0 + i32.store offset=33569108 + i32.const 0 + i32.const 0 + i32.store offset=33569104 + i32.const 3330 + i32.const 0 + call $kprintf + drop) + (func $scheduler_add_ready (type 2) (param i32) + (local i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 1 + global.set $__stack_pointer + block ;; label = @1 + local.get 0 + i32.eqz + br_if 0 (;@1;) + local.get 0 + i32.load offset=40 + i32.const 2 + i32.ne + br_if 0 (;@1;) + local.get 0 + i64.const 0 + i64.store offset=104 + block ;; label = @2 + block ;; label = @3 + i32.const 0 + i32.load offset=33569104 + br_if 0 (;@3;) + i32.const 0 + local.get 0 + i32.store offset=33569104 + br 1 (;@2;) + end + i32.const 0 + i32.load offset=33569108 + local.tee 2 + local.get 0 + i32.store offset=104 + local.get 0 + local.get 2 + i32.store offset=108 + end + i32.const 0 + local.get 0 + i32.store offset=33569108 + local.get 1 + local.get 0 + i32.load + i32.store + i32.const 3058 + local.get 1 + call $kprintf + drop + end + local.get 1 + i32.const 16 + i32.add + global.set $__stack_pointer) + (func $scheduler_remove_ready (type 2) (param i32) + (local i32 i32 i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 1 + global.set $__stack_pointer + block ;; label = @1 + local.get 0 + i32.eqz + br_if 0 (;@1;) + local.get 0 + i32.load offset=104 + local.set 2 + block ;; label = @2 + block ;; label = @3 + local.get 0 + i32.load offset=108 + local.tee 3 + i32.eqz + br_if 0 (;@3;) + local.get 3 + local.get 2 + i32.store offset=104 + br 1 (;@2;) + end + i32.const 0 + local.get 2 + i32.store offset=33569104 end - i32.const 1953 - call $kputs + block ;; label = @2 + block ;; label = @3 + local.get 2 + i32.eqz + br_if 0 (;@3;) + local.get 2 + local.get 3 + i32.store offset=108 + br 1 (;@2;) + end + i32.const 0 + local.get 3 + i32.store offset=33569108 + end + local.get 0 + i64.const 0 + i64.store offset=104 + local.get 1 + local.get 0 + i32.load + i32.store + i32.const 3103 + local.get 1 + call $kprintf drop end local.get 1 - i32.const 32 + i32.const 16 i32.add global.set $__stack_pointer) - (func $shell_main (type 3) - i32.const 2769 - call $kputs - drop - i32.const 2307 - call $kputs - drop - i32.const 1988 - call $kputs - drop - i32.const 2769 - call $kputs - drop - i32.const 1 - i32.const 2340 - i32.const 2 - call $wasi_write - drop) - (func $handle_command (type 2) (param i32) - (local i32 i32 i32) - i32.const 2 - local.set 1 + (func $scheduler_yield (type 4) + (local i32 i32 i32 i32 i32) + global.get $__stack_pointer + i32.const 64 + i32.sub + local.tee 0 + global.set $__stack_pointer block ;; label = @1 + i32.const 0 + i32.load8_u offset=33569120 + i32.eqz + br_if 0 (;@1;) + call $process_get_current + local.tee 1 + i32.eqz + br_if 0 (;@1;) + local.get 0 + local.get 1 + i32.load + i32.store offset=48 + i32.const 3753 + local.get 0 + i32.const 48 + i32.add + call $kprintf + drop block ;; label = @2 block ;; label = @3 - loop ;; label = @4 - local.get 0 - local.get 1 - i32.add - local.tee 2 - i32.const -2 - i32.add - i32.load8_u - local.tee 3 - i32.eqz - br_if 2 (;@2;) - local.get 1 - i32.const 33560062 - i32.add - local.get 3 - i32.store8 - local.get 2 - i32.const -1 - i32.add - i32.load8_u - local.tee 3 - i32.eqz - br_if 1 (;@3;) - local.get 1 - i32.const 33560063 - i32.add + i32.const 0 + i32.load offset=33569104 + local.tee 2 + i32.eqz + br_if 0 (;@3;) + local.get 2 + i32.load offset=104 + local.set 3 + block ;; label = @4 + block ;; label = @5 + local.get 2 + i32.load offset=108 + local.tee 4 + i32.eqz + br_if 0 (;@5;) + local.get 4 + local.get 3 + i32.store offset=104 + br 1 (;@4;) + end + i32.const 0 local.get 3 - i32.store8 - local.get 2 - i32.load8_u - local.tee 2 - i32.eqz - br_if 3 (;@1;) - local.get 1 - i32.const 33560064 - i32.add - local.get 2 - i32.store8 - local.get 1 - i32.const 3 - i32.add - local.tee 1 - i32.const 257 - i32.ne - br_if 0 (;@4;) + i32.store offset=33569104 end - i32.const 255 - local.set 1 - br 2 (;@1;) + block ;; label = @4 + block ;; label = @5 + local.get 3 + i32.eqz + br_if 0 (;@5;) + local.get 3 + local.get 4 + i32.store offset=108 + br 1 (;@4;) + end + i32.const 0 + local.get 4 + i32.store offset=33569108 + end + local.get 2 + i64.const 0 + i64.store offset=104 + local.get 0 + local.get 2 + i32.load + i32.store offset=32 + i32.const 3103 + local.get 0 + i32.const 32 + i32.add + call $kprintf + drop + br 1 (;@2;) end - local.get 1 - i32.const -1 - i32.add - local.set 1 + i32.const 0 + call $process_find + local.tee 2 + br_if 0 (;@2;) + i32.const 2801 + i32.const 0 + call $kprintf + drop br 1 (;@1;) end local.get 1 - i32.const -2 + local.get 2 + i32.eq + br_if 0 (;@1;) + local.get 1 + i32.load + local.set 3 + local.get 0 + local.get 2 + i32.load + i32.store offset=20 + local.get 0 + local.get 3 + i32.store offset=16 + i32.const 3666 + local.get 0 + i32.const 16 i32.add - local.set 1 + call $kprintf + drop + block ;; label = @2 + local.get 1 + i32.load offset=40 + i32.const 3 + i32.ne + br_if 0 (;@2;) + local.get 1 + i64.const 0 + i64.store offset=104 + local.get 1 + i32.const 2 + i32.store offset=40 + block ;; label = @3 + block ;; label = @4 + i32.const 0 + i32.load offset=33569104 + br_if 0 (;@4;) + i32.const 0 + local.get 1 + i32.store offset=33569104 + br 1 (;@3;) + end + i32.const 0 + i32.load offset=33569108 + local.tee 3 + local.get 1 + i32.store offset=104 + local.get 1 + local.get 3 + i32.store offset=108 + end + i32.const 0 + local.get 1 + i32.store offset=33569108 + local.get 0 + local.get 1 + i32.load + i32.store + i32.const 3058 + local.get 0 + call $kprintf + drop + end + i32.const 33561920 + local.get 2 + i32.store offset=7168 + local.get 2 + i32.const 3 + i32.store offset=40 end + local.get 0 + i32.const 64 + i32.add + global.set $__stack_pointer) + (func $spawn_simple (type 6) (param i32 i32) (result i32) + (local i32) + global.get $__stack_pointer + i32.const 16 + i32.sub + local.tee 2 + global.set $__stack_pointer + local.get 2 + i32.const 0 + i32.store offset=12 + local.get 2 + local.get 0 + i32.store offset=8 + local.get 0 local.get 1 - i32.const 33560064 + i32.const 1 + local.get 2 + i32.const 8 + i32.add + call $process_create + local.set 0 + local.get 2 + i32.const 16 i32.add + global.set $__stack_pointer + local.get 0) + (func $ipc_init (type 0) (result i32) + (local i32) + i32.const 4042 + i32.const 0 + call $kprintf + drop + i32.const -1024 + local.set 0 + loop ;; label = @1 + local.get 0 + i32.const 33570204 + i32.add + i64.const 68719476736 + i64.store align=4 + local.get 0 + i32.const 33570196 + i32.add + i64.const 0 + i64.store align=4 + local.get 0 + i32.const 33570188 + i32.add + i64.const 68719476736 + i64.store align=4 + local.get 0 + i32.const 33570180 + i32.add + i64.const 0 + i64.store align=4 + local.get 0 + i32.const 33570172 + i32.add + i64.const 68719476736 + i64.store align=4 + local.get 0 + i32.const 33570164 + i32.add + i64.const 0 + i64.store align=4 + local.get 0 + i32.const 33570156 + i32.add + i64.const 68719476736 + i64.store align=4 + local.get 0 + i32.const 33570148 + i32.add + i64.const 0 + i64.store align=4 + local.get 0 + i32.const 64 + i32.add + local.tee 0 + br_if 0 (;@1;) + end i32.const 0 - i32.store8 - i32.const 33560064 - call $execute_command i32.const 1 - i32.const 2340 - i32.const 2 - call $wasi_write - drop) - (table (;0;) 2 2 funcref) - (global $__stack_pointer (mut i32) (i32.const 34608912)) + i32.store8 offset=33570148 + i32.const 3365 + i32.const 0 + call $kprintf + drop + i32.const 0) + (table (;0;) 3 3 funcref) + (global $__stack_pointer (mut i32) (i32.const 34618736)) (global $__tls_base (mut i32) (i32.const 0)) (export "_start" (func $_start)) (export "handle_command" (func $handle_command)) (start $__wasm_init_memory) - (elem (;0;) (i32.const 1) func $console_init) - (data $.rodata " echo - Echo arguments to stdout\00about\00exit\00cat\00ps\00ls\00bin dev etc home proc tmp usr var\00clear\00help\00echo\00 about - Show system information\00/proc/version\00This is a minimal UNIX-like operating system\00 exit - Exit the shell\002 tty0 00:00:00 shell\001 tty0 00:00:00 kernel\00 clear - Clear the terminal\00root:x:0:0:root:/root:/bin/sh\00user:x:1000:1000:user:/home/user:/bin/sh\00[INIT] Kernel initialization complete\00console\00 help - Show this help message\00/etc/passwd\00cat: missing file operand\00[INIT] Memory management initialized\00[INIT] Device drivers initialized\00[INIT] Filesystem initialized\00[DEBUG] kernel_main() started\00Memory: 128MB shared\00[DEBUG] kernel_main() finished\00WebVM - POSIX-compatible WebAssembly OS\00 POSIX-compatible WebAssembly OS\00TODO\00\1b[2J\1b[H\00PID TTY TIME CMD\00=====================================\00WebVM Shell - Available commands:\00Architecture: wasm32\00 WebVM Kernel v0.1.0\00WebVM version 0.1.0\00Version: 0.1.0\00Type 'help' for available commands.\00running entirely in your web browser.\00[KERNEL] Entering main loop...\00[INIT] Starting kernel initialization...\00[KERNEL] Shell exited, halting system...\00[KERNEL] Starting shell...\00 cat - Display file contents (stub)\00 ps - List processes (stub)\00 ls - List files (stub)\00Welcome to WebVM Shell!\00Goodbye!\00$ \00cat: %s: No such file or directory\0a\00[FS] Failed to mount /dev\0a\00[INIT] Failed to initialize memory management\0a\00[INIT] Failed to initialize drivers\0a\00[DRIVER] Failed to initialize driver\0a\00[FS] Failed to mount root filesystem\0a\00[INIT] Failed to initialize filesystem\0a\00sh: %s: command not found\0a\00[DRIVER] All drivers initialized\0a\00[FS] Failed to mount /proc\0a\00[KERNEL] Initialization failed, halting.\0a\00[DRIVER] Initializing driver...\0a\00")) + (elem (;0;) (i32.const 1) func $console_init $test_process_entry) + (data $.rodata "0123456789abcdefghijklmnopqrstuvwxyz\00 echo - Echo arguments to stdout\00about\00exit\00cat\00test_process\00 spawn - Spawn a test process\00spawn: failed to create process\00ps\00ls\00 ps - List running processes\00bin dev etc home proc tmp usr var\00clear\00help\00echo\00spawn\00 about - Show system information\00/proc/version\00This is a minimal UNIX-like operating system\00kill\00kill: cannot kill current shell\00 exit - Exit the shell\00 clear - Clear the terminal\00root:x:0:0:root:/root:/bin/sh\00user:x:1000:1000:user:/home/user:/bin/sh\00[INIT] Kernel initialization complete\00console\00 help - Show this help message\00/etc/passwd\00cat: missing file operand\00[INIT] Memory management initialized\00[INIT] Process management initialized\00[INIT] Device drivers initialized\00[INIT] Scheduler initialized\00[INIT] Filesystem initialized\00[INIT] IPC initialized\00[DEBUG] kernel_main() started\00Memory: 128MB shared\00WebVM - POSIX-compatible WebAssembly OS\00 POSIX-compatible WebAssembly OS\00\1b[2J\1b[H\00kill: usage: kill \00=====================================\00WebVM Shell - Available commands:\00Architecture: wasm32\00 WebVM Kernel v0.1.0\00WebVM version 0.1.0\00Version: 0.1.0\00Type 'help' for available commands.\00running entirely in your web browser.\00[KERNEL] Entering main loop...\00[INIT] Starting kernel initialization...\00[KERNEL] Starting shell...\00(null)\00 cat - Display file contents (stub)\00 ls - List files (stub)\00 kill - Terminate a process (kill )\00Welcome to WebVM Shell!\00Goodbye!\00UNKNOWN \00WAITING \00RUNNING \00$ \00ZOMBIE \00READY \00INIT \00TERM \00cat: %s: No such file or directory\0a\00[FS] Failed to mount /dev\0a\00[INIT] Failed to initialize memory management\0a\00[INIT] Failed to initialize process management\0a\00[PROCESS] Cannot kill kernel process\0a\00[INIT] Failed to initialize drivers\0a\00[SCHEDULER] No runnable processes\0a\00kill: invalid pid: %s\0a\00[PROCESS] Created process %d: %s\0a\00%-3d %-4d %s %s\0a\00[DRIVER] Failed to initialize driver\0a\00[FS] Failed to mount root filesystem\0a\00[INIT] Failed to initialize filesystem\0a\00[TEST] Test process exiting\0a\00[SCHEDULER] Added process %d to ready queue\0a\00[SCHEDULER] Removed process %d from ready queue\0a\00[PROCESS] No free process slots available\0a\00sh: %s: command not found\0a\00[PROCESS] Process %d not found\0a\00[PROCESS] Process management initialized\0a\00[DRIVER] All drivers initialized\0a\00[SCHEDULER] Scheduler initialized\0a\00[IPC] IPC subsystem initialized\0a\00[PROCESS] Process %d already terminated\0a\00Process %d terminated\0a\00[TEST] Test process running... count=%d\0a\00[PROCESS] Failed to allocate stack for process %d\0a\00kill: failed to kill process %d\0a\00[PROCESS] Killing process %d with signal %d\0a\00Spawned test process with PID %d\0a\00[SCHEDULER] Context switch: %d -> %d\0a\00Total processes: %d\0a\00[FS] Failed to mount /proc\0a\00[SCHEDULER] Process %d yielding CPU\0a\00PID PPID STATE NAME\0a\00[INIT] Failed to initialize IPC\0a\00[PROCESS] Process table dump:\0a\00[KERNEL] Initialization failed, halting.\0a\00[PROCESS] Initializing process management...\0a\00[DRIVER] Initializing driver...\0a\00[SCHEDULER] Initializing scheduler...\0a\00[IPC] Initializing IPC subsystem...\0a\00--- ---- --------- ----------------\0a\00[TEST] Test process started (pid=%d)\0a\00\00\00\00\00\00\00\00\ff\ff\ff\ffkernel\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00shell\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"))