#define MSG_IMPLEMENTATION #define MSG_NO_MALLOC #include "tar.h" #include #include #include #include #include #include #include #include #include #include #include #include #define INIT_PATH "/usr/bin/test" static enum launch_status resolve_dependency( struct launch_ctx *ctx, const char *name, kern_handle_t *out, void *arg) { char s[128]; while (*name == '/') { name++; } snprintf(s, sizeof s, "searching for library %s", name); kern_log(s); struct tar *fs = arg; struct tar_file file = {0}; if (tar_open(fs, name, &file) != 0) { snprintf(s, sizeof s, "cannot find library %s", name); kern_log(s); return LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY; } kern_handle_t image = KERN_HANDLE_INVALID; int err = tar_file_create_vm_object(&file, &image); if (err != 0) { snprintf(s, sizeof s, "cannot load library %s", name); kern_log(s); return -1; } *out = image; return LAUNCH_OK; } static kern_status_t open( xpc_context_t *ctx, const xpc_endpoint_t *sender, const char *path, int flags, int *out_err, void *arg) { kern_logf( "received msg: [%u.%x] open(%s, %d)", sender->e_task, sender->e_port, path, flags); *out_err = 13; return KERN_OK; } static void *_fs_alloc(struct fs_allocator *alloc, size_t count) { return heap_alloc(alloc->fs_arg, count); } static void *_fs_calloc(struct fs_allocator *alloc, size_t count, size_t sz) { return heap_calloc(alloc->fs_arg, count, sz); } static void *_fs_realloc(struct fs_allocator *alloc, void *p, size_t count) { return heap_realloc(alloc->fs_arg, p, count); } static void _fs_free(struct fs_allocator *alloc, void *p) { heap_free(alloc->fs_arg, p); } int main( int argc, const char **argv, kern_handle_t task, kern_handle_t address_space, uintptr_t bsp_base) { struct tar bsp = {0}; if (tar_init(&bsp, bsp_base) != 0) { kern_log("cannot access bsp"); return -1; } struct tar_file init = {0}; if (tar_open(&bsp, INIT_PATH, &init) != 0) { kern_log("cannot find init program " INIT_PATH); return -1; } kern_trace("loading " INIT_PATH); kern_handle_t image = KERN_HANDLE_INVALID; int err = tar_file_create_vm_object(&init, &image); if (err != 0) { kern_log("cannot load executable " INIT_PATH); return -1; } kern_trace("loaded executable vm-object " INIT_PATH); kern_tracef("task=%x, region=%x", task, address_space); struct launch_ctx launch; struct launch_result result; const char *init_argv[] = { "init", "arg1", "arg2", "arg3", }; const char *init_env[] = { "TESTVAR=testvalue", }; struct rosetta_bootstrap_channel init_channels[] = { { .c_type = RSBS_CHANNEL_SYSTEM, .c_tid = 0, .c_cid = 0, }, }; struct launch_parameters params = { .p_executable = image, .p_parent_task = task, .p_task_name = "init", .p_local_address_space = address_space, .p_resolver_arg = &bsp, .p_argc = sizeof init_argv / sizeof init_argv[0], .p_argv = init_argv, .p_envc = sizeof init_env / sizeof init_env[0], .p_envp = init_env, .p_channel_count = sizeof init_channels / sizeof init_channels[0], .p_channels = init_channels, }; kern_handle_t channel; channel_create(0, &channel); launch_ctx_init(&launch); launch.ctx_resolve_library = resolve_dependency; enum launch_status status = launch_ctx_execute(&launch, ¶ms, LAUNCH_F_NONE, &result); if (status != KERN_OK) { kern_logf("failed to start init: %d", status); return -1; } heap_t heap = HEAP_INIT; struct fs_allocator fs_allocator = { .fs_alloc = _fs_alloc, .fs_calloc = _fs_calloc, .fs_realloc = _fs_realloc, .fs_free = _fs_free, .fs_arg = &heap, }; struct fs_context *fs = fs_context_create(&fs_allocator); if (!fs) { kern_logf("cannot initialise fs"); return -1; } enum fs_status fs_status = fs_context_mount_filesystem( fs, tar_mount, (void *)bsp_base, 0); if (fs_status != FS_SUCCESS) { kern_logf("cannot mount filesustem (%d)", fs_status); return -1; } while (1) { xpc_msg_t msg; kern_status_t status = xpc_msg_recv(channel, &msg); if (status != KERN_OK) { kern_logf("message recv error %d", status); continue; } switch (msg.msg_header.hdr_interface) { case INTERFACE_FS: status = fs_context_dispatch_msg(fs, &msg); break; default: kern_logf( "unknown message protocol %u", msg.msg_header.hdr_interface); xpc_msg_reply_error(&msg, KERN_UNSUPPORTED); break; } if (status != KERN_OK) { kern_logf("message reply error %d", status); continue; } } return 0; }