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
+149
View File
@@ -52,6 +52,10 @@
#define UTSM_IOCTL_SEND_MSG _IOWR('U', 2, struct utsm_ioctl_msg)
#define UTSM_IOCTL_PARK _IO('U', 3)
#define UTSM_IOCTL_GET_READY _IOR('U', 4, int)
#define UTSM_IOCTL_WRITE_POOL _IOW('U', 5, struct utsm_ioctl_pool)
#define UTSM_IOCTL_READ_POOL _IOWR('U', 6, struct utsm_ioctl_pool)
#define UTSM_IOCTL_HOST_READ _IOWR('U', 7, struct utsm_ioctl_hostfile)
#define UTSM_IOCTL_HOST_WRITE _IOW('U', 8, struct utsm_ioctl_hostfile)
/* Ioctl message wrapper: carries type + data in a single call */
struct utsm_ioctl_msg {
@@ -62,6 +66,29 @@ struct utsm_ioctl_msg {
u8 data[UTSM_IPC_MSG_DATA_SIZE]; /* payload */
};
/* Pool transfer descriptor for WRITE_POOL / READ_POOL ioctls.
* Used by the exec daemon to stage large file-transfer payloads into the
* shared payload_pool (bulk data channel for UTSM_MSG_FILE_RESPONSE). */
struct utsm_ioctl_pool {
u32 offset; /* byte offset into payload_pool */
u32 len; /* bytes to transfer */
u64 user_buf; /* userspace buffer pointer */
};
/* Host-file transfer descriptor for HOST_READ / HOST_WRITE ioctls.
* Gives Linux userspace access to files on the UTSM-side FAT32 system disk
* (root directory, 8.3-convertible names, whole-file semantics, max 256KB)
* via the UTSM_HCALL_FILE_READ / UTSM_HCALL_FILE_WRITE hypercalls.
* payload_pool at offset 0 is the bulk data buffer in both directions. */
struct utsm_ioctl_hostfile {
u64 offset; /* in: file offset (HOST_READ; must be 0 for HOST_WRITE) */
u32 len; /* in: requested length; out: bytes transferred */
u32 reserved;
u64 total; /* out: total file size (HOST_READ) */
u64 user_buf; /* userspace buffer pointer */
char name[64]; /* UTSM FAT32 root file name (NUL-terminated) */
};
/* ===== Hypercall ABI =====
*
* Linux calls VMCALL with:
@@ -121,6 +148,23 @@ static inline long utsm_hcall_console_write(const char *buf, u64 len)
return utsm_hcall(UTSM_HCALL_CONSOLE_WRITE, (u64)buf, len, 0);
}
/* UTSM FAT32 file read: stages file[offset..offset+len) into payload_pool.
* Returns positive packed value (low 20 bits = staged bytes, >> 20 = total
* file size) or a negative UTSM_HCALL_* error. The name pointer follows the
* same GVA==GPA identity-mapping convention as the other hypercalls. */
static inline long utsm_hcall_file_read(const char *name, u64 offset, u64 len)
{
return utsm_hcall(UTSM_HCALL_FILE_READ, (u64)name, offset, len);
}
/* UTSM FAT32 file write: writes len bytes staged at payload_pool[0] as the
* whole new content of the named root file (create or replace).
* Returns bytes written or a negative UTSM_HCALL_* error. */
static inline long utsm_hcall_file_write(const char *name, u64 len)
{
return utsm_hcall(UTSM_HCALL_FILE_WRITE, (u64)name, 0, len);
}
/* ===== Shared memory state ===== */
static struct utsm_ipc_shm *g_shm; /* kernel virtual address of SHM */
@@ -284,6 +328,111 @@ static long utsm_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return 0;
}
case UTSM_IOCTL_WRITE_POOL: {
/* Copy userspace data into payload_pool (daemon → UTSM bulk data) */
struct utsm_ioctl_pool p;
if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
return -EFAULT;
if (p.offset > UTSM_IPC_PAYLOAD_SIZE ||
p.len > UTSM_IPC_PAYLOAD_SIZE - p.offset)
return -EINVAL;
if (p.len == 0)
return 0;
if (copy_from_user(g_shm->payload_pool + p.offset,
(void __user *)(uintptr_t)p.user_buf, p.len))
return -EFAULT;
mb(); /* ensure pool data visible to UTSM before response msg */
return 0;
}
case UTSM_IOCTL_READ_POOL: {
/* Copy payload_pool data to userspace (UTSM → daemon bulk data) */
struct utsm_ioctl_pool p;
if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
return -EFAULT;
if (p.offset > UTSM_IPC_PAYLOAD_SIZE ||
p.len > UTSM_IPC_PAYLOAD_SIZE - p.offset)
return -EINVAL;
if (p.len == 0)
return 0;
if (copy_to_user((void __user *)(uintptr_t)p.user_buf,
g_shm->payload_pool + p.offset, p.len))
return -EFAULT;
return 0;
}
case UTSM_IOCTL_HOST_READ: {
/* Read a file from the UTSM FAT32 disk into userspace.
* Hypercall stages the chunk into payload_pool, we relay it out. */
struct utsm_ioctl_hostfile hf;
char kname[64];
long ret;
u32 n;
if (copy_from_user(&hf, (void __user *)arg, sizeof(hf)))
return -EFAULT;
if (hf.len == 0 || hf.len > UTSM_IPC_PAYLOAD_SIZE)
return -EINVAL;
if (!hf.user_buf)
return -EINVAL;
memcpy(kname, hf.name, sizeof(kname));
kname[sizeof(kname) - 1] = '\0';
ret = utsm_hcall_file_read(kname, hf.offset, hf.len);
if (ret < 0) {
if (ret == UTSM_HCALL_NOENT) return -ENOENT;
if (ret == UTSM_HCALL_INVAL) return -EINVAL;
if (ret == UTSM_HCALL_NOMEM) return -ENOMEM;
return -EIO;
}
n = (u32)(ret & 0xFFFFF);
hf.total = (u64)ret >> 20;
if (n > hf.len)
n = hf.len; /* defensive: never overflow the user buffer */
if (n > 0 &&
copy_to_user((void __user *)(uintptr_t)hf.user_buf,
g_shm->payload_pool, n))
return -EFAULT;
hf.len = n;
if (copy_to_user((void __user *)arg, &hf, sizeof(hf)))
return -EFAULT;
return 0;
}
case UTSM_IOCTL_HOST_WRITE: {
/* Write userspace data as the whole content of a UTSM FAT32 file.
* Stage into payload_pool first, then hypercall to commit. */
struct utsm_ioctl_hostfile hf;
char kname[64];
long ret;
if (copy_from_user(&hf, (void __user *)arg, sizeof(hf)))
return -EFAULT;
if (hf.len > UTSM_IPC_PAYLOAD_SIZE)
return -EINVAL;
if (hf.len > 0 && !hf.user_buf)
return -EINVAL;
memcpy(kname, hf.name, sizeof(kname));
kname[sizeof(kname) - 1] = '\0';
if (hf.len > 0 &&
copy_from_user(g_shm->payload_pool,
(void __user *)(uintptr_t)hf.user_buf, hf.len))
return -EFAULT;
mb(); /* ensure pool data visible to UTSM before the hypercall */
ret = utsm_hcall_file_write(kname, hf.len);
if (ret < 0) {
if (ret == UTSM_HCALL_INVAL) return -EINVAL;
if (ret == UTSM_HCALL_NOMEM) return -ENOMEM;
return -EIO;
}
return 0;
}
default:
return -ENOTTY;
}