This commit is contained in:
xyou
2026-07-31 13:53:49 +08:00
parent 5ea84fac97
commit f52157b7af
241 changed files with 26843 additions and 8155 deletions
+266
View File
@@ -20,7 +20,9 @@
#include <utsm/vmm.h>
#include <utsm/log.h>
#include <utsm/types.h>
#include <utsm/block.h>
#include <ipc_proto.h>
#include "../../tools/fat32_io.h"
/* ===== 内部辅助 ===== */
@@ -184,13 +186,277 @@ static int lxc_status(char *buf, u64 cap) {
return (int)n;
}
/* ===== Phase 3 文件传输(FILE_LIST / FILE_READ) =====
*
* 同步请求-响应模型(与 exec 相同):
* 1. 构建 ipc_file_request(指定 payload_pool 写入偏移与容量)
* 2. ipc_shm_send 入队 → linux_resume 唤醒 daemon
* 3. daemon 把批量数据直接写进 payload_pool,回 FILE_RESPONSE 后 HLT
* 4. 从 ring 取出响应头,按 data_len 从 payload_pool 拷出数据
*/
/* 发送文件请求并等待响应(公共子流程)。
* msg_type : UTSM_MSG_FILE_LIST_REQUEST / UTSM_MSG_FILE_READ_REQUEST
* path : Linux 绝对路径
* offset : FILE_READ 的文件偏移(LIST 传 0)
* want_cap : 期望读取的最大字节数(会钳制到 payload_pool 容量)
* 成功时 resp 填充并返回 0;失败返回负值(-2 发送失败, -3 resume 失败,
* -4 无响应)。 */
static int lxc_file_roundtrip(u32 msg_type, const char *path, u64 offset,
u32 want_cap, struct ipc_file_response *resp) {
if (!lxc_is_available()) return -1;
if (!path || !resp) return -1;
u32 pool_cap = ipc_shm_payload_capacity();
if (want_cap > pool_cap) want_cap = pool_cap;
struct ipc_file_request req;
my_memzero(&req, sizeof(req));
req.pool_offset = 0; /* 独占使用整个 pool(同步模型,无并发) */
req.pool_capacity = want_cap;
req.file_offset = offset;
u64 plen = my_strlen(path);
if (plen >= UTSM_FILE_PATH_MAX) plen = UTSM_FILE_PATH_MAX - 1;
my_memcpy(req.path, path, plen);
req.path[plen] = 0;
if (ipc_shm_send(msg_type, &req, sizeof(req)) != 0) {
log_warn("[LNXC] file: failed to enqueue request");
return -2;
}
int r = linux_resume();
if (r != 0) {
log_hex64("[LNXC] file: linux_resume failed=", (u64)(i64)r);
return -3;
}
/* 从 ring 中取 FILE_RESPONSE(忽略其间可能残留的 EXEC_* 消息) */
for (int i = 0; i < 256; i++) {
struct utsm_ipc_msg msg;
if (ipc_shm_recv(&msg) != 0) break; /* ring 空 */
if (msg.type == UTSM_MSG_FILE_RESPONSE &&
msg.data_len >= sizeof(struct ipc_file_response)) {
my_memcpy(resp, msg.data, sizeof(*resp));
return 0;
}
}
return -4; /* 无响应 */
}
/* 从 payload_pool 拷出数据到调用方缓冲。返回拷出的字节数。 */
static u64 lxc_pool_copyout(char *buf, u64 cap, u32 data_len) {
if (!buf || cap == 0 || data_len == 0) return 0;
u8 *pool = (u8 *)ipc_shm_payload_ptr(0);
if (!pool) return 0;
u64 n = data_len;
if (n > cap) n = cap;
if (n > ipc_shm_payload_capacity()) n = ipc_shm_payload_capacity();
my_memcpy(buf, pool, n);
return n;
}
static int lxc_file_list(const char *path, char *buf, u64 cap, u64 *out_len) {
struct ipc_file_response resp;
/* 请求的容量取调用方缓冲与 pool 容量的较小值 */
u32 want = (cap > 0xFFFFFFFFULL) ? 0xFFFFFFFFU : (u32)cap;
int rc = lxc_file_roundtrip(UTSM_MSG_FILE_LIST_REQUEST, path, 0, want, &resp);
if (rc != 0) {
if (out_len) *out_len = 0;
return rc;
}
if (resp.status != UTSM_FILE_OK) {
if (out_len) *out_len = 0;
log_hex64("[LNXC] file_list: linux side error=", resp.status);
return -5;
}
u64 n = lxc_pool_copyout(buf, cap, resp.data_len);
if (out_len) *out_len = n;
/* Linux 侧写出的数据超过调用方缓冲 → 截断提示 */
if (resp.data_len > n) return -6;
return 0;
}
static int lxc_file_read(const char *path, u64 offset, char *buf, u64 cap,
u64 *out_len, u64 *out_total) {
struct ipc_file_response resp;
u32 want = (cap > 0xFFFFFFFFULL) ? 0xFFFFFFFFU : (u32)cap;
int rc = lxc_file_roundtrip(UTSM_MSG_FILE_READ_REQUEST, path, offset, want, &resp);
if (rc != 0) {
if (out_len) *out_len = 0;
if (out_total) *out_total = 0;
return rc;
}
if (out_total) *out_total = resp.total_size;
if (resp.status != UTSM_FILE_OK) {
if (out_len) *out_len = 0;
log_hex64("[LNXC] file_read: linux side error=", resp.status);
return -5;
}
u64 n = lxc_pool_copyout(buf, cap, resp.data_len);
if (out_len) *out_len = n;
if (resp.data_len > n) return -6;
return 0;
}
/* 写入 Linux 文件:把调用方数据先搬进 payload_pool,再走同步请求-响应。
* 单次最多搬运 payload pool 容量(~1MB),大文件由调用方循环推进 offset。 */
static int lxc_file_write(const char *path, u64 offset, const char *buf,
u64 len, u64 *out_written) {
if (!lxc_is_available()) return -1;
if (!path || (!buf && len > 0)) return -1;
u32 pool_cap = ipc_shm_payload_capacity();
u64 n = len;
if (n > pool_cap) n = pool_cap;
if (n > 0) {
u8 *pool = (u8 *)ipc_shm_payload_ptr(0);
if (!pool) return -1;
my_memcpy(pool, buf, n);
utsm_ipc_mb(); /* 保证 pool 数据先于请求对 guest 可见 */
}
/* 复用公共子流程:WRITE 时 pool_capacity 字段表示已 staged 的字节数 */
struct ipc_file_response resp;
int rc = lxc_file_roundtrip(UTSM_MSG_FILE_WRITE_REQUEST, path, offset,
(u32)n, &resp);
if (rc != 0) {
if (out_written) *out_written = 0;
return rc;
}
if (resp.status != UTSM_FILE_OK) {
if (out_written) *out_written = 0;
log_hex64("[LNXC] file_write: linux side error=", resp.status);
return -5;
}
if (out_written) *out_written = resp.data_len;
return 0;
}
/* ===== UTSM FAT32 系统盘接入(file_pull / file_push / hypercall 共用) =====
*
* 复用 tools/fat32_io.h(static inline 库,仅根目录、单文件 ≤256KB),
* block 读写函数指针来自 UTSM block 注册表(block_get_api(),
* 等价于 DSK 侧 dkm_kernel_api +0xA8 block_read / +0x18 block_write)。 */
static int g_f32_inited; /* 1 = f32_init 已完成 */
/* 惰性初始化 FAT32 库。返回 0 可用,-9 无块设备。 */
static int lxc_f32_ensure(void) {
const dkm_block_api *api = block_get_api();
if (!api || !api->read || !api->write) return -9;
if (api->device_count() == 0) return -9;
if (!g_f32_inited) {
f32_init(api->read, api->write);
g_f32_inited = 1;
}
return 0;
}
int lxc_f32_read_file(const char *name, u8 **out_data, u32 *out_size) {
if (!name || !out_data || !out_size) return -10;
int rc = lxc_f32_ensure();
if (rc != 0) return rc;
char n11[11];
if (f32_name_to_83(name, n11) != 0) return -10;
int fr = f32_read_root_file(n11, out_data, out_size);
if (fr == -5) return -11; /* 根目录中未找到 */
if (fr != 0) return -12; /* 磁盘 / 格式错误 */
return 0;
}
int lxc_f32_write_file(const char *name, const u8 *data, u32 size) {
if (!name || (!data && size > 0)) return -10;
int rc = lxc_f32_ensure();
if (rc != 0) return rc;
char n11[11];
if (f32_name_to_83(name, n11) != 0) return -10;
if (f32_write_root_file(n11, data, size) != 0) return -12;
return 0;
}
/* pull 暂存缓冲:与 fat32_io 单文件上限一致(256KB) */
static u8 g_pull_stage[262144];
/* 跨内核拉取:Linux 文件 → UTSM FAT32 根目录。
* 先经 IPC 分块读完整文件到暂存缓冲(失败则不写盘,避免半成品),
* 再一次 f32_write_root_file 落盘。 */
static int lxc_file_pull(const char *linux_path, const char *fat32_name,
u64 *out_size) {
if (!lxc_is_available()) return -1;
if (!linux_path || !fat32_name) return -1;
int rc = lxc_f32_ensure();
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
u64 off = 0;
u64 total = 0;
for (;;) {
u64 got = 0;
u64 space = (u64)sizeof(g_pull_stage) - off;
if (space == 0) {
if (out_size) *out_size = 0;
return -7; /* 超过 256KB 暂存上限 */
}
rc = lxc_file_read(linux_path, off, (char *)g_pull_stage + off,
space, &got, &total);
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
off += got;
if (got == 0 || off >= total) break;
}
rc = lxc_f32_write_file(fat32_name, g_pull_stage, (u32)off);
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
if (out_size) *out_size = off;
return 0;
}
/* 跨内核推送:UTSM FAT32 根目录 → Linux 文件(整文件替换)。
* f32_read_root_file 读出后经 lxc_file_write 按 pool 容量分块写入;
* 首块 offset=0 → daemon 侧 O_TRUNC,实现整文件替换语义。 */
static int lxc_file_push(const char *fat32_name, const char *linux_path,
u64 *out_size) {
if (!lxc_is_available()) return -1;
if (!fat32_name || !linux_path) return -1;
u8 *data = 0;
u32 size = 0;
int rc = lxc_f32_read_file(fat32_name, &data, &size);
if (rc != 0) { if (out_size) *out_size = 0; return rc; }
u32 pool_cap = ipc_shm_payload_capacity();
u64 off = 0;
for (;;) {
u64 remain = (u64)size - off;
u64 chunk = remain > pool_cap ? pool_cap : remain;
u64 written = 0;
rc = lxc_file_write(linux_path, off, (const char *)data + off,
chunk, &written);
if (rc != 0) { if (out_size) *out_size = off; return rc; }
if (written != chunk) { /* 短写:按 I/O 错误处理 */
if (out_size) *out_size = off + written;
return -5;
}
off += written;
if (off >= size) break;
}
if (out_size) *out_size = off;
return 0;
}
/* ===== 服务表 ===== */
static const linux_compat_service g_lxc_service = {
LINUX_COMPAT_MAGIC,
lxc_is_available,
lxc_exec,
lxc_file_list,
lxc_file_read,
lxc_status,
lxc_file_write,
lxc_file_pull,
lxc_file_push,
};
const linux_compat_service *linux_compat_get_service(void) {