mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-24 11:14:01 +00:00
partctl
This commit is contained in:
@@ -111,6 +111,10 @@ grep -n exec /shell/init.cmd
|
||||
cat /shell/init.cmd | grep -n exec
|
||||
ls /shell > /temp/shell_list.txt
|
||||
diskinfo
|
||||
partctl list
|
||||
partctl init-mbr
|
||||
partctl create 1 2048 32768 0x0C 1
|
||||
partctl delete 1
|
||||
mkfsfat32 CLEONOS
|
||||
mount /temp/disk
|
||||
write /temp/disk/hello.txt hello-disk
|
||||
|
||||
@@ -111,6 +111,10 @@ grep -n exec /shell/init.cmd
|
||||
cat /shell/init.cmd | grep -n exec
|
||||
ls /shell > /temp/shell_list.txt
|
||||
diskinfo
|
||||
partctl list
|
||||
partctl init-mbr
|
||||
partctl create 1 2048 32768 0x0C 1
|
||||
partctl delete 1
|
||||
mkfsfat32 CLEONOS
|
||||
mount /temp/disk
|
||||
write /temp/disk/hello.txt hello-disk
|
||||
|
||||
@@ -130,7 +130,7 @@ set(USER_SHELL_COMMAND_APPS
|
||||
help args ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield
|
||||
bg fg jobs kill ps top
|
||||
procstat sysstat
|
||||
diskinfo mkfsfat32 mount
|
||||
diskinfo mkfsfat32 mount partctl
|
||||
shutdown restart exit clear ansi ansitest wavplay fastfetch memstat fsstat taskstat userstat
|
||||
shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm kdbg bmpview qrcode
|
||||
)
|
||||
|
||||
@@ -32,6 +32,7 @@ static int ush_cmd_help(void) {
|
||||
ush_writeln(" diskinfo");
|
||||
ush_writeln(" mkfsfat32 [label]");
|
||||
ush_writeln(" mount [path] (default suggested: /temp/disk)");
|
||||
ush_writeln(" partctl <subcommand> (mbr partition control: list/init-mbr/create/delete/set-boot)");
|
||||
ush_writeln(" pid");
|
||||
ush_writeln(" spawn <path|name> [args...] / bg <path|name> [args...]");
|
||||
ush_writeln(" wait <pid> / fg [pid]");
|
||||
|
||||
469
cleonos/c/apps/partctl_main.c
Normal file
469
cleonos/c/apps/partctl_main.c
Normal file
@@ -0,0 +1,469 @@
|
||||
#include "cmd_runtime.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PARTCTL_SECTOR_SIZE 512U
|
||||
#define PARTCTL_MBR_ENTRY_OFFSET 446U
|
||||
#define PARTCTL_MBR_ENTRY_SIZE 16U
|
||||
#define PARTCTL_MBR_ENTRY_COUNT 4U
|
||||
#define PARTCTL_MBR_SIG_OFFSET 510U
|
||||
|
||||
static unsigned int partctl_read_u32_le(const unsigned char *ptr) {
|
||||
return (unsigned int)ptr[0] | ((unsigned int)ptr[1] << 8U) | ((unsigned int)ptr[2] << 16U) | ((unsigned int)ptr[3] << 24U);
|
||||
}
|
||||
|
||||
static void partctl_write_u32_le(unsigned char *ptr, unsigned int value) {
|
||||
ptr[0] = (unsigned char)(value & 0xFFU);
|
||||
ptr[1] = (unsigned char)((value >> 8U) & 0xFFU);
|
||||
ptr[2] = (unsigned char)((value >> 16U) & 0xFFU);
|
||||
ptr[3] = (unsigned char)((value >> 24U) & 0xFFU);
|
||||
}
|
||||
|
||||
static int partctl_parse_u64(const char *text, u64 *out_value) {
|
||||
char *end = (char *)0;
|
||||
unsigned long long value;
|
||||
|
||||
if (text == (const char *)0 || text[0] == '\0' || out_value == (u64 *)0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = strtoull(text, &end, 0);
|
||||
if (end == text || *end != '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_value = (u64)value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_tokenize(const char *arg, char tokens[][USH_ARG_MAX], int max_tokens) {
|
||||
int count = 0;
|
||||
u64 i = 0ULL;
|
||||
|
||||
if (arg == (const char *)0 || max_tokens <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (arg[i] != '\0' && count < max_tokens) {
|
||||
u64 tlen = 0ULL;
|
||||
|
||||
while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (arg[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
while (arg[i] != '\0' && ush_is_space(arg[i]) == 0) {
|
||||
if (tlen + 1ULL < USH_ARG_MAX) {
|
||||
tokens[count][tlen++] = arg[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
tokens[count][tlen] = '\0';
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int partctl_disk_required(void) {
|
||||
if (cleonos_sys_disk_present() == 0ULL) {
|
||||
(void)fputs("partctl: disk not present\n", 1);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_read_sector0(unsigned char *sector) {
|
||||
if (sector == (unsigned char *)0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_disk_required() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cleonos_sys_disk_read_sector(0ULL, (void *)sector) == 0ULL) {
|
||||
(void)fputs("partctl: read sector0 failed\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_write_sector0(const unsigned char *sector) {
|
||||
if (sector == (const unsigned char *)0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_disk_required() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cleonos_sys_disk_write_sector(0ULL, (const void *)sector) == 0ULL) {
|
||||
(void)fputs("partctl: write sector0 failed\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_mbr_has_signature(const unsigned char *sector) {
|
||||
return (sector[PARTCTL_MBR_SIG_OFFSET] == 0x55U && sector[PARTCTL_MBR_SIG_OFFSET + 1U] == 0xAAU) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void partctl_mbr_ensure_signature(unsigned char *sector) {
|
||||
sector[PARTCTL_MBR_SIG_OFFSET] = 0x55U;
|
||||
sector[PARTCTL_MBR_SIG_OFFSET + 1U] = 0xAAU;
|
||||
}
|
||||
|
||||
static void partctl_usage(void) {
|
||||
(void)fputs("partctl usage:\n", 1);
|
||||
(void)fputs(" partctl list\n", 1);
|
||||
(void)fputs(" partctl init-mbr\n", 1);
|
||||
(void)fputs(" partctl create <index:1-4> <start_lba> <sectors> <type_hex> [boot:0|1]\n", 1);
|
||||
(void)fputs(" partctl delete <index:1-4>\n", 1);
|
||||
(void)fputs(" partctl set-boot <index:1-4> <0|1>\n", 1);
|
||||
}
|
||||
|
||||
static int partctl_cmd_list(void) {
|
||||
unsigned char sector[PARTCTL_SECTOR_SIZE];
|
||||
u64 disk_sectors;
|
||||
u64 i;
|
||||
int has_any = 0;
|
||||
|
||||
if (partctl_read_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
disk_sectors = cleonos_sys_disk_sector_count();
|
||||
(void)printf("disk.sectors: %llu\n", (unsigned long long)disk_sectors);
|
||||
(void)printf("mbr.signature: %s\n", partctl_mbr_has_signature(sector) != 0 ? "0x55AA" : "invalid");
|
||||
(void)fputs("idx boot type start_lba sectors end_lba\n", 1);
|
||||
|
||||
for (i = 0ULL; i < PARTCTL_MBR_ENTRY_COUNT; i++) {
|
||||
u64 off = PARTCTL_MBR_ENTRY_OFFSET + (i * PARTCTL_MBR_ENTRY_SIZE);
|
||||
unsigned char boot = sector[off + 0ULL];
|
||||
unsigned char type = sector[off + 4ULL];
|
||||
unsigned int start = partctl_read_u32_le(§or[off + 8ULL]);
|
||||
unsigned int size = partctl_read_u32_le(§or[off + 12ULL]);
|
||||
u64 end_lba = 0ULL;
|
||||
|
||||
if (size != 0U) {
|
||||
has_any = 1;
|
||||
end_lba = (u64)start + (u64)size - 1ULL;
|
||||
}
|
||||
|
||||
(void)printf("%llu %s 0x%02X %-12llu %-12llu ",
|
||||
(unsigned long long)(i + 1ULL), (boot == 0x80U) ? "yes " : "no ", (unsigned int)type,
|
||||
(unsigned long long)start, (unsigned long long)size);
|
||||
|
||||
if (size == 0U) {
|
||||
(void)fputs("-\n", 1);
|
||||
} else {
|
||||
(void)printf("%llu\n", (unsigned long long)end_lba);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_any == 0) {
|
||||
(void)fputs("partctl: no partition entries\n", 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_check_overlap(const unsigned char *sector, u64 skip_index, u64 start, u64 sectors) {
|
||||
u64 i;
|
||||
u64 end = start + sectors;
|
||||
|
||||
for (i = 0ULL; i < PARTCTL_MBR_ENTRY_COUNT; i++) {
|
||||
u64 off;
|
||||
unsigned int ex_start;
|
||||
unsigned int ex_size;
|
||||
u64 ex_end;
|
||||
|
||||
if (i == skip_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
off = PARTCTL_MBR_ENTRY_OFFSET + (i * PARTCTL_MBR_ENTRY_SIZE);
|
||||
ex_start = partctl_read_u32_le(§or[off + 8ULL]);
|
||||
ex_size = partctl_read_u32_le(§or[off + 12ULL]);
|
||||
|
||||
if (ex_size == 0U) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ex_end = (u64)ex_start + (u64)ex_size;
|
||||
if (!(end <= (u64)ex_start || start >= ex_end)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_cmd_init_mbr(void) {
|
||||
unsigned char sector[PARTCTL_SECTOR_SIZE];
|
||||
|
||||
if (partctl_disk_required() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ush_zero((void *)sector, (u64)sizeof(sector));
|
||||
partctl_mbr_ensure_signature(sector);
|
||||
|
||||
if (partctl_write_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)fputs("partctl: MBR initialized\n", 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_cmd_delete(const char *index_text) {
|
||||
unsigned char sector[PARTCTL_SECTOR_SIZE];
|
||||
u64 index = 0ULL;
|
||||
u64 off;
|
||||
|
||||
if (partctl_parse_u64(index_text, &index) == 0 || index < 1ULL || index > PARTCTL_MBR_ENTRY_COUNT) {
|
||||
(void)fputs("partctl: delete usage: partctl delete <index:1-4>\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_read_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
off = PARTCTL_MBR_ENTRY_OFFSET + ((index - 1ULL) * PARTCTL_MBR_ENTRY_SIZE);
|
||||
ush_zero((void *)§or[off], PARTCTL_MBR_ENTRY_SIZE);
|
||||
partctl_mbr_ensure_signature(sector);
|
||||
|
||||
if (partctl_write_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)printf("partctl: deleted partition %llu\n", (unsigned long long)index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_cmd_set_boot(const char *index_text, const char *value_text) {
|
||||
unsigned char sector[PARTCTL_SECTOR_SIZE];
|
||||
u64 index = 0ULL;
|
||||
u64 value = 0ULL;
|
||||
u64 off;
|
||||
u64 i;
|
||||
|
||||
if (partctl_parse_u64(index_text, &index) == 0 || index < 1ULL || index > PARTCTL_MBR_ENTRY_COUNT) {
|
||||
(void)fputs("partctl: set-boot usage: partctl set-boot <index:1-4> <0|1>\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_parse_u64(value_text, &value) == 0 || (value != 0ULL && value != 1ULL)) {
|
||||
(void)fputs("partctl: set-boot usage: partctl set-boot <index:1-4> <0|1>\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_read_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0ULL; i < PARTCTL_MBR_ENTRY_COUNT; i++) {
|
||||
u64 eoff = PARTCTL_MBR_ENTRY_OFFSET + (i * PARTCTL_MBR_ENTRY_SIZE);
|
||||
if (value != 0ULL && (i + 1ULL) != index) {
|
||||
sector[eoff] = 0x00U;
|
||||
}
|
||||
}
|
||||
|
||||
off = PARTCTL_MBR_ENTRY_OFFSET + ((index - 1ULL) * PARTCTL_MBR_ENTRY_SIZE);
|
||||
sector[off] = (value != 0ULL) ? 0x80U : 0x00U;
|
||||
partctl_mbr_ensure_signature(sector);
|
||||
|
||||
if (partctl_write_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)printf("partctl: partition %llu boot flag=%llu\n", (unsigned long long)index, (unsigned long long)value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_cmd_create(const char *index_text, const char *start_text, const char *sectors_text,
|
||||
const char *type_text, const char *boot_text) {
|
||||
unsigned char sector[PARTCTL_SECTOR_SIZE];
|
||||
u64 index = 0ULL;
|
||||
u64 start_lba = 0ULL;
|
||||
u64 sectors = 0ULL;
|
||||
u64 type = 0ULL;
|
||||
u64 boot = 0ULL;
|
||||
u64 disk_sectors;
|
||||
u64 off;
|
||||
u64 i;
|
||||
|
||||
if (partctl_parse_u64(index_text, &index) == 0 || index < 1ULL || index > PARTCTL_MBR_ENTRY_COUNT) {
|
||||
(void)fputs("partctl: create invalid index\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_parse_u64(start_text, &start_lba) == 0 || partctl_parse_u64(sectors_text, §ors) == 0 ||
|
||||
partctl_parse_u64(type_text, &type) == 0) {
|
||||
(void)fputs("partctl: create invalid number\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (boot_text != (const char *)0 && boot_text[0] != '\0') {
|
||||
if (partctl_parse_u64(boot_text, &boot) == 0 || (boot != 0ULL && boot != 1ULL)) {
|
||||
(void)fputs("partctl: create invalid boot flag (expected 0|1)\n", 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_lba == 0ULL || sectors == 0ULL) {
|
||||
(void)fputs("partctl: start_lba and sectors must be > 0\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type > 0xFFULL || start_lba > 0xFFFFFFFFULL || sectors > 0xFFFFFFFFULL) {
|
||||
(void)fputs("partctl: MBR supports only 32-bit LBA/size and 8-bit type\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
disk_sectors = cleonos_sys_disk_sector_count();
|
||||
if (start_lba >= disk_sectors || sectors > disk_sectors || (start_lba + sectors) > disk_sectors ||
|
||||
(start_lba + sectors) < start_lba) {
|
||||
(void)fputs("partctl: range exceeds disk size\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_read_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (partctl_check_overlap(sector, index - 1ULL, start_lba, sectors) == 0) {
|
||||
(void)fputs("partctl: range overlaps an existing partition\n", 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (boot != 0ULL) {
|
||||
for (i = 0ULL; i < PARTCTL_MBR_ENTRY_COUNT; i++) {
|
||||
u64 eoff = PARTCTL_MBR_ENTRY_OFFSET + (i * PARTCTL_MBR_ENTRY_SIZE);
|
||||
sector[eoff] = 0x00U;
|
||||
}
|
||||
}
|
||||
|
||||
off = PARTCTL_MBR_ENTRY_OFFSET + ((index - 1ULL) * PARTCTL_MBR_ENTRY_SIZE);
|
||||
ush_zero((void *)§or[off], PARTCTL_MBR_ENTRY_SIZE);
|
||||
sector[off + 0ULL] = (boot != 0ULL) ? 0x80U : 0x00U;
|
||||
sector[off + 1ULL] = 0xFFU;
|
||||
sector[off + 2ULL] = 0xFFU;
|
||||
sector[off + 3ULL] = 0xFFU;
|
||||
sector[off + 4ULL] = (unsigned char)type;
|
||||
sector[off + 5ULL] = 0xFFU;
|
||||
sector[off + 6ULL] = 0xFFU;
|
||||
sector[off + 7ULL] = 0xFFU;
|
||||
partctl_write_u32_le(§or[off + 8ULL], (unsigned int)start_lba);
|
||||
partctl_write_u32_le(§or[off + 12ULL], (unsigned int)sectors);
|
||||
partctl_mbr_ensure_signature(sector);
|
||||
|
||||
if (partctl_write_sector0(sector) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)printf("partctl: created p%llu start=%llu sectors=%llu type=0x%02X boot=%llu\n",
|
||||
(unsigned long long)index, (unsigned long long)start_lba, (unsigned long long)sectors,
|
||||
(unsigned int)((unsigned char)type), (unsigned long long)boot);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int partctl_run(const char *arg) {
|
||||
char tokens[8][USH_ARG_MAX];
|
||||
int token_count = partctl_tokenize(arg, tokens, 8);
|
||||
|
||||
if (token_count == 0 || ush_streq(tokens[0], "help") != 0) {
|
||||
partctl_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ush_streq(tokens[0], "list") != 0) {
|
||||
return partctl_cmd_list();
|
||||
}
|
||||
|
||||
if (ush_streq(tokens[0], "init-mbr") != 0) {
|
||||
return partctl_cmd_init_mbr();
|
||||
}
|
||||
|
||||
if (ush_streq(tokens[0], "delete") != 0) {
|
||||
if (token_count != 2) {
|
||||
partctl_usage();
|
||||
return 0;
|
||||
}
|
||||
return partctl_cmd_delete(tokens[1]);
|
||||
}
|
||||
|
||||
if (ush_streq(tokens[0], "set-boot") != 0) {
|
||||
if (token_count != 3) {
|
||||
partctl_usage();
|
||||
return 0;
|
||||
}
|
||||
return partctl_cmd_set_boot(tokens[1], tokens[2]);
|
||||
}
|
||||
|
||||
if (ush_streq(tokens[0], "create") != 0) {
|
||||
if (token_count != 5 && token_count != 6) {
|
||||
partctl_usage();
|
||||
return 0;
|
||||
}
|
||||
return partctl_cmd_create(tokens[1], tokens[2], tokens[3], tokens[4], (token_count == 6) ? tokens[5] : "");
|
||||
}
|
||||
|
||||
(void)fputs("partctl: unknown subcommand\n", 1);
|
||||
partctl_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cleonos_app_main(void) {
|
||||
ush_cmd_ctx ctx;
|
||||
ush_cmd_ret ret;
|
||||
ush_state sh;
|
||||
char initial_cwd[USH_PATH_MAX];
|
||||
int has_context = 0;
|
||||
int success = 0;
|
||||
const char *arg = "";
|
||||
|
||||
ush_zero(&ctx, (u64)sizeof(ctx));
|
||||
ush_zero(&ret, (u64)sizeof(ret));
|
||||
ush_init_state(&sh);
|
||||
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
|
||||
|
||||
if (ush_command_ctx_read(&ctx) != 0) {
|
||||
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "partctl") != 0) {
|
||||
has_context = 1;
|
||||
arg = ctx.arg;
|
||||
if (ctx.cwd[0] == '/') {
|
||||
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
|
||||
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
success = partctl_run(arg);
|
||||
|
||||
if (has_context != 0) {
|
||||
if (ush_streq(sh.cwd, initial_cwd) == 0) {
|
||||
ret.flags |= USH_CMD_RET_FLAG_CWD;
|
||||
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
|
||||
}
|
||||
|
||||
if (sh.exit_requested != 0) {
|
||||
ret.flags |= USH_CMD_RET_FLAG_EXIT;
|
||||
ret.exit_code = sh.exit_code;
|
||||
}
|
||||
|
||||
(void)ush_command_ret_write(&ret);
|
||||
}
|
||||
|
||||
return (success != 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -153,6 +153,8 @@ typedef struct cleonos_fb_blit_req {
|
||||
#define CLEONOS_SYSCALL_DISK_MOUNT 90ULL
|
||||
#define CLEONOS_SYSCALL_DISK_MOUNTED 91ULL
|
||||
#define CLEONOS_SYSCALL_DISK_MOUNT_PATH 92ULL
|
||||
#define CLEONOS_SYSCALL_DISK_READ_SECTOR 93ULL
|
||||
#define CLEONOS_SYSCALL_DISK_WRITE_SECTOR 94ULL
|
||||
|
||||
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
u64 cleonos_sys_log_write(const char *message, u64 length);
|
||||
@@ -248,5 +250,7 @@ u64 cleonos_sys_disk_format_fat32(const char *label);
|
||||
u64 cleonos_sys_disk_mount(const char *mount_path);
|
||||
u64 cleonos_sys_disk_mounted(void);
|
||||
u64 cleonos_sys_disk_mount_path(char *out_path, u64 out_size);
|
||||
u64 cleonos_sys_disk_read_sector(u64 lba, void *out_sector);
|
||||
u64 cleonos_sys_disk_write_sector(u64 lba, const void *sector_data);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -403,3 +403,11 @@ u64 cleonos_sys_disk_mounted(void) {
|
||||
u64 cleonos_sys_disk_mount_path(char *out_path, u64 out_size) {
|
||||
return cleonos_syscall(CLEONOS_SYSCALL_DISK_MOUNT_PATH, (u64)out_path, out_size, 0ULL);
|
||||
}
|
||||
|
||||
u64 cleonos_sys_disk_read_sector(u64 lba, void *out_sector) {
|
||||
return cleonos_syscall(CLEONOS_SYSCALL_DISK_READ_SECTOR, lba, (u64)out_sector, 0ULL);
|
||||
}
|
||||
|
||||
u64 cleonos_sys_disk_write_sector(u64 lba, const void *sector_data) {
|
||||
return cleonos_syscall(CLEONOS_SYSCALL_DISK_WRITE_SECTOR, lba, (u64)sector_data, 0ULL);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,8 @@
|
||||
#define CLKS_SYSCALL_DISK_MOUNT 90ULL
|
||||
#define CLKS_SYSCALL_DISK_MOUNTED 91ULL
|
||||
#define CLKS_SYSCALL_DISK_MOUNT_PATH 92ULL
|
||||
#define CLKS_SYSCALL_DISK_READ_SECTOR 93ULL
|
||||
#define CLKS_SYSCALL_DISK_WRITE_SECTOR 94ULL
|
||||
|
||||
void clks_syscall_init(void);
|
||||
u64 clks_syscall_dispatch(void *frame_ptr);
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
#define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL)
|
||||
#define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym"
|
||||
#define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL
|
||||
#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_DISK_MOUNT_PATH
|
||||
#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_DISK_WRITE_SECTOR
|
||||
#define CLKS_SYSCALL_DISK_SECTOR_BYTES 512U
|
||||
#define CLKS_SYSCALL_STATS_RING_SIZE 256U
|
||||
#define CLKS_SYSCALL_USC_MAX_ALLOWED_APPS 64U
|
||||
|
||||
@@ -530,6 +531,40 @@ static u64 clks_syscall_disk_mount_path(u64 arg0, u64 arg1) {
|
||||
return clks_syscall_copy_text_to_user(arg0, arg1, mount_path, clks_strlen(mount_path));
|
||||
}
|
||||
|
||||
static u64 clks_syscall_disk_read_sector(u64 arg0, u64 arg1) {
|
||||
u8 sector[CLKS_SYSCALL_DISK_SECTOR_BYTES];
|
||||
|
||||
if (arg1 == 0ULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
if (clks_syscall_user_ptr_writable(arg1, (u64)CLKS_SYSCALL_DISK_SECTOR_BYTES) == CLKS_FALSE) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
if (clks_disk_read_sector(arg0, (void *)sector) == CLKS_FALSE) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
clks_memcpy((void *)arg1, sector, (usize)CLKS_SYSCALL_DISK_SECTOR_BYTES);
|
||||
return 1ULL;
|
||||
}
|
||||
|
||||
static u64 clks_syscall_disk_write_sector(u64 arg0, u64 arg1) {
|
||||
u8 sector[CLKS_SYSCALL_DISK_SECTOR_BYTES];
|
||||
|
||||
if (arg1 == 0ULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
if (clks_syscall_user_ptr_readable(arg1, (u64)CLKS_SYSCALL_DISK_SECTOR_BYTES) == CLKS_FALSE) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
clks_memcpy(sector, (const void *)arg1, (usize)CLKS_SYSCALL_DISK_SECTOR_BYTES);
|
||||
return (clks_disk_write_sector(arg0, (const void *)sector) == CLKS_TRUE) ? 1ULL : 0ULL;
|
||||
}
|
||||
|
||||
static u64 clks_syscall_fd_open(u64 arg0, u64 arg1, u64 arg2) {
|
||||
char path[CLKS_SYSCALL_PATH_MAX];
|
||||
|
||||
@@ -2061,6 +2096,10 @@ static const char *clks_syscall_usc_syscall_name(u64 id) {
|
||||
return "DISK_MOUNTED";
|
||||
case CLKS_SYSCALL_DISK_MOUNT_PATH:
|
||||
return "DISK_MOUNT_PATH";
|
||||
case CLKS_SYSCALL_DISK_READ_SECTOR:
|
||||
return "DISK_READ_SECTOR";
|
||||
case CLKS_SYSCALL_DISK_WRITE_SECTOR:
|
||||
return "DISK_WRITE_SECTOR";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -2094,6 +2133,8 @@ static clks_bool clks_syscall_usc_is_dangerous(u64 id) {
|
||||
return (CLKS_CFG_USC_SC_RESTART != 0) ? CLKS_TRUE : CLKS_FALSE;
|
||||
case CLKS_SYSCALL_DISK_FORMAT_FAT32:
|
||||
return CLKS_TRUE;
|
||||
case CLKS_SYSCALL_DISK_WRITE_SECTOR:
|
||||
return CLKS_TRUE;
|
||||
default:
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
@@ -2613,6 +2654,10 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
|
||||
return clks_syscall_disk_mounted();
|
||||
case CLKS_SYSCALL_DISK_MOUNT_PATH:
|
||||
return clks_syscall_disk_mount_path(frame->rbx, frame->rcx);
|
||||
case CLKS_SYSCALL_DISK_READ_SECTOR:
|
||||
return clks_syscall_disk_read_sector(frame->rbx, frame->rcx);
|
||||
case CLKS_SYSCALL_DISK_WRITE_SECTOR:
|
||||
return clks_syscall_disk_write_sector(frame->rbx, frame->rcx);
|
||||
default:
|
||||
return (u64)-1;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
- `/proc/<pid>`:指定 PID 快照文本
|
||||
- `/proc` 为只读;写入类 syscall 不支持。
|
||||
|
||||
## 4. Syscall 列表(0~92)
|
||||
## 4. Syscall 列表(0~94)
|
||||
|
||||
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
|
||||
|
||||
@@ -715,6 +715,22 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
- 返回:实际写入字节数(不含终止符),失败返回 `0`
|
||||
- 说明:查询当前挂载点路径;返回值为写入长度,且内核保证 `\0` 终止。
|
||||
|
||||
### 93 `CLEONOS_SYSCALL_DISK_READ_SECTOR`
|
||||
|
||||
- 参数:
|
||||
- `arg0`: `u64 lba`
|
||||
- `arg1`: `void *out_sector`(512 字节缓冲区)
|
||||
- 返回:成功 `1`,失败 `0`
|
||||
- 说明:按 LBA 读取单个扇区(512B)到用户缓冲区,常用于分区表/低级磁盘工具。
|
||||
|
||||
### 94 `CLEONOS_SYSCALL_DISK_WRITE_SECTOR`
|
||||
|
||||
- 参数:
|
||||
- `arg0`: `u64 lba`
|
||||
- `arg1`: `const void *sector_data`(512 字节缓冲区)
|
||||
- 返回:成功 `1`,失败 `0`
|
||||
- 说明:按 LBA 写入单个扇区(512B)。该 syscall 在 USC 策略中默认视为高风险操作。
|
||||
|
||||
## 5. 用户态封装函数
|
||||
|
||||
用户态封装位于:
|
||||
@@ -746,6 +762,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
- `cleonos_sys_kernel_version()`
|
||||
- `cleonos_sys_disk_present()` / `cleonos_sys_disk_size_bytes()` / `cleonos_sys_disk_sector_count()`
|
||||
- `cleonos_sys_disk_formatted()` / `cleonos_sys_disk_format_fat32()` / `cleonos_sys_disk_mount()` / `cleonos_sys_disk_mounted()` / `cleonos_sys_disk_mount_path()`
|
||||
- `cleonos_sys_disk_read_sector()` / `cleonos_sys_disk_write_sector()`
|
||||
|
||||
## 6. 开发注意事项
|
||||
|
||||
@@ -756,7 +773,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
|
||||
## 7. Wine 兼容说明
|
||||
|
||||
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..92`(含 `DL_*`、`FB_*`、`KERNEL_VERSION`、`DISK_*`)。
|
||||
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..94`(含 `DL_*`、`FB_*`、`KERNEL_VERSION`、`DISK_*`)。
|
||||
- `DL_*`(`77..79`)在 Wine 中为“可运行兼容”实现:
|
||||
- `DL_OPEN`:加载 guest ELF 到当前 Unicorn 地址空间,返回稳定 `handle`,并做引用计数。
|
||||
- `DL_SYM`:解析 ELF `SYMTAB/DYNSYM` 并返回 guest 可调用地址。
|
||||
@@ -768,10 +785,11 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
- 配合 Wine 参数 `--fb-window` 可将 framebuffer 实时显示到主机窗口(pygame 后端);未启用时保持内存缓冲模式。
|
||||
- `FB_CLEAR` 支持清屏颜色写入。
|
||||
- `KERNEL_VERSION`(`84`)在 Wine 中返回内核版本字符串(当前默认 `1.0.0-alpha`)。
|
||||
- `DISK_*`(`85..92`)在 Wine 中已实现:
|
||||
- `DISK_*`(`85..94`)在 Wine 中已实现:
|
||||
- 提供虚拟磁盘容量信息与 FAT32 格式化状态查询。
|
||||
- `DISK_FORMAT_FAT32` 会初始化/重置 Wine rootfs 下的虚拟磁盘目录。
|
||||
- `DISK_MOUNT`/`DISK_MOUNT_PATH` 支持挂载点管理,并与 `FS_MKDIR/WRITE/APPEND/REMOVE` 的路径规则联动。
|
||||
- `DISK_READ_SECTOR`/`DISK_WRITE_SECTOR`(`93..94`)在 Wine 中已实现为 512B 原始扇区读写(host 文件后端)。
|
||||
- Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。
|
||||
- Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0`,`AUDIO_PLAY_TONE=0`,`AUDIO_STOP=1`。
|
||||
- Wine 版本号策略固定为 `85.0.0-wine`(历史兼容号;不会随 syscall 扩展继续增长)。
|
||||
|
||||
@@ -38,7 +38,7 @@ 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..92(含 `FD_*`、`DL_*`、`FB_*`、`PROC_*`、`STATS_*`、`EXEC_PATHV_IO`、`KERNEL_VERSION`、`DISK_*`)
|
||||
- CLeonOS `int 0x80` syscall 0..94(含 `FD_*`、`DL_*`、`FB_*`、`PROC_*`、`STATS_*`、`EXEC_PATHV_IO`、`KERNEL_VERSION`、`DISK_*`)
|
||||
- TTY 输出与键盘输入队列
|
||||
- rootfs 文件/目录访问(`FS_*`)
|
||||
- `/temp` 与已挂载磁盘路径写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`)
|
||||
@@ -52,14 +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`)
|
||||
- 磁盘接口兼容(`DISK_PRESENT/SIZE_BYTES/SECTOR_COUNT/FORMATTED/FORMAT_FAT32/MOUNT/MOUNTED/MOUNT_PATH/READ_SECTOR/WRITE_SECTOR`)
|
||||
- Wine 虚拟磁盘目录默认位于 `<rootfs>/__clks_disk0__`(格式化标记文件 `.fat32`,原始扇区后端文件 `.rawdisk.img`)
|
||||
- 异常退出状态编码与故障元信息(`PROC_LAST_SIGNAL/PROC_FAULT_*`)
|
||||
|
||||
## 版本策略
|
||||
|
||||
- CLeonOS-Wine 版本号固定为:`85.0.0-wine`
|
||||
- 该值按项目策略固定,不再随新增 syscall 变更(即使当前实现范围已扩展到 `0..92`)
|
||||
- 该值按项目策略固定,不再随新增 syscall 变更(即使当前实现范围已扩展到 `0..94`)
|
||||
|
||||
## 参数
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ SYS_DISK_FORMAT_FAT32 = 89
|
||||
SYS_DISK_MOUNT = 90
|
||||
SYS_DISK_MOUNTED = 91
|
||||
SYS_DISK_MOUNT_PATH = 92
|
||||
SYS_DISK_READ_SECTOR = 93
|
||||
SYS_DISK_WRITE_SECTOR = 94
|
||||
|
||||
# proc states (from cleonos/c/include/cleonos_syscall.h)
|
||||
PROC_STATE_UNUSED = 0
|
||||
|
||||
@@ -69,8 +69,10 @@ from .constants import (
|
||||
SYS_DISK_MOUNTED,
|
||||
SYS_DISK_MOUNT_PATH,
|
||||
SYS_DISK_PRESENT,
|
||||
SYS_DISK_READ_SECTOR,
|
||||
SYS_DISK_SECTOR_COUNT,
|
||||
SYS_DISK_SIZE_BYTES,
|
||||
SYS_DISK_WRITE_SECTOR,
|
||||
SYS_GETPID,
|
||||
SYS_KERNEL_VERSION,
|
||||
SYS_KBD_BUFFERED,
|
||||
@@ -286,10 +288,12 @@ class CLeonOSWineNative:
|
||||
self._disk_mount_path = "/temp/disk"
|
||||
self._disk_root = (self.rootfs / "__clks_disk0__").resolve()
|
||||
self._disk_marker = self._disk_root / ".fat32"
|
||||
self._disk_image_file = self._disk_root / ".rawdisk.img"
|
||||
self._disk_formatted = False
|
||||
self._disk_mounted = False
|
||||
try:
|
||||
self._disk_root.mkdir(parents=True, exist_ok=True)
|
||||
self._disk_prepare_raw_image()
|
||||
if self._disk_marker.exists():
|
||||
self._disk_formatted = True
|
||||
self._disk_mounted = True
|
||||
@@ -762,6 +766,16 @@ class CLeonOSWineNative:
|
||||
return 1 if self._disk_mounted else 0
|
||||
if sid == SYS_DISK_MOUNT_PATH:
|
||||
return self._disk_mount_path_query(uc, arg0, arg1)
|
||||
if sid == SYS_DISK_READ_SECTOR:
|
||||
sector_data = self._disk_read_sector_raw(int(arg0))
|
||||
if sector_data is None:
|
||||
return 0
|
||||
return 1 if self._write_guest_bytes(uc, int(arg1), sector_data) else 0
|
||||
if sid == SYS_DISK_WRITE_SECTOR:
|
||||
sector_data = self._read_guest_bytes_exact(uc, int(arg1), 512)
|
||||
if sector_data is None:
|
||||
return 0
|
||||
return 1 if self._disk_write_sector_raw(int(arg0), sector_data) else 0
|
||||
|
||||
return u64_neg1()
|
||||
|
||||
@@ -1080,20 +1094,78 @@ class CLeonOSWineNative:
|
||||
return None
|
||||
return host
|
||||
|
||||
def _disk_prepare_raw_image(self) -> None:
|
||||
target_size = int(self._disk_size_bytes)
|
||||
|
||||
if target_size < 512:
|
||||
raise RuntimeError("wine disk image size too small")
|
||||
|
||||
if not self._disk_image_file.exists():
|
||||
with open(self._disk_image_file, "wb") as fp:
|
||||
fp.truncate(target_size)
|
||||
return
|
||||
|
||||
current_size = int(self._disk_image_file.stat().st_size)
|
||||
if current_size != target_size:
|
||||
with open(self._disk_image_file, "r+b") as fp:
|
||||
fp.truncate(target_size)
|
||||
|
||||
def _disk_read_sector_raw(self, lba: int) -> Optional[bytes]:
|
||||
if not self._disk_present:
|
||||
return None
|
||||
if lba < 0:
|
||||
return None
|
||||
offset = int(lba) * 512
|
||||
if offset + 512 > int(self._disk_size_bytes):
|
||||
return None
|
||||
try:
|
||||
with open(self._disk_image_file, "rb") as fp:
|
||||
fp.seek(offset)
|
||||
data = fp.read(512)
|
||||
if len(data) != 512:
|
||||
return None
|
||||
return data
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _disk_write_sector_raw(self, lba: int, data: bytes) -> bool:
|
||||
if not self._disk_present:
|
||||
return False
|
||||
if lba < 0:
|
||||
return False
|
||||
if len(data) != 512:
|
||||
return False
|
||||
offset = int(lba) * 512
|
||||
if offset + 512 > int(self._disk_size_bytes):
|
||||
return False
|
||||
try:
|
||||
with open(self._disk_image_file, "r+b") as fp:
|
||||
fp.seek(offset)
|
||||
fp.write(data)
|
||||
fp.flush()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _disk_format_fat32(self, label: str) -> int:
|
||||
_ = label
|
||||
if not self._disk_present:
|
||||
return 0
|
||||
|
||||
try:
|
||||
self._disk_prepare_raw_image()
|
||||
self._disk_root.mkdir(parents=True, exist_ok=True)
|
||||
for child in list(self._disk_root.iterdir()):
|
||||
if child.name == self._disk_marker.name:
|
||||
if child.name == self._disk_marker.name or child.name == self._disk_image_file.name:
|
||||
continue
|
||||
if child.is_dir():
|
||||
shutil.rmtree(child)
|
||||
else:
|
||||
child.unlink()
|
||||
with open(self._disk_image_file, "r+b") as fp:
|
||||
fp.seek(0)
|
||||
fp.write(b"\x00" * 512)
|
||||
fp.flush()
|
||||
self._disk_marker.write_text("FAT32\n", encoding="utf-8")
|
||||
self._disk_formatted = True
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user