diff --git a/src/libraries/j6/include/j6/init.h b/src/libraries/j6/include/j6/init.h index 93bce28..9beeec1 100644 --- a/src/libraries/j6/include/j6/init.h +++ b/src/libraries/j6/include/j6/init.h @@ -12,39 +12,42 @@ extern "C" { #endif -#ifdef __cplusplus -#define add_header(name) \ - static constexpr j6_arg_type type_id = j6_arg_type_ ## name; \ - j6_arg_header header; -#else -#define add_header(name) \ - j6_arg_header header; -#endif +enum j6_aux_type { + // The SysV ABI-specified aux vector types + j6_aux_null, // AT_NULL + j6_aux_ignore, // AT_IGNORE + j6_aux_execfd, // AD_EXECFD - File descriptor of the exe to load + j6_aux_phdr, // AD_PHDR - Program headers pointer for the exe to load + j6_aux_phent, // AD_PHENT - Size of a program header entry + j6_aux_phnum, // AD_PHNUM - Number of program header entries + j6_aux_pagesz, // AD_PAGESZ - System page size + j6_aux_base, // AD_BASE - Base address of dynamic loader + j6_aux_flags, // AD_FLAGS - Flags + j6_aux_entry, // AD_ENTRY - Entrypoint for the exe to load + j6_aux_notelf, // AD_NOTELF - If non-zero, this program is not ELF + j6_aux_uid, // AD_UID - User ID + j6_aux_euid, // AD_EUID - Effective User ID + j6_aux_gid, // AD_GID - Group ID + j6_aux_egid, // AD_EGID - Effective Group ID -enum j6_arg_type { - j6_arg_type_none, - j6_arg_type_sysv_init, - j6_arg_type_loader, - j6_arg_type_driver, - j6_arg_type_handles, + j6_aux_start = 0xf000, + j6_aux_handles, // Pointer to a j6_arg_handles structure + j6_aux_device, // Pointer to a j6_arg_driver structure + j6_aux_loader, // Pointer to a j6_arg_loader structure }; -struct j6_arg_header +struct j6_aux { - uint32_t size; - uint16_t type; - uint16_t reserved; - j6_arg_header *next; -}; - -struct j6_arg_none -{ - add_header(none); + uint64_t type; + union { + uint64_t value; + void *pointer; + void (*func)(); + }; }; struct j6_arg_loader { - add_header(loader); uintptr_t loader_base; uintptr_t image_base; uintptr_t *got; @@ -54,8 +57,8 @@ struct j6_arg_loader struct j6_arg_driver { - add_header(driver); uint64_t device; + uint32_t size; uint8_t data [0]; }; @@ -67,32 +70,13 @@ struct j6_arg_handle_entry struct j6_arg_handles { - add_header(handles); size_t nhandles; j6_arg_handle_entry handles[0]; }; -struct j6_init_args -{ - uint64_t argv[2]; - j6_arg_header *args; -}; - - -/// Find the first handle of the given type held by this process -j6_handle_t API j6_find_first_handle(j6_object_type obj_type); - /// Find the first handle tagged with the given proto in the process init args j6_handle_t API j6_find_init_handle(uint64_t proto); -/// Get the init args -const j6_init_args * j6_get_init_args(); - -/// Drivers may use driver_main instead of main -int driver_main(unsigned, const char **, const char **, const j6_init_args *); - #ifdef __cplusplus } // extern "C" #endif - -#undef add_header diff --git a/src/libraries/j6/init.cpp b/src/libraries/j6/init.cpp index e28aaf7..a4264ad 100644 --- a/src/libraries/j6/init.cpp +++ b/src/libraries/j6/init.cpp @@ -1,5 +1,7 @@ // The kernel depends on libj6 for some shared code, // but should not include the user-specific code. +#include "j6/init.h" +#include "j6/types.h" #ifndef __j6kernel #include @@ -10,65 +12,45 @@ #include namespace { - constexpr size_t static_arr_count = 32; - j6_handle_descriptor handle_array[static_arr_count]; - j6_init_args init_args = { 0, 0, 0 }; -} // namespace + char const * const *envp = nullptr; + const j6_aux *aux = nullptr; -j6_handle_t -j6_find_first_handle(j6_object_type obj_type) -{ - size_t count = static_arr_count; - j6_handle_descriptor *handles = handle_array; - j6_status_t s = j6_handle_list(handles, &count); - - if (s != j6_err_insufficient && s != j6_status_ok) - return j6_handle_invalid; - - if (count > static_arr_count) - count = static_arr_count; - - for (size_t i = 0; i < count; ++i) { - j6_handle_descriptor &desc = handle_array[i]; - if (desc.type == obj_type) return desc.handle; + const j6_aux * find_aux(uint64_t type) { + if (!aux) return nullptr; + for (j6_aux const *p = aux; p->type; ++p) + if (p->type == type) return p; + return nullptr; } - - return j6_handle_invalid; -} +} // namespace j6_handle_t j6_find_init_handle(uint64_t proto) { - j6_arg_header *arg = init_args.args; - while (arg) { - if (arg->type == j6_arg_type_handles) { - j6_arg_handles *harg = reinterpret_cast(arg); - for (unsigned i = 0; i < harg->nhandles; ++i) { - j6_arg_handle_entry &ent = harg->handles[i]; - if (ent.proto == proto) - return ent.handle; - } - } - arg = arg->next; + const j6_aux *aux_handles = find_aux(j6_aux_handles); + if (!aux_handles) + return j6_handle_invalid; + + const j6_arg_handles *arg = reinterpret_cast(aux_handles->pointer); + for (unsigned i = 0; i < arg->nhandles; ++i) { + const j6_arg_handle_entry &ent = arg->handles[i]; + if (ent.proto == proto) + return ent.handle; } return j6_handle_invalid; } - -const j6_init_args * API -j6_get_init_args() -{ - return &init_args; -} - extern "C" void API -__init_libj6(uint64_t argv0, uint64_t argv1, j6_arg_header *args) +__init_libj6(const uint64_t *stack) { - init_args.argv[0] = argv0; - init_args.argv[1] = argv1; - init_args.args = args; -} + // Walk the stack to get the aux vector + uint64_t argc = *stack++; + stack += argc + 1; // Skip argv's and sentinel + envp = reinterpret_cast(stack); + while (*stack++); // Skip envp's and sentinel + + aux = reinterpret_cast(stack); +} #endif // __j6kernel diff --git a/src/libraries/j6/init.s b/src/libraries/j6/init.s deleted file mode 100644 index 6945ffb..0000000 --- a/src/libraries/j6/init.s +++ /dev/null @@ -1,6 +0,0 @@ -extern driver_main -global main:function weak (main.end - main) -main: - jmp driver_main -main.end: - diff --git a/src/libraries/libc/arch/amd64/crt/crt0.s b/src/libraries/libc/arch/amd64/crt/crt0.s index 4004d4c..85a781f 100644 --- a/src/libraries/libc/arch/amd64/crt/crt0.s +++ b/src/libraries/libc/arch/amd64/crt/crt0.s @@ -71,12 +71,13 @@ global _libc_crt0_start:function (_libc_crt0_start.end - _libc_crt0_start) _start: _libc_crt0_start: - mov rdx, [rsp] ; grab args pointer + mov r15, rsp ; grab initial stack pointer push 0 ; Add null frame push 0 mov rbp, rsp + mov rdi, r15 lookup_GOT __init_libj6 call rax mov rbx, rax @@ -86,8 +87,9 @@ _libc_crt0_start: call __run_global_ctors - mov rdi, 0 - mov rsi, rsp + mov rdi, [r15] + mov rsi, r15 + add rsi, 8 mov rdx, 0 ; TODO: actually parse stack for argc, argv, envp mov rcx, rbx lookup_GOT main diff --git a/src/user/ld.so/main.cpp b/src/user/ld.so/main.cpp index 7e1909d..753db5a 100644 --- a/src/user/ld.so/main.cpp +++ b/src/user/ld.so/main.cpp @@ -12,28 +12,37 @@ image_list all_images; extern "C" uintptr_t -ldso_init(j6_arg_header *stack_args, uintptr_t *got) +ldso_init(const uint64_t *stack, uintptr_t *got) { - j6_arg_loader *arg_loader = nullptr; - j6_arg_handles *arg_handles = nullptr; + j6_arg_loader const *arg_loader = nullptr; + j6_arg_handles const *arg_handles = nullptr; - j6_arg_header *arg = stack_args; - while (arg) { - switch (arg->type) + // Walk the stack to get the aux vector + uint64_t argc = *stack++; + stack += argc + 1; // Skip argv's and sentinel + while (*stack++); // Skip envp's and sentinel + + j6_aux const *aux = reinterpret_cast(stack); + bool more = true; + while (aux && more) { + switch (aux->type) { - case j6_arg_type_loader: - arg_loader = reinterpret_cast(arg); + case j6_aux_null: + more = false; break; - case j6_arg_type_handles: - arg_handles = reinterpret_cast(arg); + case j6_aux_loader: + arg_loader = reinterpret_cast(aux->pointer); break; - + + case j6_aux_handles: + arg_handles = reinterpret_cast(aux->pointer); + break; + default: break; } - - arg = arg->next; + ++aux; } if (!arg_loader) { @@ -43,7 +52,7 @@ ldso_init(j6_arg_header *stack_args, uintptr_t *got) j6_handle_t vfs = j6_handle_invalid; if (arg_handles) { for (size_t i = 0; i < arg_handles->nhandles; ++i) { - j6_arg_handle_entry &ent = arg_handles->handles[i]; + const j6_arg_handle_entry &ent = arg_handles->handles[i]; if (ent.proto == j6::proto::vfs::id) { vfs = ent.handle; break; @@ -51,7 +60,6 @@ ldso_init(j6_arg_header *stack_args, uintptr_t *got) } } - // First relocate ld.so itself. It cannot have any dependencies image_list::item_type ldso_image; ldso_image.base = arg_loader->loader_base; diff --git a/src/user/ld.so/start.s b/src/user/ld.so/start.s index f0a248c..2a222a4 100644 --- a/src/user/ld.so/start.s +++ b/src/user/ld.so/start.s @@ -17,7 +17,7 @@ _ldso_start: ; Call ldso_init with the loader-provided stack data and ; also the address of the GOT, since clang refuses to take ; the address of it, only dereference it. - mov rdi, [rbp] + mov rdi, rbp lea rsi, [rel _GLOBAL_OFFSET_TABLE_] call ldso_init @@ -32,17 +32,6 @@ _ldso_start: pop rsi pop rdi - ; Pop all the loader args - pop rsp ; Point the stack at the first arg - mov rax, 0 - mov rbx, 0 -.poploop: - mov eax, [dword rsp] ; size - mov ebx, [dword rsp+4] ; type - add rsp, rax - cmp ebx, 0 - jne .poploop - mov rbp, rsp jmp r11 .end: diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index bdccfe6..de857e4 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "j6/types.h" @@ -26,10 +27,10 @@ static util::xoroshiro256pp rng {0x123456}; inline uintptr_t align_up(uintptr_t a) { return ((a-1) & ~(MiB-1)) + MiB; } -class stack_pusher +class stack_builder { public: - stack_pusher(uint8_t *local_top, uintptr_t child_top) : + stack_builder(uint8_t *local_top, uintptr_t child_top) : m_local_top {local_top}, m_child_top {child_top}, m_used {0}, m_last_arg {0} { memset(local_top - 4096, 0, 4096); // Zero top page } @@ -41,20 +42,51 @@ public: return reinterpret_cast(local_pointer()); } + void add_arg(const char *arg) { + size_t len = strlen(arg); + char * argp = push(len); + strncpy(argp, arg, len + 1); // Copy the 0 + m_argv.append(child_pointer()); + } + + void add_env(const char *key, const char *value) { + size_t klen = strlen(key); + size_t vlen = strlen(value); + char * envp = push(klen + vlen + 1); // add = + strncpy(envp, key, klen); + envp[klen] = '='; + strncpy(envp+klen+1, value, vlen + 1); // Copy the 0 + m_envp.append(child_pointer()); + } + + void add_aux(j6_aux_type type, uint64_t value) { + m_aux.append({type, value}); + } + template - T * push_arg(size_t extra = 0) { + T * add_aux_data(j6_aux_type type, size_t extra = 0) { T * arg = push(extra); - arg->header.size = sizeof(T) + extra; - arg->header.type = T::type_id; - arg->header.next = reinterpret_cast(m_last_arg); - m_last_arg = child_pointer(); + add_aux(type, child_pointer()); return arg; } - void push_current_pointer() { - uintptr_t addr = child_pointer(); - uintptr_t *ptr = push(); - *ptr = addr; + void build() { + if ((m_argv.count() + m_envp.count()) % 2 == 0) + *push() = 0; // Pad for 16-byte alignment + + *push() = {0, 0}; + for(j6_aux &aux : m_aux) + *push() = aux; + + *push() = 0; + for (uintptr_t addr : m_envp) + *push() = addr; + + *push() = 0; + for (uintptr_t addr : m_argv) + *push() = addr; + + *push() = m_argv.count(); } uint8_t * local_pointer() { return m_local_top - m_used; } @@ -65,6 +97,10 @@ private: uintptr_t m_child_top; size_t m_used; uintptr_t m_last_arg; + + util::vector m_argv; + util::vector m_envp; + util::vector m_aux; }; j6_handle_t @@ -227,15 +263,14 @@ load_program( return false; } - stack_pusher stack { + stack_builder stack { reinterpret_cast(stack_addr + stack_size), stack_top, }; - // Push program's arg sentinel - stack.push_arg(); - - j6_arg_handles *handles_arg = stack.push_arg(3 * sizeof(j6_arg_handle_entry)); + static constexpr size_t nhandles = 3; + static constexpr size_t handles_extra = 3 * sizeof(j6_arg_handle_entry); + j6_arg_handles *handles_arg = stack.add_aux_data(j6_aux_handles, handles_extra); handles_arg->nhandles = 3; handles_arg->handles[0].handle = sys; handles_arg->handles[0].proto = 0; @@ -246,23 +281,17 @@ load_program( if (arg) { size_t data_size = arg->bytes - sizeof(*arg); - j6_arg_driver *driver_arg = stack.push_arg(data_size); + j6_arg_driver *driver_arg = stack.add_aux_data(j6_aux_device, data_size); driver_arg->device = arg->type_id; const uint8_t *arg_data = arg->data(); memcpy(driver_arg->data, arg_data, data_size); } - // Add an aligned pointer to the program's args list - stack.push_current_pointer(); - uintptr_t entrypoint = program_elf.entrypoint() + program_image_base; if (dyn) { - // Push loaders's arg sentinel - stack.push_arg(); - - j6_arg_loader *loader_arg = stack.push_arg(); + j6_arg_loader *loader_arg = stack.add_aux_data(j6_aux_loader); loader_arg->image_base = program_image_base; loader_arg->entrypoint = program_elf.entrypoint(); // ld.so will offset the entrypoint, don't do it here. @@ -270,9 +299,6 @@ load_program( if (got_section) loader_arg->got = reinterpret_cast(program_image_base + got_section->addr); - // Add an aligned pointer to the loaders's args list - stack.push_current_pointer(); - uintptr_t ldso_image_base = (eop & ~(MiB-1)) + MiB; for (auto seg : program_elf.segments()) { @@ -300,6 +326,8 @@ load_program( } } + stack.build(); + uintptr_t stack_base = stack_top-stack_size; res = j6_vma_map(stack_vma, proc, &stack_base, j6_vm_flag_exact); if (res != j6_status_ok) { diff --git a/src/user/srv.init/main.cpp b/src/user/srv.init/main.cpp index 4224adf..83bb5bb 100644 --- a/src/user/srv.init/main.cpp +++ b/src/user/srv.init/main.cpp @@ -31,6 +31,9 @@ main(int argc, const char **argv, const char **env) { j6_status_t s; + // argv[0] is not a char* for init, but the modules pointer + uintptr_t modules_addr = reinterpret_cast(argv[0]); + j6_handle_t slp_mb = j6_handle_invalid; j6_handle_t slp_mb_child = j6_handle_invalid; @@ -42,7 +45,22 @@ main(int argc, const char **argv, const char **env) j6::syslog(j6::logs::srv, j6::log_level::info, "srv.init starting"); - sys = j6_find_first_handle(j6_object_type_system); + // Since we had no parent to set up a j6_arg_handles object, + // ask the kernel for our handles and look in that list for + // the system handle. + static constexpr size_t num_init_handles = 16; + j6_handle_descriptor handles[num_init_handles]; + size_t num_handles = num_init_handles; + s = j6_handle_list(handles, &num_handles); + if (s != j6_status_ok) + return s; + + for (unsigned i = 0; i < num_handles; ++i) { + if (handles[i].type == j6_object_type_system) { + sys = handles[i].handle; + break; + } + } if (sys == j6_handle_invalid) return 1; @@ -74,9 +92,6 @@ main(int argc, const char **argv, const char **env) if (s != j6_status_ok) return s; - const j6_init_args *initp = j6_get_init_args(); - uintptr_t modules_addr = initp->argv[0]; - std::vector mods; load_modules(modules_addr, sys, 0, mods); diff --git a/src/user/srv.init/start.s b/src/user/srv.init/start.s index d9f20fe..baaca9a 100644 --- a/src/user/srv.init/start.s +++ b/src/user/srv.init/start.s @@ -19,11 +19,17 @@ _start: ; stack in BSS and assign that to be init's first stack mov rsp, init_stack_top - ; Push a fake j6_arg_none - push 0x00 ; pad for 16-byte alignment - push 0x00 ; no next arg - push 0x10 ; size 16 bytes, type 0 (none) - push rsp + ; Push fake initial stack + push 0x00 ; stack sentinel (16 bytes) + push 0x00 ; + push 0x00 ; alignment padding + push 0x00 ; auxv sentinel (16 bytes) + push 0x00 ; + push 0x00 ; envp sentinel (8 bytes) + push 0x00 ; argv sentinel (8 bytes) + push rsi ; argv[1] -- for init, not actually a char* + push rdi ; argv[0] -- for init, not actually a char* + push 0x02 ; argc jmp _libc_crt0_start .end: