mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-24 11:14:01 +00:00
硬盘支持(FAT32)
This commit is contained in:
@@ -38,10 +38,10 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b
|
||||
## 支持
|
||||
|
||||
- ELF64 (x86_64) PT_LOAD 段装载
|
||||
- CLeonOS `int 0x80` syscall 0..84(含 `FD_*`、`DL_*`、`FB_*`、`PROC_*`、`STATS_*`、`EXEC_PATHV_IO`、`KERNEL_VERSION`)
|
||||
- CLeonOS `int 0x80` syscall 0..92(含 `FD_*`、`DL_*`、`FB_*`、`PROC_*`、`STATS_*`、`EXEC_PATHV_IO`、`KERNEL_VERSION`、`DISK_*`)
|
||||
- TTY 输出与键盘输入队列
|
||||
- rootfs 文件/目录访问(`FS_*`)
|
||||
- `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`)
|
||||
- `/temp` 与已挂载磁盘路径写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`)
|
||||
- `EXEC_PATH/EXEC_PATHV` 执行 ELF(带深度限制)
|
||||
- `EXEC_PATHV_IO`(支持 stdio fd 继承/重定向)
|
||||
- `SPAWN_PATH/SPAWN_PATHV/WAITPID/EXIT/SLEEP_TICKS/YIELD`
|
||||
@@ -52,12 +52,14 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b
|
||||
- 动态库兼容加载(`DL_OPEN/DL_CLOSE/DL_SYM`,基于 ELF 符号解析)
|
||||
- framebuffer 兼容(`FB_INFO/FB_BLIT/FB_CLEAR`,支持内存缓冲与窗口显示)
|
||||
- 内核版本查询(`KERNEL_VERSION`)
|
||||
- 磁盘接口兼容(`DISK_PRESENT/SIZE_BYTES/SECTOR_COUNT/FORMATTED/FORMAT_FAT32/MOUNT/MOUNTED/MOUNT_PATH`)
|
||||
- Wine 虚拟磁盘目录默认位于 `<rootfs>/__clks_disk0__`(格式化标记文件 `.fat32`)
|
||||
- 异常退出状态编码与故障元信息(`PROC_LAST_SIGNAL/PROC_FAULT_*`)
|
||||
|
||||
## 版本策略
|
||||
|
||||
- CLeonOS-Wine 版本号固定为:`85.0.0-wine`
|
||||
- 该值来源于“当前实现 syscall 数量 = 85(0..84)”,按项目约定后续不再变更
|
||||
- 该值按项目策略固定,不再随新增 syscall 变更(即使当前实现范围已扩展到 `0..92`)
|
||||
|
||||
## 参数
|
||||
|
||||
@@ -71,6 +73,7 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b
|
||||
- `--` 之后内容:作为 guest argv 透传(推荐)
|
||||
- `--max-exec-depth N`:设置 exec 嵌套深度上限
|
||||
- `--verbose`:打印更多日志
|
||||
- 环境变量 `CLEONOS_WINE_DISK_SIZE_MB`:设置 Wine 虚拟磁盘容量(MB,默认 `64`)
|
||||
|
||||
## `execv/spawnv` 参数格式
|
||||
|
||||
|
||||
@@ -99,6 +99,14 @@ SYS_FB_INFO = 81
|
||||
SYS_FB_BLIT = 82
|
||||
SYS_FB_CLEAR = 83
|
||||
SYS_KERNEL_VERSION = 84
|
||||
SYS_DISK_PRESENT = 85
|
||||
SYS_DISK_SIZE_BYTES = 86
|
||||
SYS_DISK_SECTOR_COUNT = 87
|
||||
SYS_DISK_FORMATTED = 88
|
||||
SYS_DISK_FORMAT_FAT32 = 89
|
||||
SYS_DISK_MOUNT = 90
|
||||
SYS_DISK_MOUNTED = 91
|
||||
SYS_DISK_MOUNT_PATH = 92
|
||||
|
||||
# proc states (from cleonos/c/include/cleonos_syscall.h)
|
||||
PROC_STATE_UNUSED = 0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
@@ -62,6 +63,14 @@ from .constants import (
|
||||
SYS_FS_STAT_SIZE,
|
||||
SYS_FS_STAT_TYPE,
|
||||
SYS_FS_WRITE,
|
||||
SYS_DISK_FORMATTED,
|
||||
SYS_DISK_FORMAT_FAT32,
|
||||
SYS_DISK_MOUNT,
|
||||
SYS_DISK_MOUNTED,
|
||||
SYS_DISK_MOUNT_PATH,
|
||||
SYS_DISK_PRESENT,
|
||||
SYS_DISK_SECTOR_COUNT,
|
||||
SYS_DISK_SIZE_BYTES,
|
||||
SYS_GETPID,
|
||||
SYS_KERNEL_VERSION,
|
||||
SYS_KBD_BUFFERED,
|
||||
@@ -272,6 +281,23 @@ class CLeonOSWineNative:
|
||||
self._fb_dirty = False
|
||||
self._fb_presented_once = False
|
||||
|
||||
self._disk_present = True
|
||||
self._disk_size_bytes = self._bounded_env_int("CLEONOS_WINE_DISK_SIZE_MB", 64, 8, 4096) * 1024 * 1024
|
||||
self._disk_mount_path = "/temp/disk"
|
||||
self._disk_root = (self.rootfs / "__clks_disk0__").resolve()
|
||||
self._disk_marker = self._disk_root / ".fat32"
|
||||
self._disk_formatted = False
|
||||
self._disk_mounted = False
|
||||
try:
|
||||
self._disk_root.mkdir(parents=True, exist_ok=True)
|
||||
if self._disk_marker.exists():
|
||||
self._disk_formatted = True
|
||||
self._disk_mounted = True
|
||||
except Exception:
|
||||
self._disk_present = False
|
||||
self._disk_formatted = False
|
||||
self._disk_mounted = False
|
||||
|
||||
default_path = self._normalize_guest_path(self.guest_path_hint or f"/{self.elf_path.name}")
|
||||
self.argv_items, self.env_items = self._prepare_exec_items(default_path, self.argv_items, self.env_items)
|
||||
self._init_default_fds()
|
||||
@@ -717,6 +743,25 @@ class CLeonOSWineNative:
|
||||
return self._fb_clear(arg0)
|
||||
if sid == SYS_KERNEL_VERSION:
|
||||
return self._kernel_version(uc, arg0, arg1)
|
||||
if sid == SYS_DISK_PRESENT:
|
||||
return 1 if self._disk_present else 0
|
||||
if sid == SYS_DISK_SIZE_BYTES:
|
||||
return int(u64(self._disk_size_bytes if self._disk_present else 0))
|
||||
if sid == SYS_DISK_SECTOR_COUNT:
|
||||
if not self._disk_present:
|
||||
return 0
|
||||
return int(u64(self._disk_size_bytes // 512))
|
||||
if sid == SYS_DISK_FORMATTED:
|
||||
return 1 if (self._disk_present and self._disk_formatted) else 0
|
||||
if sid == SYS_DISK_FORMAT_FAT32:
|
||||
label = self._read_guest_cstring(uc, arg0, 16) if arg0 != 0 else ""
|
||||
return self._disk_format_fat32(label)
|
||||
if sid == SYS_DISK_MOUNT:
|
||||
return self._disk_mount(uc, arg0)
|
||||
if sid == SYS_DISK_MOUNTED:
|
||||
return 1 if self._disk_mounted else 0
|
||||
if sid == SYS_DISK_MOUNT_PATH:
|
||||
return self._disk_mount_path_query(uc, arg0, arg1)
|
||||
|
||||
return u64_neg1()
|
||||
|
||||
@@ -1008,9 +1053,90 @@ class CLeonOSWineNative:
|
||||
def _guest_path_is_under_temp(path: str) -> bool:
|
||||
return path == "/temp" or path.startswith("/temp/")
|
||||
|
||||
def _disk_path_is_under_mount(self, path: str) -> bool:
|
||||
if not self._disk_mounted:
|
||||
return False
|
||||
normalized = self._normalize_guest_path(path)
|
||||
mount = self._normalize_guest_path(self._disk_mount_path)
|
||||
return normalized == mount or normalized.startswith(mount + "/")
|
||||
|
||||
def _disk_guest_to_host(self, guest_path: str, *, must_exist: bool) -> Optional[Path]:
|
||||
normalized = self._normalize_guest_path(guest_path)
|
||||
mount = self._normalize_guest_path(self._disk_mount_path)
|
||||
|
||||
if not self._disk_present or not self._disk_formatted or not self._disk_mounted:
|
||||
return None
|
||||
|
||||
if normalized == mount:
|
||||
host = self._disk_root
|
||||
elif normalized.startswith(mount + "/"):
|
||||
rel = normalized[len(mount) + 1 :]
|
||||
parts = [part for part in rel.split("/") if part]
|
||||
host = self._disk_root.joinpath(*parts) if parts else self._disk_root
|
||||
else:
|
||||
return None
|
||||
|
||||
if must_exist and not host.exists():
|
||||
return None
|
||||
return host
|
||||
|
||||
def _disk_format_fat32(self, label: str) -> int:
|
||||
_ = label
|
||||
if not self._disk_present:
|
||||
return 0
|
||||
|
||||
try:
|
||||
self._disk_root.mkdir(parents=True, exist_ok=True)
|
||||
for child in list(self._disk_root.iterdir()):
|
||||
if child.name == self._disk_marker.name:
|
||||
continue
|
||||
if child.is_dir():
|
||||
shutil.rmtree(child)
|
||||
else:
|
||||
child.unlink()
|
||||
self._disk_marker.write_text("FAT32\n", encoding="utf-8")
|
||||
self._disk_formatted = True
|
||||
return 1
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def _disk_mount(self, uc: Uc, mount_ptr: int) -> int:
|
||||
mount_path = self._normalize_guest_path(self._read_guest_cstring(uc, mount_ptr, EXEC_PATH_MAX))
|
||||
|
||||
if not self._disk_present or not self._disk_formatted:
|
||||
return 0
|
||||
|
||||
if mount_path == "/":
|
||||
return 0
|
||||
|
||||
self._disk_mount_path = mount_path
|
||||
self._disk_mounted = True
|
||||
return 1
|
||||
|
||||
def _disk_mount_path_query(self, uc: Uc, out_ptr: int, out_size: int) -> int:
|
||||
if out_ptr == 0 or out_size == 0:
|
||||
return 0
|
||||
|
||||
if not self._disk_mounted:
|
||||
return 0
|
||||
|
||||
payload = self._normalize_guest_path(self._disk_mount_path).encode("utf-8", errors="replace")
|
||||
max_copy = int(out_size) - 1
|
||||
if max_copy < 0:
|
||||
return 0
|
||||
if len(payload) > max_copy:
|
||||
payload = payload[:max_copy]
|
||||
return len(payload) if self._write_guest_bytes(uc, out_ptr, payload + b"\x00") else 0
|
||||
|
||||
def _fs_mkdir(self, uc: Uc, path_ptr: int) -> int:
|
||||
path = self._normalize_guest_path(self._read_guest_cstring(uc, path_ptr))
|
||||
if not self._guest_path_is_under_temp(path):
|
||||
is_temp_path = self._guest_path_is_under_temp(path)
|
||||
is_disk_path = self._disk_path_is_under_mount(path)
|
||||
|
||||
if not is_temp_path and not is_disk_path:
|
||||
return 0
|
||||
|
||||
if is_disk_path and not self._disk_formatted:
|
||||
return 0
|
||||
|
||||
host_path = self._guest_to_host(path, must_exist=False)
|
||||
@@ -1028,8 +1154,17 @@ class CLeonOSWineNative:
|
||||
|
||||
def _fs_write_common(self, uc: Uc, path_ptr: int, data_ptr: int, size: int, append_mode: bool) -> int:
|
||||
path = self._normalize_guest_path(self._read_guest_cstring(uc, path_ptr))
|
||||
is_temp_path = self._guest_path_is_under_temp(path)
|
||||
is_disk_path = self._disk_path_is_under_mount(path)
|
||||
disk_mount = self._normalize_guest_path(self._disk_mount_path)
|
||||
|
||||
if not self._guest_path_is_under_temp(path) or path == "/temp":
|
||||
if not is_temp_path and not is_disk_path:
|
||||
return 0
|
||||
|
||||
if is_disk_path and not self._disk_formatted:
|
||||
return 0
|
||||
|
||||
if path == "/temp" or (is_disk_path and path == disk_mount):
|
||||
return 0
|
||||
|
||||
if size < 0 or size > self.state.fs_write_max:
|
||||
@@ -1068,8 +1203,17 @@ class CLeonOSWineNative:
|
||||
|
||||
def _fs_remove(self, uc: Uc, path_ptr: int) -> int:
|
||||
path = self._normalize_guest_path(self._read_guest_cstring(uc, path_ptr))
|
||||
is_temp_path = self._guest_path_is_under_temp(path)
|
||||
is_disk_path = self._disk_path_is_under_mount(path)
|
||||
disk_mount = self._normalize_guest_path(self._disk_mount_path)
|
||||
|
||||
if not self._guest_path_is_under_temp(path) or path == "/temp":
|
||||
if not is_temp_path and not is_disk_path:
|
||||
return 0
|
||||
|
||||
if is_disk_path and not self._disk_formatted:
|
||||
return 0
|
||||
|
||||
if path == "/temp" or (is_disk_path and path == disk_mount):
|
||||
return 0
|
||||
|
||||
host_path = self._guest_to_host(path, must_exist=True)
|
||||
@@ -2178,6 +2322,11 @@ class CLeonOSWineNative:
|
||||
|
||||
def _guest_to_host(self, guest_path: str, *, must_exist: bool) -> Optional[Path]:
|
||||
norm = self._normalize_guest_path(guest_path)
|
||||
disk_host = self._disk_guest_to_host(norm, must_exist=must_exist)
|
||||
|
||||
if disk_host is not None:
|
||||
return disk_host
|
||||
|
||||
if norm == "/":
|
||||
return self.rootfs if (not must_exist or self.rootfs.exists()) else None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user