mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
[libj6] Change to a more SysV style process init args
Pull out the old linked list of args structures in favor of doing things the SysV ABI-specified way.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 <stddef.h>
|
||||
@@ -10,65 +12,45 @@
|
||||
#include <j6/types.h>
|
||||
|
||||
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<j6_arg_handles*>(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<const j6_arg_handles*>(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<char const * const *>(stack);
|
||||
while (*stack++); // Skip envp's and sentinel
|
||||
|
||||
aux = reinterpret_cast<const j6_aux*>(stack);
|
||||
}
|
||||
|
||||
#endif // __j6kernel
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
extern driver_main
|
||||
global main:function weak (main.end - main)
|
||||
main:
|
||||
jmp driver_main
|
||||
main.end:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<const j6_aux*>(stack);
|
||||
bool more = true;
|
||||
while (aux && more) {
|
||||
switch (aux->type)
|
||||
{
|
||||
case j6_arg_type_loader:
|
||||
arg_loader = reinterpret_cast<j6_arg_loader*>(arg);
|
||||
case j6_aux_null:
|
||||
more = false;
|
||||
break;
|
||||
|
||||
case j6_arg_type_handles:
|
||||
arg_handles = reinterpret_cast<j6_arg_handles*>(arg);
|
||||
case j6_aux_loader:
|
||||
arg_loader = reinterpret_cast<const j6_arg_loader*>(aux->pointer);
|
||||
break;
|
||||
|
||||
|
||||
case j6_aux_handles:
|
||||
arg_handles = reinterpret_cast<const j6_arg_handles*>(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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <j6/protocols.h>
|
||||
#include <j6/syscalls.h>
|
||||
#include <j6/syslog.hh>
|
||||
#include <util/vector.h>
|
||||
#include <util/xoroshiro.h>
|
||||
|
||||
#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<T*>(local_pointer());
|
||||
}
|
||||
|
||||
void add_arg(const char *arg) {
|
||||
size_t len = strlen(arg);
|
||||
char * argp = push<char>(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<char>(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 <typename T>
|
||||
T * push_arg(size_t extra = 0) {
|
||||
T * add_aux_data(j6_aux_type type, size_t extra = 0) {
|
||||
T * arg = push<T>(extra);
|
||||
arg->header.size = sizeof(T) + extra;
|
||||
arg->header.type = T::type_id;
|
||||
arg->header.next = reinterpret_cast<j6_arg_header*>(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<uintptr_t, 16>();
|
||||
*ptr = addr;
|
||||
void build() {
|
||||
if ((m_argv.count() + m_envp.count()) % 2 == 0)
|
||||
*push<uint64_t>() = 0; // Pad for 16-byte alignment
|
||||
|
||||
*push<j6_aux>() = {0, 0};
|
||||
for(j6_aux &aux : m_aux)
|
||||
*push<j6_aux>() = aux;
|
||||
|
||||
*push<uint64_t>() = 0;
|
||||
for (uintptr_t addr : m_envp)
|
||||
*push<uintptr_t>() = addr;
|
||||
|
||||
*push<uint64_t>() = 0;
|
||||
for (uintptr_t addr : m_argv)
|
||||
*push<uintptr_t>() = addr;
|
||||
|
||||
*push<size_t>() = 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<uintptr_t> m_argv;
|
||||
util::vector<uintptr_t> m_envp;
|
||||
util::vector<j6_aux> m_aux;
|
||||
};
|
||||
|
||||
j6_handle_t
|
||||
@@ -227,15 +263,14 @@ load_program(
|
||||
return false;
|
||||
}
|
||||
|
||||
stack_pusher stack {
|
||||
stack_builder stack {
|
||||
reinterpret_cast<uint8_t*>(stack_addr + stack_size),
|
||||
stack_top,
|
||||
};
|
||||
|
||||
// Push program's arg sentinel
|
||||
stack.push_arg<j6_arg_none>();
|
||||
|
||||
j6_arg_handles *handles_arg = stack.push_arg<j6_arg_handles>(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_arg_handles>(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<j6_arg_driver>(data_size);
|
||||
j6_arg_driver *driver_arg = stack.add_aux_data<j6_arg_driver>(j6_aux_device, data_size);
|
||||
driver_arg->device = arg->type_id;
|
||||
|
||||
const uint8_t *arg_data = arg->data<uint8_t>();
|
||||
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_none>();
|
||||
|
||||
j6_arg_loader *loader_arg = stack.push_arg<j6_arg_loader>();
|
||||
j6_arg_loader *loader_arg = stack.add_aux_data<j6_arg_loader>(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<uintptr_t*>(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) {
|
||||
|
||||
@@ -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<uintptr_t>(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<const module*> mods;
|
||||
load_modules(modules_addr, sys, 0, mods);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user