Compare commits

...

66 Commits

Author SHA1 Message Date
b975256cb9 meta: update kernel 2026-03-24 20:26:19 +00:00
8d22ec661c bootstrap: remove old request handler code 2026-03-24 20:26:12 +00:00
a91dc5965e services: herdd: getdents test 2026-03-24 20:25:49 +00:00
329829c0e9 lib: fs: implement file cleanup using disconnect and detach events 2026-03-24 20:25:13 +00:00
dade9fa81f lib: xpc: add support for event messages 2026-03-24 20:24:36 +00:00
e9ccefd980 toolchain: xpcg: fix buffer length output not being set 2026-03-24 12:45:13 +00:00
20723d4dff bootstrap: tar: implement readdir() 2026-03-24 12:44:33 +00:00
d2df4259e6 interface: fs: add fs.getdents function 2026-03-24 12:43:33 +00:00
e30368553f lib: c: io: implement getdents() 2026-03-24 12:42:39 +00:00
660cb3bd71 lib: c: io: update fs_read usage 2026-03-24 12:42:08 +00:00
d3a25f0af7 lib: c: remove errno log messages 2026-03-24 12:41:41 +00:00
30614e679b lib: xpc: implement support for iterating through directories 2026-03-24 12:41:12 +00:00
1eb6853cb0 lib: xpc: implement scatter/gather i/o for buffers and messages 2026-03-24 12:40:16 +00:00
af3dd454b0 bootstrap: start herdd instead of systemd 2026-03-23 18:16:15 +00:00
2a587942ac meta: add herdd runlevel configuration files 2026-03-23 18:15:55 +00:00
bf5052fd3d meta: replace systemd and ldd with herdd and nsd 2026-03-23 18:15:38 +00:00
d4d3ab13f4 prog: remove test program 2026-03-23 18:14:57 +00:00
98dbaa05ac cmake: add support for building services with config files 2026-03-23 18:13:22 +00:00
1e3e38b0e2 meta: update kernel 2026-03-22 19:11:55 +00:00
c1e10e8b70 lib: c: implement runtime initialisation 2026-03-22 19:11:43 +00:00
7b89a038a2 lib: c: add fallback errno storage for single-threaded programs 2026-03-22 19:11:25 +00:00
a792bbe5db lib: c: pthread: implement per-thread errno storage 2026-03-22 19:09:18 +00:00
dd46a378b3 lib: c: pthread: implement pthread_self 2026-03-22 19:08:42 +00:00
33888e364b lib: rosetta: change integer bootstrap args to fixed-width types 2026-03-22 19:07:39 +00:00
a535c588f1 lib: launch: add terminating null ptr to environ array 2026-03-22 19:07:07 +00:00
9f4c4cbc9d lib: fs: fix incorrect status code in fs_msg_open 2026-03-22 19:06:40 +00:00
3e0fdb616c ld: resolve: search all images for symbols, rather than just direct links 2026-03-22 19:05:47 +00:00
44cd6c551a ld: resolve: remove redundant stack pointer save/restore 2026-03-22 19:05:25 +00:00
60e1ca951c ld: resolve: fix incorrect symbol and GOT index calculation 2026-03-22 19:04:58 +00:00
119a86b8e6 cmake: update for compatibility with CMake 4.0 2026-03-22 13:11:10 +00:00
ac8f669e6b meta: update kernel 2026-03-21 10:56:58 +00:00
7d6af0344c bootstrap: cleanup test code 2026-03-21 10:56:47 +00:00
1e52036585 bootstrap: tar: use the nr_written value returned by xpc_buffer_write to increment the file cursor 2026-03-21 10:56:32 +00:00
24fc8ecb97 bootstrap: configure to build as a purely static executable 2026-03-21 10:55:49 +00:00
cc15bb54f3 ld: implement an actual program loader 2026-03-21 10:54:50 +00:00
ed138d581e prog: test: simple function call test 2026-03-21 10:54:21 +00:00
eaf5e02ad4 prog: systemd: simple function call test 2026-03-21 10:54:09 +00:00
88f8d4f18a lib: launch: implement alternate argument handling to support interpreters 2026-03-21 10:53:38 +00:00
5d9a3fa54d lib: launch: implement GLOB_DAT and RELATIVE relocations 2026-03-21 10:53:12 +00:00
8236f99aef lib: xpc: fix overlapping variable uses in xpc_string_t 2026-03-21 10:52:23 +00:00
81b9e7777a lib: xpc: fix overlapping variable uses in xpc_buffer_t 2026-03-21 10:52:16 +00:00
aa155824d3 lib: xpc: add a nr_written output to xpc_msg_write 2026-03-21 10:51:17 +00:00
af424d85d8 lib: fs: implement fs.seek() 2026-03-21 10:48:33 +00:00
a37a07d708 lib: fs: convert some verbose log messages to trace messages 2026-03-21 10:47:08 +00:00
2fab6687b0 lib: fs: fix incorect offset calculation in page request handler 2026-03-21 10:46:40 +00:00
d1a9c5cd45 lib: fs: implement private and shared file mappings 2026-03-21 10:46:15 +00:00
3bf995cdf6 lib: c: io: implement lseek() 2026-03-21 10:44:58 +00:00
8c09909d07 lib: c: malloc: enable the global heap for the static module 2026-03-21 10:44:47 +00:00
a041bc55db lib: c: rt: call task_exit once main() returns 2026-03-21 10:44:21 +00:00
32d0606d16 lib: c: io: add sys/types.h 2026-03-21 10:42:11 +00:00
3bc331b9c5 lib: c: io: add fcntl.h 2026-03-21 10:42:00 +00:00
c2b59ed494 lib: c: io: implement close() 2026-03-21 10:41:29 +00:00
c340f927bb lib: c: io: mmap can now reserve a region of memory when called with PROT_NONE 2026-03-21 10:40:44 +00:00
7a00de28a1 lib: c: io: munmap now unmaps and unreserves a region of memory 2026-03-21 10:40:15 +00:00
9148349f44 lib: c: implement strcpy and strncpy 2026-03-21 10:38:40 +00:00
766411d983 interface: fs: add fs.seek function 2026-03-21 10:35:48 +00:00
555989e74a cmake: build all programs as position-independent by default 2026-03-21 10:35:09 +00:00
ffc2ed735e toolchain: xpcg: replace bluelib with fx 2026-03-21 10:33:39 +00:00
68ae449731 toolchain: xpcg: add an offset type for signed offset values 2026-03-21 10:33:01 +00:00
08a9627548 ld: remove unused address space handle 2026-03-18 21:10:34 +00:00
844f6d50eb bootstrap: test pthread features 2026-03-18 21:10:18 +00:00
863be171c1 lib: launch: populate result with handles to the newly-created task 2026-03-18 21:09:59 +00:00
0471838f30 lib: fs: fix dangling address space handle 2026-03-18 21:09:23 +00:00
cf70352caa lib: c: add pthread implementation 2026-03-18 21:08:59 +00:00
342b588b38 meta: update kernel 2026-03-18 21:08:35 +00:00
cdf828be2d lib: c: implement munmap() 2026-03-18 20:49:19 +00:00
118 changed files with 5554 additions and 1001 deletions

View File

@@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 4.0)
project(Rosetta C CXX ASM) project(Rosetta C CXX ASM)
include(CheckPIESupported)
check_pie_supported()
set(sys_dir ${CMAKE_CURRENT_BINARY_DIR}/sys) set(sys_dir ${CMAKE_CURRENT_BINARY_DIR}/sys)
set(kernel_name mango_kernel) set(kernel_name mango_kernel)
@@ -25,6 +28,7 @@ add_subdirectory(interface)
add_subdirectory(sys) add_subdirectory(sys)
add_subdirectory(lib) add_subdirectory(lib)
add_subdirectory(services) add_subdirectory(services)
add_subdirectory(runlevel)
add_subdirectory(programs) add_subdirectory(programs)
sysroot_add_program(NAME ${kernel_name} BIN_DIR /boot) sysroot_add_program(NAME ${kernel_name} BIN_DIR /boot)

View File

@@ -5,17 +5,23 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
find_program(C_COMPILER x86_64-elf-gcc REQUIRED) find_program(C_COMPILER x86_64-elf-gcc REQUIRED)
find_program(CXX_COMPILER x86_64-elf-g++ REQUIRED) find_program(CXX_COMPILER x86_64-elf-g++ REQUIRED)
find_program(ASM_COMPILER x86_64-elf-as REQUIRED) #find_program(ASM_COMPILER x86_64-elf-as REQUIRED)
add_compile_definitions(__mango__=1) add_compile_definitions(__mango__=1)
set(CMAKE_C_COMPILER ${C_COMPILER}) set(CMAKE_C_COMPILER ${C_COMPILER})
set(CMAKE_CXX_COMPILER ${CXX_COMPILER}) set(CMAKE_CXX_COMPILER ${CXX_COMPILER})
set(CMAKE_ASM_COMPILER ${ASM_COMPILER}) #set(CMAKE_ASM_COMPILER ${ASM_COMPILER})
SET(CMAKE_C_FLAGS "-ffreestanding -nostdlib -z max-page-size=0x1000 -m64 -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234" CACHE STRING "" FORCE) SET(CMAKE_C_FLAGS "-ffreestanding -nostdlib -z max-page-size=0x1000 -m64 -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234" CACHE STRING "" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-shared" CACHE STRING "" FORCE) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-shared" CACHE STRING "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--unresolved-symbols=report-all,--dynamic-linker=/lib/ld64.so" CACHE STRING "" FORCE) set(CMAKE_EXE_LINKER_FLAGS "-Wl,--unresolved-symbols=report-all,--dynamic-linker=/lib/ld64.so" CACHE STRING "" FORCE)
set(CMAKE_C_LINK_OPTIONS_PIE "-pie")
set(CMAKE_C_LINK_PIE_SUPPORTED TRUE)
set(CMAKE_C_LINK_NO_PIE_SUPPORTED TRUE)
SET(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
set(CMAKE_C_OUTPUT_EXTENSION .o) set(CMAKE_C_OUTPUT_EXTENSION .o)
set(CMAKE_CXX_OUTPUT_EXTENSION .o) set(CMAKE_CXX_OUTPUT_EXTENSION .o)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)

View File

@@ -9,6 +9,36 @@ function(bsp_reset)
COMMAND_ERROR_IS_FATAL ANY) COMMAND_ERROR_IS_FATAL ANY)
endfunction(bsp_reset) endfunction(bsp_reset)
function(bsp_add_file)
set(options)
set(one_value_args ID SRC_PATH DEST_DIR)
set(multi_value_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
set(target_name ${arg_ID})
set(bsp_target_name _bsp-${target_name})
get_property(bsp_targets GLOBAL PROPERTY bsp_target_list)
list(LENGTH bsp_targets nr_bsp_targets)
if (${nr_bsp_targets} GREATER 0)
math(EXPR serialiser_index "${nr_bsp_targets}-1")
list(GET bsp_targets ${serialiser_index} serialiser)
endif ()
add_custom_target(${bsp_target_name}
COMMAND ${Python_EXECUTABLE} ${bsp_tool}
add-binary ${bsp_manifest} ${target_name}
${arg_DEST_DIR} ${arg_SRC_PATH}
COMMENT "Preparing bsp component: ${target_name}"
DEPENDS ${arg_SRC_PATH} ${serialiser})
set_property(GLOBAL PROPERTY bsp_target_list ${bsp_targets} ${bsp_target_name})
endfunction(bsp_add_file)
function(bsp_add_library) function(bsp_add_library)
set(options) set(options)
set(one_value_args NAME HEADER_DIR LIB_DIR) set(one_value_args NAME HEADER_DIR LIB_DIR)
@@ -70,6 +100,40 @@ function(bsp_add_program)
set_property(GLOBAL PROPERTY bsp_target_list ${bsp_targets} ${bsp_target_name}) set_property(GLOBAL PROPERTY bsp_target_list ${bsp_targets} ${bsp_target_name})
endfunction(bsp_add_program) endfunction(bsp_add_program)
function(bsp_add_service)
set(options)
set(one_value_args NAME BIN_DIR SVC_DIR)
set(multi_value_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
set(target_name ${arg_NAME})
set(bsp_target_name _bsp-${target_name})
get_property(bsp_targets GLOBAL PROPERTY bsp_target_list)
get_property(cfg_file TARGET ${arg_NAME} PROPERTY service_cfg_path)
list(LENGTH bsp_targets nr_bsp_targets)
if (${nr_bsp_targets} GREATER 0)
math(EXPR serialiser_index "${nr_bsp_targets}-1")
list(GET bsp_targets ${serialiser_index} serialiser)
endif ()
add_custom_target(${bsp_target_name}
COMMAND ${Python_EXECUTABLE} ${bsp_tool}
add-binary ${bsp_manifest} ${target_name}
${arg_BIN_DIR} $<TARGET_FILE:${target_name}>
COMMAND ${Python_EXECUTABLE} ${bsp_tool}
add-binary ${bsp_manifest} ${target_name}-cfg
${arg_SVC_DIR} ${cfg_file}
COMMENT "Preparing bsp component: ${target_name}"
DEPENDS ${target_name} ${serialiser})
set_property(GLOBAL PROPERTY bsp_target_list ${bsp_targets} ${bsp_target_name})
endfunction(bsp_add_service)
function(bsp_finalise) function(bsp_finalise)
set(options) set(options)
set(one_value_args BOOTSTRAP_PROGRAM DEST_DIR BSP_NAME) set(one_value_args BOOTSTRAP_PROGRAM DEST_DIR BSP_NAME)

View File

@@ -155,6 +155,40 @@ function(sysroot_add_program)
set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name}) set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name})
endfunction(sysroot_add_program) endfunction(sysroot_add_program)
function(sysroot_add_service)
set(options)
set(one_value_args NAME BIN_DIR SVC_DIR)
set(multi_value_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
set(target_name ${arg_NAME})
set(sysroot_target_name _sysroot-${target_name})
get_property(sysroot_targets GLOBAL PROPERTY sysroot_target_list)
get_property(cfg_file TARGET ${arg_NAME} PROPERTY service_cfg_path)
list(LENGTH sysroot_targets nr_sysroot_targets)
if (${nr_sysroot_targets} GREATER 0)
math(EXPR serialiser_index "${nr_sysroot_targets}-1")
list(GET sysroot_targets ${serialiser_index} serialiser)
endif ()
add_custom_target(${sysroot_target_name}
COMMAND ${Python_EXECUTABLE} ${sysroot_tool}
add-binary ${sysroot_manifest} ${target_name}
${arg_BIN_DIR} $<TARGET_FILE:${target_name}>
COMMAND ${Python_EXECUTABLE} ${sysroot_tool}
add-binary ${sysroot_manifest} ${target_name}-cfg
${arg_SVC_DIR} ${cfg_file}
COMMENT "Preparing sysroot component: ${target_name}"
DEPENDS ${target_name} ${serialiser})
set_property(GLOBAL PROPERTY sysroot_target_list ${sysroot_targets} ${sysroot_target_name})
endfunction(sysroot_add_service)
function(sysroot_add_file) function(sysroot_add_file)
set(options) set(options)
set(one_value_args ID SRC_PATH DEST_DIR) set(one_value_args ID SRC_PATH DEST_DIR)

View File

@@ -32,6 +32,29 @@ function(rosetta_add_executable)
DESTINATION ${arg_SYSROOT_PATH}) DESTINATION ${arg_SYSROOT_PATH})
endfunction(rosetta_add_executable) endfunction(rosetta_add_executable)
function(rosetta_add_service)
set(options)
set(one_value_args NAME CFG_FILE)
set(multi_value_args SOURCES)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}"
"${one_value_args}"
"${multi_value_args}")
set(exec_name ${arg_NAME})
get_property(programs GLOBAL PROPERTY rosetta_program_list)
set_property(GLOBAL PROPERTY rosetta_program_list ${programs} ${exec_name})
message(STATUS "Building service ${exec_name}")
add_executable(${exec_name} ${arg_SOURCES})
set_target_properties(${exec_name} PROPERTIES
POSITION_INDEPENDENT_CODE ON
service_cfg_path ${arg_CFG_FILE})
install(TARGETS ${exec_name}
DESTINATION ${arg_SYSROOT_PATH})
endfunction(rosetta_add_service)
function(rosetta_add_library) function(rosetta_add_library)
set(options STATIC SHARED) set(options STATIC SHARED)
set(one_value_args NAME) set(one_value_args NAME)

View File

@@ -3,7 +3,11 @@ interface fs 6400;
func open[0](path: string, flags: int) -> (err: int); func open[0](path: string, flags: int) -> (err: int);
func close[1]() -> (err: int); func close[1]() -> (err: int);
func read[2](count: size) -> (err: int, nr_read: size, data: buffer); func read[2](count: size) -> (err: int, data: buffer);
func write[3](data: buffer) -> (err: int, nr_written: size); func write[3](data: buffer) -> (err: int, nr_written: size);
func map[4](prot: int, flags: int) -> (err: int, vmo: handle); func seek[4](offset: offset, origin: int) -> (err: int, new_pos: offset);
func map[5](prot: int, flags: int) -> (err: int, vmo: handle);
func getdents[6]() -> (err: int, dents: buffer);

2
kernel

Submodule kernel updated: a2e918c428...a0a6a061a4

View File

@@ -26,5 +26,7 @@ bsp_add_library(
NAME libc NAME libc
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(libc libmango libxpc-static interface::fs) target_link_libraries(libc PRIVATE libmango librosetta libxpc-static interface::fs)
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1) target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1)
add_subdirectory(pthread)

View File

@@ -8,13 +8,17 @@ foreach (dir ${source_dirs})
set(headers ${headers} ${dir_headers}) set(headers ${headers} ${dir_headers})
endforeach (dir) endforeach (dir)
set(component_sources ${sources} PARENT_SCOPE) file(GLOB sys_sources
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.S)
set(component_sources ${sources} ${sys_sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE) set(component_headers ${headers} PARENT_SCOPE)
rosetta_add_library(STATIC rosetta_add_library(STATIC
NAME libc-core NAME libc-core
PUBLIC_INCLUDE_DIRS ${public_include_dirs} PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources} SOURCES ${sources} ${sys_sources}
HEADERS ${headers}) HEADERS ${headers})
sysroot_add_library( sysroot_add_library(
@@ -22,4 +26,4 @@ sysroot_add_library(
HEADER_DIR /usr/include HEADER_DIR /usr/include
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(libc-core libmango) target_link_libraries(libc-core PRIVATE libmango librosetta)

View File

@@ -1,6 +1,13 @@
#include <errno.h> #include <errno.h>
#include <mango/status.h> #include <mango/status.h>
static int __errno = 32;
int __attribute__((weak)) * __errno_location(void)
{
return &__errno;
}
#if defined(BUILD_STATIC) #if defined(BUILD_STATIC)
int __set_errno(int err) int __set_errno(int err)
{ {
@@ -12,6 +19,7 @@ int __set_errno(int err)
int __set_errno(int err) int __set_errno(int err)
{ {
/* TODO */ /* TODO */
*__errno_location() = err;
return -1; return -1;
} }
#endif #endif

View File

@@ -0,0 +1,26 @@
char *strcpy(char *output, const char *input)
{
unsigned int i;
for (i = 0; input[i] != 0; i++) {
output[i] = input[i];
}
output[i] = '\0';
return output;
}
char *strncpy(char *output, const char *input, unsigned int count)
{
unsigned int size = count;
unsigned int i;
for (i = 0; i < size; i++) {
output[i] = input[i];
if (input[i] == 0) {
break;
}
}
output[i] = '\0';
return output;
}

View File

@@ -0,0 +1,18 @@
#include <mango/log.h>
#include <rosetta/bootstrap.h>
#include <stdio.h>
extern int main(int, const char **, const char **);
void *__attribute__((weak)) pthread_self(void)
{
/* Nothing */
return NULL;
}
int __libc_init(const struct rosetta_bootstrap *bsinfo)
{
(volatile void)pthread_self();
kern_logf("bsinfo = %p", bsinfo);
return 0;
}

13
lib/libc/include/dirent.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef DIRENT_H_
#define DIRENT_H_
#define DT_UNKNOWN 0
#define DT_BLK 1
#define DT_CHR 2
#define DT_DIR 3
#define DT_FIFO 4
#define DT_LNK 5
#define DT_REG 6
#define DT_SOCK 7
#endif

View File

@@ -1,6 +1,8 @@
#ifndef ERRNO_H_ #ifndef ERRNO_H_
#define ERRNO_H_ #define ERRNO_H_
#define errno (*__errno_location())
#define SUCCESS 0 /* Success */ #define SUCCESS 0 /* Success */
#define EPERM 1 /* Operation not permitted */ #define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */ #define ENOENT 2 /* No such file or directory */
@@ -142,4 +144,6 @@
extern int __set_errno(int err); extern int __set_errno(int err);
extern int __errno_from_kern_status(unsigned int err); extern int __errno_from_kern_status(unsigned int err);
extern int __attribute__((weak)) * __errno_location(void);
#endif #endif

53
lib/libc/include/fcntl.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef FCNTL_H_
#define FCNTL_H_
#define O_RDONLY 0x0000 /* open for reading only */
#define O_WRONLY 0x0001 /* open for writing only */
#define O_RDWR 0x0002 /* open for reading and writing */
#define O_ACCMODE 0x0003 /* mask for above modes */
#define O_NONBLOCK 0x00000004 /* no delay */
#define O_APPEND 0x00000008 /* set append mode */
#define O_SHLOCK 0x00000010 /* open with shared file lock */
#define O_EXLOCK 0x00000020 /* open with exclusive file lock */
#define O_ASYNC 0x00000040 /* signal pgrp when data ready */
#define O_FSYNC O_SYNC /* source compatibility: do not use */
#define O_NOFOLLOW 0x00000100 /* don't follow symlinks */
#define O_CREAT 0x00000200 /* create if nonexistant */
#define O_TRUNC 0x00000400 /* truncate to zero length */
#define O_EXCL 0x00000800 /* error if already exists */
#define O_RESOLVE_BENEATH \
0x00001000 /* only for open(2), same value as FMARK \
*/
#define O_EVTONLY \
0x00008000 /* descriptor requested for event notifications only */
#define O_NOCTTY 0x00020000 /* don't assign controlling terminal */
#define O_DIRECTORY 0x00100000
#define O_SYMLINK 0x00200000 /* allow open of a symlink */
#define O_CLOEXEC 0x01000000 /* implicitly set FD_CLOEXEC */
#define O_NOFOLLOW_ANY 0x20000000 /* no symlinks allowed in path */
#define O_EXEC 0x40000000 /* open file for execute only */
#define O_SEARCH (O_EXEC | O_DIRECTORY) /* open directory for search only */
#define AT_FDCWD -2
#define AT_EACCESS 0x0010 /* Use effective ids in access check */
#define AT_SYMLINK_NOFOLLOW \
0x0020 /* Act on the symlink itself not the target */
#define AT_SYMLINK_FOLLOW 0x0040 /* Act on target of symlink */
#define AT_REMOVEDIR 0x0080 /* Path refers to directory */
#define AT_REALDEV \
0x0200 /* Return real device inodes resides on for fstatat(2) */
#define AT_FDONLY \
0x0400 /* Use only the fd and Ignore the path for fstatat(2) */
#define AT_SYMLINK_NOFOLLOW_ANY \
0x0800 /* Path should not contain any symlinks */
#endif

View File

@@ -11,6 +11,9 @@ extern size_t strlen(const char *s);
extern int strcmp(const char *s1, const char *s2); extern int strcmp(const char *s1, const char *s2);
extern int strncmp(const char *s1, const char *s2, unsigned long n); extern int strncmp(const char *s1, const char *s2, unsigned long n);
extern int strcpy(const char *s1, const char *s2);
extern int strncpy(const char *s1, const char *s2, unsigned long n);
extern void *memset(void *str, int c, size_t n); extern void *memset(void *str, int c, size_t n);
extern void *memcpy(void *dst, const void *src, size_t len); extern void *memcpy(void *dst, const void *src, size_t len);

View File

@@ -41,5 +41,6 @@ extern void *mmap(
int flags, int flags,
int fd, int fd,
off_t offset); off_t offset);
extern int munmap(void *addr, size_t length);
#endif #endif

View File

@@ -0,0 +1,17 @@
#ifndef SYS_TYPES_H_
#define SYS_TYPES_H_
#include <mango/types.h>
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
struct dentry {
unsigned long d_ino;
unsigned short d_reclen;
char d_type;
char d_name[];
};
#endif

View File

@@ -2,6 +2,7 @@
#define UNISTD_H_ #define UNISTD_H_
#include <stddef.h> #include <stddef.h>
#include <sys/types.h>
extern int open(const char *path, int flags); extern int open(const char *path, int flags);
extern int close(int fd); extern int close(int fd);
@@ -9,4 +10,8 @@ extern int close(int fd);
extern int read(int fd, void *buf, size_t count); extern int read(int fd, void *buf, size_t count);
extern int write(int fd, const void *buf, size_t count); extern int write(int fd, const void *buf, size_t count);
extern off_t lseek(int fd, off_t offset, int whence);
extern long getdents(int fd, struct dentry *dirp, unsigned int count);
#endif #endif

View File

@@ -0,0 +1,11 @@
#include <errno.h>
#include <mango/handle.h>
#include <mango/msg.h>
#include <rosetta/fs.h>
#include <sys/remote.h>
int close(int fd)
{
kern_handle_close(fd);
return 0;
}

View File

@@ -0,0 +1,22 @@
#include <errno.h>
#include <mango/handle.h>
#include <mango/msg.h>
#include <rosetta/fs.h>
#include <sys/remote.h>
#include <sys/types.h>
int getdents(int fd, struct dentry *dirp, unsigned int count)
{
int err;
size_t nr_read = 0;
kern_status_t status = fs_getdents(fd, &err, dirp, count, &nr_read);
if (status != KERN_OK) {
return __set_errno(__errno_from_kern_status(status));
}
if (err != SUCCESS) {
return __set_errno(err);
}
return nr_read;
}

View File

@@ -0,0 +1,22 @@
#include <errno.h>
#include <mango/handle.h>
#include <mango/msg.h>
#include <rosetta/fs.h>
#include <sys/remote.h>
off_t lseek(int fd, off_t offset, int whence)
{
int err;
off_t new_offset;
kern_status_t status = fs_seek(fd, offset, whence, &err, &new_offset);
if (status != KERN_OK) {
return __set_errno(__errno_from_kern_status(status));
}
if (err != SUCCESS) {
return __set_errno(err);
}
return new_offset;
}

View File

@@ -57,6 +57,24 @@ static int get_vmo(
return err; return err;
} }
static void *mreserve(kern_handle_t address_space, void *addr, size_t length)
{
virt_addr_t base = (virt_addr_t)addr;
if (!base) {
base = MAP_ADDRESS_ANY;
}
kern_status_t status
= address_space_reserve(address_space, base, length, &base);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
return (void *)base;
}
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{ {
int tmp = 0; int tmp = 0;
@@ -105,6 +123,12 @@ void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
return MAP_FAILED; return MAP_FAILED;
} }
if ((flags & (MAP_ANONYMOUS | MAP_PRIVATE)) && (prot == PROT_NONE)) {
void *ret = mreserve(address_space, addr, length);
kern_handle_close(address_space);
return ret;
}
kern_handle_t vmo = KERN_HANDLE_INVALID; kern_handle_t vmo = KERN_HANDLE_INVALID;
int err = get_vmo(fd, prot, flags, length, &vmo); int err = get_vmo(fd, prot, flags, length, &vmo);
if (err != SUCCESS) { if (err != SUCCESS) {

View File

@@ -0,0 +1,44 @@
#include <errno.h>
#include <mango/handle.h>
#include <mango/task.h>
#include <mango/vm.h>
#include <rosetta/fs.h>
#include <stdbool.h>
#include <sys/mman.h>
int munmap(void *addr, size_t length)
{
kern_status_t status = KERN_OK;
kern_handle_t self = KERN_HANDLE_INVALID,
address_space = KERN_HANDLE_INVALID;
status = task_self(&self);
if (status != KERN_OK) {
return __set_errno(EPERM);
}
status = task_get_address_space(self, &address_space);
kern_handle_close(self);
if (status != KERN_OK) {
return __set_errno(EPERM);
}
status = address_space_unmap(address_space, (virt_addr_t)addr, length);
if (status != KERN_OK) {
kern_handle_close(address_space);
return __set_errno(__errno_from_kern_status(status));
}
status = address_space_release(
address_space,
(virt_addr_t)addr,
length);
kern_handle_close(address_space);
if (status != KERN_OK) {
return __set_errno(__errno_from_kern_status(status));
}
return __set_errno(SUCCESS);
}

View File

@@ -8,7 +8,7 @@ int read(int fd, void *buf, size_t count)
{ {
int err; int err;
size_t nr_read; size_t nr_read;
kern_status_t status = fs_read(fd, count, &err, &nr_read, buf, count); kern_status_t status = fs_read(fd, count, &err, buf, count, &nr_read);
if (status != KERN_OK) { if (status != KERN_OK) {
return __set_errno(__errno_from_kern_status(status)); return __set_errno(__errno_from_kern_status(status));
} }

View File

@@ -30,4 +30,5 @@ sysroot_add_library(
HEADER_DIR /usr/include HEADER_DIR /usr/include
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_compile_definitions(libc-malloc PRIVATE ENABLE_GLOBAL_HEAP=1)
target_link_libraries(libc-malloc libc-core libmango) target_link_libraries(libc-malloc libc-core libmango)

View File

@@ -0,0 +1,46 @@
set(pthread_source_dirs thread)
foreach (dir ${pthread_source_dirs})
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
set(pthread_sources ${pthread_sources} ${dir_sources})
set(pthread_headers ${pthread_headers} ${dir_headers})
endforeach (dir)
file(GLOB pthread_sys_sources
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.S)
set(pthread_sources ${pthread_sources} ${pthread_sys_sources})
set(pthread_headers ${pthread_headers} ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread.h)
set(pthread_public_include_dir ${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(STATIC
NAME libc-pthread
PUBLIC_INCLUDE_DIRS ${pthread_public_include_dir}
SOURCES ${pthread_sources}
HEADERS ${pthread_headers})
rosetta_add_library(SHARED
NAME libpthread
PUBLIC_INCLUDE_DIRS ${pthread_public_include_dir}
SOURCES ${pthread_sources}
HEADERS ${pthread_headers})
sysroot_add_library(
NAME libc-pthread
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
sysroot_add_library(
NAME libpthread
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
bsp_add_library(
NAME libpthread
LIB_DIR /usr/lib)
target_link_libraries(libc-pthread PRIVATE libc-io libmango)
target_link_libraries(libpthread PRIVATE libmango)
target_link_libraries(libpthread PUBLIC libc)

View File

@@ -0,0 +1,25 @@
#ifndef PTHREAD_H_
#define PTHREAD_H_
#define __PTHREAD_ATTR_SIZE__ 32
typedef struct __pthread *pthread_t;
typedef struct __pthread_attr {
long __sig;
char __opaque[__PTHREAD_ATTR_SIZE__];
} pthread_attr_t;
extern int __pthread_init(void);
extern int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_func)(void *),
void *arg);
extern pthread_t pthread_self(void);
extern int pthread_join(pthread_t thread, void **retval);
extern int pthread_detach(pthread_t thread);
extern void pthread_exit(void *retval);
#endif

0
lib/libc/pthread/init.c Normal file
View File

View File

@@ -0,0 +1,13 @@
.code64
.global __pthread_self
.type __pthread_self, @function
__pthread_self:
push %rbp
mov %rsp, %rbp
mov %gs:0, %rax
pop %rbp
ret

View File

@@ -0,0 +1,35 @@
.code64
#include "mango/syscall.h"
.global __pthread_unmap_exit
.type __pthread_unmap_exit, @function
/*
%rdi = (kern_handle_t)address_space
%rsi = (void *)unmap_base
%rdx = (size_t)unmap_length
*/
__pthread_unmap_exit:
push %rbp
mov %rsp, %rbp
/* save the address space handle for later */
mov %rdi, %rbx
/* first, unmap the specified region */
mov $SYS_ADDRESS_SPACE_UNMAP, %rax
/* args are already in the correct registers */
syscall
/* next, close the handle to the address space */
mov $SYS_THREAD_EXIT, %rax
mov %rbx, %rdi
syscall
/* finally, stop the current thread */
mov $SYS_THREAD_EXIT, %rax
syscall
/* unreachable */
ret

View File

@@ -0,0 +1,9 @@
#include "pthread.h"
#include <pthread.h>
int *__errno_location(void)
{
struct __pthread *self = pthread_self();
return &self->thr_errno;
}

View File

@@ -0,0 +1,26 @@
#ifndef _THREAD_PTHREAD_H_
#define _THREAD_PTHREAD_H_
#include <mango/types.h>
enum pthread_flags {
THREAD_DETACHED = 0x01u,
};
struct __pthread {
struct __pthread *thr_self;
int thr_errno;
enum pthread_flags thr_flags;
kern_handle_t thr_handle;
void *thr_map_base;
size_t thr_map_size;
void *thr_result;
};
extern struct __pthread *__pthread_self(void);
extern void __pthread_unmap_exit(
kern_handle_t address_space,
void *unmap_base,
size_t unmap_length);
#endif

View File

View File

@@ -0,0 +1,89 @@
#include "pthread.h"
#include <errno.h>
#include <mango/status.h>
#include <mango/task.h>
#include <pthread.h>
#include <string.h>
#include <sys/mman.h>
#define DEFAULT_STACK_SIZE 0x40000
static void thread_launchpad(uintptr_t thread, uintptr_t func, uintptr_t arg)
{
struct __pthread *self = (struct __pthread *)thread;
void *(*start_func)(void *) = (void *(*)(void *))func;
void *result = start_func((void *)arg);
pthread_exit(result);
}
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_func)(void *),
void *arg)
{
kern_status_t status = KERN_OK;
kern_handle_t task;
status = task_self(&task);
if (status != KERN_OK) {
return __set_errno(EPERM);
}
size_t stack_size = DEFAULT_STACK_SIZE;
void *base
= mmap(NULL,
stack_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
if (!base) {
return __set_errno(ENOMEM);
}
virt_addr_t sp = (virt_addr_t)base + DEFAULT_STACK_SIZE;
sp -= sizeof(struct __pthread);
struct __pthread *new = (struct __pthread *)sp;
sp &= ~(virt_addr_t)0x10;
memset(new, 0x0, sizeof *new);
new->thr_self = new;
new->thr_map_base = base;
new->thr_map_size = stack_size;
uintptr_t args[] = {
(uintptr_t)new,
(uintptr_t)start_func,
(uintptr_t)arg,
};
size_t nr_args = sizeof args / sizeof args[0];
status = task_create_thread(
task,
(virt_addr_t)thread_launchpad,
sp,
args,
nr_args,
&new->thr_handle);
if (status != KERN_OK) {
munmap(base, stack_size);
return __set_errno(__errno_from_kern_status(status));
}
thread_config_set(
new->thr_handle,
THREAD_CFG_GSBASE,
&new,
sizeof(void *));
thread_start(new->thr_handle);
*thread = new;
return __set_errno(SUCCESS);
}

View File

@@ -0,0 +1,17 @@
#include "pthread.h"
#include <errno.h>
#include <mango/handle.h>
#include <mango/object.h>
#include <mango/signal.h>
#include <mango/task.h>
#include <pthread.h>
#include <sys/mman.h>
int pthread_detach(struct __pthread *thread)
{
thread->thr_flags |= THREAD_DETACHED;
kern_handle_close(thread->thr_handle);
return 0;
}

View File

@@ -0,0 +1,31 @@
#include "pthread.h"
#include <mango/handle.h>
#include <mango/task.h>
#include <pthread.h>
#include <stdlib.h>
extern void pthread_exit(void *retval)
{
struct __pthread *self = pthread_self();
if (!self) {
/* TODO: abort(); */
return;
}
if (self->thr_flags & THREAD_DETACHED) {
kern_handle_t task;
kern_handle_t address_space;
task_self(&task);
task_get_address_space(task, &address_space);
kern_handle_close(task);
__pthread_unmap_exit(
address_space,
self->thr_map_base,
self->thr_map_size);
} else {
self->thr_result = retval;
thread_exit();
}
}

View File

@@ -0,0 +1,31 @@
#include "pthread.h"
#include <errno.h>
#include <mango/handle.h>
#include <mango/object.h>
#include <mango/signal.h>
#include <mango/task.h>
#include <pthread.h>
#include <sys/mman.h>
int pthread_join(struct __pthread *thread, void **retval)
{
kern_wait_item_t wait;
wait.w_handle = thread->thr_handle;
wait.w_waitfor = THREAD_SIGNAL_STOPPED;
wait.w_observed = 0;
kern_status_t status = kern_object_wait(&wait, 1);
if (status != KERN_OK) {
return __set_errno(EINVAL);
}
if (retval) {
*retval = thread->thr_result;
}
kern_handle_close(thread->thr_handle);
munmap(thread->thr_map_base, thread->thr_map_size);
return 0;
}

View File

@@ -0,0 +1,36 @@
#include "pthread.h"
#include <mango/task.h>
#include <mango/types.h>
#include <string.h>
#include <sys/mman.h>
static struct __pthread main_thread = {0};
struct __pthread *pthread_self(void)
{
static int init = 0;
if (!init) {
kern_handle_t self_handle = KERN_HANDLE_INVALID;
kern_status_t status = thread_self(&self_handle);
if (status != KERN_OK) {
/* TODO set an errno value in a way that doesn't result
* in a recursive call to pthread_self */
return NULL;
}
struct __pthread *self = &main_thread;
self->thr_self = self;
self->thr_handle = self_handle;
self->thr_map_base = self;
self->thr_map_size = sizeof *self;
thread_config_set(
self_handle,
THREAD_CFG_GSBASE,
&self,
sizeof(void *));
init = 1;
return self;
}
return __pthread_self();
}

View File

@@ -1,6 +1,5 @@
file(GLOB runtime_sources file(GLOB runtime_sources
${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/*.s) ${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/*.s)
set_property(SOURCE ${runtime_sources} PROPERTY LANGUAGE C)
rosetta_add_object_library( rosetta_add_object_library(
NAME libc-runtime STATIC NAME libc-runtime STATIC

View File

@@ -3,14 +3,22 @@
.global _start .global _start
.type _start, @function .type _start, @function
.extern main .extern __libc_init
.type main, @function .type __libc_init, @function
.extern task_exit
.type task_exit, @function
_start: _start:
# Args (as provided by the ABI) # %rdi: (struct rosetta_bootstrap *)bs_info
# %rdi: int argc mov %rdi, %rbx
# %rsi: const char **argv call __libc_init
# %rdx: kern_handle_t task
# %rcx: kern_handle_t address_space mov 0(%rbx), %rdi # argc
mov 8(%rbx), %rsi # argv
mov 24(%rbx), %rdx # envp
call main call main
mov %rax, %rdi
call task_exit
1: jmp 1b 1: jmp 1b

View File

@@ -75,6 +75,7 @@ struct fs_context *fs_context_create(struct fs_allocator *alloc)
TEMP_OBJECT_SIZE, TEMP_OBJECT_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&temp_buffer); &temp_buffer);
kern_handle_close(address_space);
if (status != KERN_OK) { if (status != KERN_OK) {
kern_handle_close(ctx->ctx_temp_object); kern_handle_close(ctx->ctx_temp_object);
kern_handle_close(ctx->ctx_vm_controller); kern_handle_close(ctx->ctx_vm_controller);
@@ -89,7 +90,9 @@ struct fs_context *fs_context_create(struct fs_allocator *alloc)
ctx->ctx_vtable.close = fs_msg_close; ctx->ctx_vtable.close = fs_msg_close;
ctx->ctx_vtable.read = fs_msg_read; ctx->ctx_vtable.read = fs_msg_read;
ctx->ctx_vtable.write = fs_msg_write; ctx->ctx_vtable.write = fs_msg_write;
ctx->ctx_vtable.seek = fs_msg_seek;
ctx->ctx_vtable.map = fs_msg_map; ctx->ctx_vtable.map = fs_msg_map;
ctx->ctx_vtable.getdents = fs_msg_getdents;
return ctx; return ctx;
} }
@@ -138,6 +141,28 @@ kern_handle_t fs_context_get_vm_controller(const struct fs_context *ctx)
return ctx->ctx_vm_controller; return ctx->ctx_vm_controller;
} }
static enum fs_status handle_event(struct fs_context *ctx, xpc_msg_t *msg)
{
switch (msg->msg_event) {
case KERN_MSG_EVENT_CONNECTION:
kern_logf("received connection");
break;
case KERN_MSG_EVENT_DISCONNECTION: {
struct fs_file *f
= fs_context_get_file(ctx, msg->msg_sender.e_port);
if (f) {
fs_context_close_file(ctx, f);
}
break;
}
default:
kern_logf("received unknown event");
break;
}
return FS_SUCCESS;
}
static enum fs_status handle_msg(struct fs_context *ctx) static enum fs_status handle_msg(struct fs_context *ctx)
{ {
xpc_msg_t msg; xpc_msg_t msg;
@@ -147,16 +172,20 @@ static enum fs_status handle_msg(struct fs_context *ctx)
} }
if (status != KERN_OK) { if (status != KERN_OK) {
kern_logf("message recv error %d", status); kern_tracef("message recv error %d", status);
return FS_ERR_INTERNAL_FAILURE; return FS_ERR_INTERNAL_FAILURE;
} }
if (msg.msg_type != KERN_MSG_TYPE_DATA) {
return handle_event(ctx, &msg);
}
switch (msg.msg_header.hdr_interface) { switch (msg.msg_header.hdr_interface) {
case INTERFACE_FS: case INTERFACE_FS:
status = fs_context_dispatch_msg(ctx, &msg); status = fs_context_dispatch_msg(ctx, &msg);
break; break;
default: default:
kern_logf( kern_tracef(
"unknown message protocol %u", "unknown message protocol %u",
msg.msg_header.hdr_interface); msg.msg_header.hdr_interface);
xpc_msg_reply_error(&msg, KERN_UNSUPPORTED); xpc_msg_reply_error(&msg, KERN_UNSUPPORTED);
@@ -166,18 +195,43 @@ static enum fs_status handle_msg(struct fs_context *ctx)
return FS_SUCCESS; return FS_SUCCESS;
} }
static enum fs_status handle_page_request(struct fs_context *ctx) static enum fs_status handle_page_request_detach(
struct fs_context *ctx,
equeue_packet_page_request_t *packet,
struct file_mapping *mapping)
{ {
equeue_packet_page_request_t packet;
vm_controller_recv(ctx->ctx_vm_controller, &packet);
struct file_mapping *mapping = (struct file_mapping *)packet.req_vmo;
kern_logf( kern_logf(
"received page request [%zx-%zx] for file %s", "received page request (detach) for file %s",
packet.req_offset,
packet.req_offset + packet.req_length,
mapping->m_file->f_dent->d_name); mapping->m_file->f_dent->d_name);
size_t length = packet.req_length; struct fs_file *f = mapping->m_file;
switch (mapping->m_type) {
case FILE_MAPPING_PRIVATE:
queue_delete(&f->f_mappings, &mapping->m_entry);
break;
default:
break;
}
kern_handle_close(mapping->m_vmo);
fs_context_free(ctx, mapping);
fs_context_close_file(ctx, f);
return FS_SUCCESS;
}
static enum fs_status handle_page_request_read(
struct fs_context *ctx,
equeue_packet_page_request_t *packet,
struct file_mapping *mapping)
{
kern_tracef(
"received page request (read) [%zx-%zx] for file %s",
packet->req_offset,
packet->req_offset + packet->req_length,
mapping->m_file->f_dent->d_name);
size_t length = packet->req_length;
if (length > TEMP_OBJECT_SIZE) { if (length > TEMP_OBJECT_SIZE) {
length = TEMP_OBJECT_SIZE; length = TEMP_OBJECT_SIZE;
} }
@@ -187,20 +241,44 @@ static enum fs_status handle_page_request(struct fs_context *ctx)
enum fs_status status = fs_file_read_at( enum fs_status status = fs_file_read_at(
mapping->m_file, mapping->m_file,
&buf, &buf,
mapping->m_file_offset + packet.req_offset, packet->req_offset,
length); length);
if (status != FS_SUCCESS) { if (status != FS_SUCCESS) {
kern_logf("map-read failed with code %d", status); kern_tracef("map-read failed with code %d", status);
return status; return status;
} }
vm_controller_supply_pages( vm_controller_supply_pages(
ctx->ctx_vm_controller, ctx->ctx_vm_controller,
mapping->m_vmo, mapping->m_vmo,
packet.req_offset, packet->req_offset,
ctx->ctx_temp_object, ctx->ctx_temp_object,
0, 0,
packet.req_length); packet->req_length);
return FS_SUCCESS;
}
static enum fs_status handle_page_request(struct fs_context *ctx)
{
equeue_packet_page_request_t packet;
kern_status_t status
= vm_controller_recv(ctx->ctx_vm_controller, &packet);
if (status != KERN_OK) {
return KERN_BAD_STATE;
}
struct file_mapping *mapping = (struct file_mapping *)packet.req_vmo;
switch (packet.req_type) {
case PAGE_REQUEST_READ:
return handle_page_request_read(ctx, &packet, mapping);
case PAGE_REQUEST_DETACH:
return handle_page_request_detach(ctx, &packet, mapping);
default:
kern_logf("unknown page request type %zx", packet.req_type);
break;
}
return FS_SUCCESS; return FS_SUCCESS;
} }
@@ -259,6 +337,16 @@ struct fs_file *fs_context_get_file(struct fs_context *ctx, unsigned long id)
void fs_context_close_file(struct fs_context *ctx, struct fs_file *f) void fs_context_close_file(struct fs_context *ctx, struct fs_file *f)
{ {
if (f->f_ref > 1) {
kern_logf(
"reference to file '%s' has been closed",
f->f_dent->d_name);
f->f_ref--;
return;
}
kern_logf("file '%s' has been closed", f->f_dent->d_name);
btree_delete(&ctx->ctx_filelist, &f->f_node);
} }
static size_t get_first_path_component(const char *in, char *out, size_t max) static size_t get_first_path_component(const char *in, char *out, size_t max)

View File

@@ -52,3 +52,15 @@ enum fs_status fs_file_write(
f->f_seek = seek; f->f_seek = seek;
return status; return status;
} }
enum fs_status fs_file_readdir(struct fs_file *f, struct xpc_buffer *buf)
{
if (!f->f_ops || !f->f_ops->f_readdir) {
return FS_ERR_NOT_IMPLEMENTED;
}
off_t seek = f->f_seek;
enum fs_status status = f->f_ops->f_readdir(f, buf, &seek);
f->f_seek = seek;
return status;
}

View File

@@ -9,6 +9,9 @@
#include <fs/inode.h> #include <fs/inode.h>
struct fs_file { struct fs_file {
/* reference count includes the file descriptor, and any vm-objects
* attached to the file */
unsigned int f_ref;
/* id of the open file, equal to the koid of the port being used to /* id of the open file, equal to the koid of the port being used to
* access the file */ * access the file */
unsigned long f_id; unsigned long f_id;

View File

@@ -19,6 +19,8 @@ struct fs_file_ops {
size_t, size_t,
off_t *); off_t *);
enum fs_status (*f_seek)(struct fs_file *, off_t, int); enum fs_status (*f_seek)(struct fs_file *, off_t, int);
enum fs_status (
*f_readdir)(struct fs_file *, struct xpc_buffer *, off_t *);
}; };
extern struct fs_inode *fs_file_get_inode(const struct fs_file *f); extern struct fs_inode *fs_file_get_inode(const struct fs_file *f);
@@ -37,4 +39,8 @@ extern enum fs_status fs_file_write(
const struct xpc_buffer *buf, const struct xpc_buffer *buf,
size_t count); size_t count);
extern enum fs_status fs_file_readdir(
struct fs_file *f,
struct xpc_buffer *buf);
#endif #endif

View File

@@ -2,12 +2,14 @@
#define FS_INODE_H_ #define FS_INODE_H_
#include <fs/status.h> #include <fs/status.h>
#include <mango/types.h>
#include <stddef.h> #include <stddef.h>
struct fs_inode; struct fs_inode;
struct fs_dentry; struct fs_dentry;
struct fs_superblock; struct fs_superblock;
struct fs_file_ops; struct fs_file_ops;
struct file_mapping;
enum fs_inode_mode { enum fs_inode_mode {
FS_INODE_REG = 0x01u, FS_INODE_REG = 0x01u,
@@ -27,6 +29,7 @@ struct fs_inode {
const struct fs_inode_ops *i_ops; const struct fs_inode_ops *i_ops;
const struct fs_file_ops *i_fops; const struct fs_file_ops *i_fops;
size_t i_size; size_t i_size;
struct file_mapping *i_shared_mapping;
}; };
extern enum fs_status fs_inode_lookup( extern enum fs_status fs_inode_lookup(

View File

@@ -27,7 +27,6 @@ extern kern_status_t fs_msg_read(
const xpc_endpoint_t *sender, const xpc_endpoint_t *sender,
size_t count, size_t count,
int *out_err, int *out_err,
size_t *out_nr_read,
xpc_buffer_t *out_data, xpc_buffer_t *out_data,
void *arg); void *arg);
extern kern_status_t fs_msg_write( extern kern_status_t fs_msg_write(
@@ -38,6 +37,14 @@ extern kern_status_t fs_msg_write(
size_t *out_nr_written, size_t *out_nr_written,
void *arg); void *arg);
extern kern_status_t fs_msg_seek(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
off_t offset,
int origin,
int *out_err,
off_t *out_new_pos,
void *arg);
extern kern_status_t fs_msg_map( extern kern_status_t fs_msg_map(
xpc_context_t *ctx, xpc_context_t *ctx,
const xpc_endpoint_t *sender, const xpc_endpoint_t *sender,
@@ -47,4 +54,11 @@ extern kern_status_t fs_msg_map(
kern_handle_t *out_vmo, kern_handle_t *out_vmo,
void *arg); void *arg);
extern kern_status_t fs_msg_getdents(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
int *out_err,
xpc_buffer_t *out_dents,
void *arg);
#endif #endif

View File

@@ -0,0 +1,34 @@
#include "../file.h"
#include <errno.h>
#include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
kern_status_t fs_msg_getdents(
xpc_context_t *xpc,
const xpc_endpoint_t *sender,
int *out_err,
xpc_buffer_t *out_dents,
void *arg)
{
struct fs_context *ctx = arg;
struct fs_file *f = fs_context_get_file(ctx, sender->e_port);
if (!f) {
*out_err = EBADF;
return KERN_OK;
}
if (!(f->f_inode->i_mode & FS_INODE_DIR)) {
*out_err = ENOTDIR;
return KERN_OK;
}
size_t start = fs_file_get_cursor(f);
enum fs_status status = fs_file_readdir(f, out_dents);
size_t end = fs_file_get_cursor(f);
*out_err = fs_status_to_errno(status);
return KERN_OK;
}

View File

@@ -11,29 +11,25 @@
#include <stdio.h> #include <stdio.h>
#include <sys/mman.h> #include <sys/mman.h>
extern kern_status_t fs_msg_map( static int create_file_mapping(
xpc_context_t *xpc, struct fs_context *ctx,
const xpc_endpoint_t *sender,
int prot, int prot,
int flags, int flags,
int *out_err, struct fs_file *f,
kern_handle_t *out_vmo, struct file_mapping **out)
void *arg)
{ {
struct fs_context *ctx = arg; if ((flags & MAP_SHARED) && f->f_inode->i_shared_mapping) {
struct fs_file *f = fs_context_get_file(ctx, sender->e_port); *out = f->f_inode->i_shared_mapping;
if (!f) { return SUCCESS;
*out_err = EBADF;
return KERN_OK;
} }
struct file_mapping *mapping = fs_context_alloc(ctx, sizeof *mapping); struct file_mapping *mapping = fs_context_alloc(ctx, sizeof *mapping);
if (!mapping) { if (!mapping) {
*out_err = ENOMEM; return ENOMEM;
return KERN_OK;
} }
kern_logf("mapping file %s", f->f_dent->d_name); memset(mapping, 0x0, sizeof *mapping);
vm_prot_t vm_prot = VM_PROT_USER; vm_prot_t vm_prot = VM_PROT_USER;
if (prot & PROT_READ) { if (prot & PROT_READ) {
vm_prot |= VM_PROT_READ; vm_prot |= VM_PROT_READ;
@@ -59,14 +55,57 @@ extern kern_status_t fs_msg_map(
if (status != KERN_OK) { if (status != KERN_OK) {
fs_context_free(ctx, mapping); fs_context_free(ctx, mapping);
*out_err = __errno_from_kern_status(status); return __errno_from_kern_status(status);
return KERN_OK;
} }
mapping->m_file = f; mapping->m_file = f;
mapping->m_file_offset = 0; mapping->m_vmo = vmo;
kern_handle_duplicate(vmo, &mapping->m_vmo);
queue_push_back(&f->f_mappings, &mapping->m_entry); if (flags & MAP_SHARED) {
mapping->m_type = FILE_MAPPING_SHARED;
f->f_inode->i_shared_mapping = mapping;
} else {
mapping->m_type = FILE_MAPPING_PRIVATE;
queue_push_back(&f->f_mappings, &mapping->m_entry);
}
*out = mapping;
return SUCCESS;
}
extern kern_status_t fs_msg_map(
xpc_context_t *xpc,
const xpc_endpoint_t *sender,
int prot,
int flags,
int *out_err,
kern_handle_t *out_vmo,
void *arg)
{
struct fs_context *ctx = arg;
struct fs_file *f = fs_context_get_file(ctx, sender->e_port);
if (!f) {
*out_err = EBADF;
return KERN_OK;
}
struct file_mapping *mapping = NULL;
int err = create_file_mapping(ctx, prot, flags, f, &mapping);
if (err != SUCCESS) {
*out_err = err;
return KERN_OK;
}
kern_tracef(
"mapping file %s (%s) using vmo %zx",
f->f_dent->d_name,
(flags & MAP_SHARED) ? "shared" : "private",
mapping->m_vmo);
kern_handle_t vmo;
kern_handle_duplicate(mapping->m_vmo, &vmo);
f->f_ref++;
*out_err = SUCCESS; *out_err = SUCCESS;
*out_vmo = vmo; *out_vmo = vmo;

View File

@@ -4,6 +4,8 @@
#include <fs/context.h> #include <fs/context.h>
#include <fs/file.h> #include <fs/file.h>
#include <fs/status.h> #include <fs/status.h>
#include <mango/log.h>
#include <stdio.h>
extern kern_status_t fs_msg_open( extern kern_status_t fs_msg_open(
xpc_context_t *xpc, xpc_context_t *xpc,
@@ -39,10 +41,11 @@ extern kern_status_t fs_msg_open(
= fs_context_resolve_path(ctx, path_buf, &dent); = fs_context_resolve_path(ctx, path_buf, &dent);
if (fs_status != FS_SUCCESS) { if (fs_status != FS_SUCCESS) {
fs_context_close_file(ctx, f); fs_context_close_file(ctx, f);
*out_err = fs_status_to_errno(status); *out_err = fs_status_to_errno(fs_status);
return KERN_OK; return KERN_OK;
} }
f->f_ref = 1;
f->f_seek = 0; f->f_seek = 0;
f->f_dent = dent; f->f_dent = dent;
f->f_inode = dent->d_inode; f->f_inode = dent->d_inode;

View File

@@ -8,7 +8,6 @@ extern kern_status_t fs_msg_read(
xpc_endpoint_t *sender, xpc_endpoint_t *sender,
size_t count, size_t count,
int *out_err, int *out_err,
size_t *out_nr_read,
xpc_buffer_t *out_data, xpc_buffer_t *out_data,
void *arg) void *arg)
{ {
@@ -24,7 +23,7 @@ extern kern_status_t fs_msg_read(
size_t end = fs_file_get_cursor(f); size_t end = fs_file_get_cursor(f);
*out_err = fs_status_to_errno(status); *out_err = fs_status_to_errno(status);
*out_nr_read = end - start; out_data->buf_len = end - start;
return KERN_OK; return KERN_OK;
} }

View File

@@ -0,0 +1,52 @@
#include "../file.h"
#include <errno.h>
#include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
#include <sys/types.h>
extern kern_status_t fs_msg_seek(
xpc_context_t *xpc,
const xpc_endpoint_t *sender,
off_t rel_offset,
int origin,
int *out_err,
off_t *out_new_pos,
void *arg)
{
struct fs_context *ctx = arg;
struct fs_file *f = fs_context_get_file(ctx, sender->e_port);
if (!f) {
*out_err = EBADF;
return KERN_OK;
}
off_t new_offset = 0;
switch (origin) {
case SEEK_SET:
new_offset = rel_offset;
break;
case SEEK_CUR:
new_offset = f->f_seek + rel_offset;
break;
case SEEK_END:
new_offset = f->f_inode->i_size + rel_offset;
break;
default:
*out_err = EINVAL;
return KERN_OK;
}
if (new_offset > f->f_inode->i_size) {
*out_err = EINVAL;
return KERN_OK;
}
f->f_seek = new_offset;
*out_err = SUCCESS;
*out_new_pos = new_offset;
return KERN_OK;
}

View File

@@ -7,10 +7,15 @@
struct fs_file; struct fs_file;
enum file_mapping_type {
FILE_MAPPING_PRIVATE,
FILE_MAPPING_SHARED,
};
struct file_mapping { struct file_mapping {
enum file_mapping_type m_type;
struct fs_file *m_file; struct fs_file *m_file;
kern_handle_t m_vmo; kern_handle_t m_vmo;
off_t m_file_offset;
struct queue_entry m_entry; struct queue_entry m_entry;
}; };

View File

@@ -18,4 +18,4 @@ sysroot_add_library(
HEADER_DIR /usr/include HEADER_DIR /usr/include
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(liblaunch librosetta libmango libc-core) target_link_libraries(liblaunch PRIVATE librosetta libmango libc-core)

View File

@@ -334,6 +334,28 @@ static enum launch_status do_rela(struct elf_image *image, elf_rela_t *rela)
ELF64_R_SYM(rela->r_info), ELF64_R_SYM(rela->r_info),
rela->r_addend); rela->r_addend);
break; break;
case R_X86_64_GLOB_DAT:
sym = get_dynsym(image, ELF64_R_SYM(rela->r_info));
if (!sym) {
return LAUNCH_ERR_MISSING_SYMBOL;
}
*(uint64_t *)(image->e_local_base + rela->r_offset)
= image->e_remote_base + sym->st_value + rela->r_addend;
kern_tracef(
"GLOB_DAT: offset=%zx, symbol=%zu, addend=%zx",
rela->r_offset,
ELF64_R_SYM(rela->r_info),
rela->r_addend);
break;
case R_X86_64_RELATIVE:
*(uint64_t *)(image->e_local_base + rela->r_offset)
= image->e_remote_base + rela->r_addend;
kern_tracef(
"RELATIVE: offset=%zx, addend=%zx",
rela->r_offset,
rela->r_addend);
break;
default: default:
kern_trace("Unknown relocation type"); kern_trace("Unknown relocation type");
return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE; return LAUNCH_ERR_UNSUPPORTED_EXECUTABLE;

View File

@@ -45,7 +45,9 @@ struct launch_ctx {
struct launch_parameters { struct launch_parameters {
kern_handle_t p_parent_task; kern_handle_t p_parent_task;
kern_handle_t p_local_address_space; kern_handle_t p_local_address_space;
kern_handle_t p_executable;
const char *p_exec_path;
kern_handle_t p_exec_image;
const char *p_task_name; const char *p_task_name;

View File

@@ -38,6 +38,7 @@ static kern_handle_t get_library(
static virt_addr_t write_bootstrap_data( static virt_addr_t write_bootstrap_data(
struct stack_writer *stack, struct stack_writer *stack,
const char *interpreter,
const struct launch_parameters *params) const struct launch_parameters *params)
{ {
virt_addr_t bs_remote; virt_addr_t bs_remote;
@@ -51,9 +52,15 @@ static virt_addr_t write_bootstrap_data(
bs->bs_handles_count = params->p_handle_count; bs->bs_handles_count = params->p_handle_count;
bs->bs_channels_count = params->p_channel_count; bs->bs_channels_count = params->p_channel_count;
if (interpreter) {
/* two extra args: interpreter path and path to executable */
bs->bs_argc += 2;
}
const char **argv, **envp; const char **argv, **envp;
if (bs->bs_argc > 0) { if (bs->bs_argc > 0) {
int argc = bs->bs_argc;
virt_addr_t remote_argv; virt_addr_t remote_argv;
argv = stack_writer_put( argv = stack_writer_put(
stack, stack,
@@ -63,27 +70,36 @@ static virt_addr_t write_bootstrap_data(
bs->bs_argv = (const char **)remote_argv; bs->bs_argv = (const char **)remote_argv;
} }
if (bs->bs_envc > 0) { /* envc+1 so there is space for a null terminator */
virt_addr_t remote_envp; virt_addr_t remote_envp;
envp = stack_writer_put( envp = stack_writer_put(
stack, stack,
NULL, NULL,
bs->bs_envc * sizeof(char *), (bs->bs_envc + 1) * sizeof(char *),
&remote_envp); &remote_envp);
bs->bs_envp = (const char **)remote_envp; bs->bs_envp = (const char **)remote_envp;
size_t i = 0, j = 0;
if (interpreter) {
virt_addr_t arg_ptr;
stack_writer_put_string(stack, interpreter, &arg_ptr);
argv[i++] = (const char *)arg_ptr;
stack_writer_put_string(stack, params->p_exec_path, &arg_ptr);
argv[i++] = (const char *)arg_ptr;
} }
for (size_t i = 0; i < params->p_argc; i++) { for (; i < bs->bs_argc; i++, j++) {
virt_addr_t arg_ptr; virt_addr_t arg_ptr;
stack_writer_put_string(stack, params->p_argv[i], &arg_ptr); stack_writer_put_string(stack, params->p_argv[j], &arg_ptr);
argv[i] = (const char *)arg_ptr; argv[i] = (const char *)arg_ptr;
} }
for (size_t i = 0; i < params->p_envc; i++) { virt_addr_t env_ptr;
virt_addr_t env_ptr; for (i = 0; i < bs->bs_envc; i++) {
stack_writer_put_string(stack, params->p_envp[i], &env_ptr); stack_writer_put_string(stack, params->p_envp[i], &env_ptr);
envp[i] = (const char *)env_ptr; envp[i] = (const char *)env_ptr;
} }
envp[i] = NULL;
return bs_remote; return bs_remote;
} }
@@ -118,16 +134,20 @@ enum launch_status launch_ctx_execute(
return LAUNCH_ERR_TASK_CREATION_FAILED; return LAUNCH_ERR_TASK_CREATION_FAILED;
} }
char interp_path[4096];
interp_path[0] = 0;
struct elf_image image; struct elf_image image;
elf_image_init(&image); elf_image_init(&image);
enum launch_status status = elf_image_load( enum launch_status status = elf_image_load(
&image, &image,
params->p_executable, params->p_exec_image,
params->p_local_address_space, params->p_local_address_space,
remote_address_space); remote_address_space);
if (status == LAUNCH_ERR_INTERPRETER_REQUIRED) { if (status == LAUNCH_ERR_INTERPRETER_REQUIRED) {
snprintf(interp_path, sizeof interp_path, "%s", image.e_interp);
kern_handle_t interp = get_library( kern_handle_t interp = get_library(
ctx, ctx,
image.e_interp, image.e_interp,
@@ -187,7 +207,7 @@ enum launch_status launch_ctx_execute(
&stack, &stack,
local_stack_buf + STACK_SIZE, local_stack_buf + STACK_SIZE,
remote_stack_buf + STACK_SIZE); remote_stack_buf + STACK_SIZE);
virt_addr_t bsdata = write_bootstrap_data(&stack, params); virt_addr_t bsdata = write_bootstrap_data(&stack, interp_path, params);
virt_addr_t ip = image.e_hdr.e_entry + image.e_remote_base; virt_addr_t ip = image.e_hdr.e_entry + image.e_remote_base;
@@ -208,7 +228,10 @@ enum launch_status launch_ctx_execute(
thread_start(thread); thread_start(thread);
kern_handle_close(thread); result->r_task = remote_task;
result->r_thread = thread;
result->r_address_space = remote_address_space;
elf_image_cleanup(&image); elf_image_cleanup(&image);
return LAUNCH_OK; return LAUNCH_OK;

View File

@@ -12,4 +12,4 @@ sysroot_add_library(
HEADER_DIR /usr/include HEADER_DIR /usr/include
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(librosetta libmango) target_link_libraries(librosetta PRIVATE libmango)

View File

@@ -26,17 +26,17 @@ struct rosetta_bootstrap_channel {
}; };
struct rosetta_bootstrap { struct rosetta_bootstrap {
int bs_argc; uintptr_t bs_argc;
const char **bs_argv; const char **bs_argv;
int bs_envc; uintptr_t bs_envc;
const char **bs_envp; const char **bs_envp;
const struct rosetta_bootstrap_handle *bs_handles; const struct rosetta_bootstrap_handle *bs_handles;
size_t bs_handles_count; uintptr_t bs_handles_count;
const struct rosetta_bootstrap_channel *bs_channels; const struct rosetta_bootstrap_channel *bs_channels;
size_t bs_channels_count; uintptr_t bs_channels_count;
}; };
extern const struct rosetta_bootstrap_channel *rosetta_bootstrap_get_channel( extern const struct rosetta_bootstrap_channel *rosetta_bootstrap_get_channel(

View File

@@ -5,6 +5,7 @@
kern_status_t xpc_buffer_read( kern_status_t xpc_buffer_read(
const xpc_buffer_t *buf, const xpc_buffer_t *buf,
size_t offset,
void *out, void *out,
size_t max, size_t max,
size_t *nr_read) size_t *nr_read)
@@ -14,25 +15,35 @@ kern_status_t xpc_buffer_read(
return KERN_BAD_STATE; return KERN_BAD_STATE;
} }
size_t to_read = max; if (offset >= buf->buf_len) {
if (to_read > buf->buf_len) { if (nr_read) {
to_read = buf->buf_len; *nr_read = 0;
}
return KERN_OK;
} }
kern_status_t status size_t to_read = max;
= xpc_msg_read(buf->buf_origin, buf->buf_offset, out, to_read); if (offset + to_read > buf->buf_len) {
to_read = buf->buf_len - offset;
}
kern_status_t status = xpc_msg_read(
buf->buf_origin,
buf->buf_offset + offset,
out,
to_read,
nr_read);
if (status != KERN_OK) { if (status != KERN_OK) {
return status; return status;
} }
/* TODO */
*nr_read = to_read;
return KERN_OK; return KERN_OK;
} }
kern_status_t xpc_buffer_write( kern_status_t xpc_buffer_write(
xpc_buffer_t *buf, xpc_buffer_t *buf,
size_t offset,
const void *in, const void *in,
size_t len, size_t len,
size_t *nr_written) size_t *nr_written)
@@ -41,9 +52,17 @@ kern_status_t xpc_buffer_write(
return KERN_BAD_STATE; return KERN_BAD_STATE;
} }
if (offset >= buf->buf_max) {
if (nr_written) {
*nr_written = 0;
}
return KERN_OK;
}
size_t to_write = len; size_t to_write = len;
if (to_write > buf->buf_max) { if (offset + to_write > buf->buf_max) {
to_write = buf->buf_max; to_write = buf->buf_max - offset;
} }
if (!(buf->buf_flags & XPC_BUFFER_F_REMOTE)) { if (!(buf->buf_flags & XPC_BUFFER_F_REMOTE)) {
@@ -52,14 +71,72 @@ kern_status_t xpc_buffer_write(
return KERN_OK; return KERN_OK;
} }
kern_status_t status return xpc_msg_write(
= xpc_msg_write(buf->buf_origin, buf->buf_offset, in, to_write); buf->buf_origin,
if (status != KERN_OK) { buf->buf_offset + offset,
return status; in,
to_write,
nr_written);
}
xpc_status_t xpc_buffer_readv(
const xpc_buffer_t *buf,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_read)
{
if (!(buf->buf_flags & XPC_BUFFER_F_IN)) {
return KERN_BAD_STATE;
} }
/* TODO */ /* TODO limit to buffer bounds */
*nr_written = to_write;
return KERN_OK; if (!(buf->buf_flags & XPC_BUFFER_F_REMOTE)) {
/* TODO */
return KERN_UNIMPLEMENTED;
}
return xpc_msg_readv(
buf->buf_origin,
buf->buf_offset + offset,
iov,
nr_iov,
nr_read);
}
xpc_status_t xpc_buffer_writev(
xpc_buffer_t *buf,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_written)
{
if (!(buf->buf_flags & XPC_BUFFER_F_OUT)) {
return KERN_BAD_STATE;
}
/* TODO limit to buffer bounds */
if (!(buf->buf_flags & XPC_BUFFER_F_REMOTE)) {
/* TODO */
return KERN_UNIMPLEMENTED;
}
return xpc_msg_writev(
buf->buf_origin,
buf->buf_offset + offset,
iov,
nr_iov,
nr_written);
}
xpc_status_t xpc_buffer_length(const xpc_buffer_t *s)
{
return s->buf_len;
}
xpc_status_t xpc_buffer_capacity(const xpc_buffer_t *s)
{
return s->buf_max;
} }

View File

@@ -1,6 +1,7 @@
#ifndef XPC_BUFFER_H_ #ifndef XPC_BUFFER_H_
#define XPC_BUFFER_H_ #define XPC_BUFFER_H_
#include <mango/types.h>
#include <stddef.h> #include <stddef.h>
#include <xpc/status.h> #include <xpc/status.h>
@@ -16,14 +17,13 @@
.buf_flags = XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE, \ .buf_flags = XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE, \
.buf_origin = (msg), \ .buf_origin = (msg), \
.buf_offset = (offset), \ .buf_offset = (offset), \
.buf_len = (size), \ .buf_max = (size), \
} }
#define XPC_LOCAL_BUFFER_OUT(ptr, size) \ #define XPC_LOCAL_BUFFER_OUT(ptr, size) \
{ \ { \
.buf_flags = XPC_BUFFER_F_OUT, \ .buf_flags = XPC_BUFFER_F_OUT, \
.buf_ptr = (ptr), \ .buf_ptr = (ptr), \
.buf_max = (size), \ .buf_max = (size), \
.buf_len = (size), \
} }
struct xpc_msg; struct xpc_msg;
@@ -46,27 +46,18 @@ typedef enum xpc_buffer_flags {
typedef struct xpc_buffer { typedef struct xpc_buffer {
xpc_buffer_flags_t buf_flags; xpc_buffer_flags_t buf_flags;
union { /* only valid if F_OUT is set. specifies the maximum
/* fields that are only valid if F_OUT is set */ * number of chars that can be written to buf_buf,
struct { * including the null terminator. */
/* only valid if F_OUT is set. specifies the maximum size_t buf_max;
* number of chars that can be written to buf_buf, /* only valid if F_OUT is set.
* including the null terminator. */ * if F_FREE_ON_DISCARD is set, must be either NULL or
size_t buf_max; * allocated via xpc_context_alloc */
/* only valid if F_OUT is set. void *buf_ptr;
* if F_FREE_ON_DISCARD is set, must be either NULL or /* valid for F_IN and F_OUT. offset of the buffer data
* allocated via xpc_context_alloc */ * within the associated message. used when reading
void *buf_ptr; * buffer data from a message. */
}; size_t buf_offset;
/* fields that are only valid if F_IN is set */
struct {
/* only valid if F_IN is set. offset of the buffer data
* within the associated message. used when reading
* buffer data from a message. */
size_t buf_offset;
};
};
/* only valid if F_REMOTE is set. /* only valid if F_REMOTE is set.
* used to read/write buffer data from/to the sender's address * used to read/write buffer data from/to the sender's address
@@ -81,13 +72,31 @@ typedef struct xpc_buffer {
extern xpc_status_t xpc_buffer_read( extern xpc_status_t xpc_buffer_read(
const xpc_buffer_t *s, const xpc_buffer_t *s,
size_t offset,
void *out, void *out,
size_t max, size_t max,
size_t *nr_read); size_t *nr_read);
extern xpc_status_t xpc_buffer_write( extern xpc_status_t xpc_buffer_write(
xpc_buffer_t *s, xpc_buffer_t *s,
size_t offset,
const void *in, const void *in,
size_t len, size_t len,
size_t *nr_written); size_t *nr_written);
extern xpc_status_t xpc_buffer_readv(
const xpc_buffer_t *s,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_read);
extern xpc_status_t xpc_buffer_writev(
xpc_buffer_t *s,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_written);
extern xpc_status_t xpc_buffer_length(const xpc_buffer_t *s);
extern xpc_status_t xpc_buffer_capacity(const xpc_buffer_t *s);
#endif #endif

View File

@@ -17,10 +17,21 @@ typedef struct xpc_msg_header {
typedef struct xpc_msg { typedef struct xpc_msg {
xpc_endpoint_t msg_sender; xpc_endpoint_t msg_sender;
xpc_msg_header_t msg_header; kern_msg_type_t msg_type;
size_t msg_handles_count;
kern_msg_handle_t msg_handles[KERN_MSG_MAX_HANDLES]; union {
/* msg_type = KERN_MSG_TYPE_DATA */
struct {
xpc_msg_header_t msg_header;
size_t msg_handles_count;
kern_msg_handle_t msg_handles[KERN_MSG_MAX_HANDLES];
};
/* msg_type = KERN_MSG_TYPE_EVENT */
struct {
kern_msg_event_type_t msg_event;
};
};
} xpc_msg_t; } xpc_msg_t;
extern void xpc_msg_header_init( extern void xpc_msg_header_init(
@@ -34,12 +45,27 @@ extern kern_status_t xpc_msg_read(
const xpc_msg_t *msg, const xpc_msg_t *msg,
size_t offset, size_t offset,
void *p, void *p,
size_t count); size_t count,
size_t *nr_read);
extern kern_status_t xpc_msg_write( extern kern_status_t xpc_msg_write(
const xpc_msg_t *msg, const xpc_msg_t *msg,
size_t offset, size_t offset,
const void *p, const void *p,
size_t count); size_t count,
size_t *nr_written);
extern kern_status_t xpc_msg_readv(
const xpc_msg_t *msg,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_read);
extern kern_status_t xpc_msg_writev(
const xpc_msg_t *msg,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_written);
extern kern_status_t xpc_msg_reply( extern kern_status_t xpc_msg_reply(
const xpc_msg_t *msg, const xpc_msg_t *msg,

View File

@@ -18,7 +18,7 @@
.s_flags = XPC_STRING_F_OUT | XPC_STRING_F_REMOTE, \ .s_flags = XPC_STRING_F_OUT | XPC_STRING_F_REMOTE, \
.s_origin = (msg), \ .s_origin = (msg), \
.s_offset = (offset), \ .s_offset = (offset), \
.s_len = (size), \ .s_max = (size), \
} }
struct xpc_msg; struct xpc_msg;
@@ -41,25 +41,19 @@ typedef enum xpc_string_flags {
typedef struct xpc_string { typedef struct xpc_string {
xpc_string_flags_t s_flags; xpc_string_flags_t s_flags;
union { /* only valid if F_OUT is set. specifies the maximum
struct { * number of chars that can be written to s_buf,
/* only valid if F_OUT is set. specifies the maximum * including the null terminator. */
* number of chars that can be written to s_buf, size_t s_max;
* including the null terminator. */ /* only valid if F_OUT is set.
size_t s_max; * if F_FREE_ON_DISCARD is set, must be either NULL or
/* only valid if F_OUT is set. * allocated via xpc_context_alloc */
* if F_FREE_ON_DISCARD is set, must be either NULL or const char *s_buf;
* allocated via xpc_context_alloc */
const char *s_buf;
};
struct { /* valid for F_IN and F_OUT. offset of the string data
/* only valid if F_IN is set. offset of the string data * within the associated message. used when reading
* within the associated message. used when reading * string data from a message. */
* string data from a message. */ size_t s_offset;
size_t s_offset;
};
};
/* only valid if F_REMOTE is set. /* only valid if F_REMOTE is set.
* used to read/write string data from/to the sender's address space. */ * used to read/write string data from/to the sender's address space. */

View File

@@ -54,14 +54,24 @@ static kern_status_t __msg_recv(
return status; return status;
} }
if (!xpc_msg_header_validate(&out->msg_header)) { switch (msg.msg_type) {
return KERN_INVALID_ARGUMENT; case KERN_MSG_TYPE_DATA:
if (!xpc_msg_header_validate(&out->msg_header)) {
return KERN_INVALID_ARGUMENT;
}
break;
case KERN_MSG_TYPE_EVENT:
out->msg_event = msg.msg_event;
break;
default:
break;
} }
out->msg_sender.e_channel = channel; out->msg_sender.e_channel = channel;
out->msg_sender.e_task = msg.msg_sender; out->msg_sender.e_task = msg.msg_sender;
out->msg_sender.e_port = msg.msg_endpoint; out->msg_sender.e_port = msg.msg_endpoint;
out->msg_sender.e_msg = msg.msg_id; out->msg_sender.e_msg = msg.msg_id;
out->msg_type = msg.msg_type;
return KERN_OK; return KERN_OK;
} }
@@ -89,34 +99,66 @@ kern_status_t xpc_msg_read(
const xpc_msg_t *msg, const xpc_msg_t *msg,
size_t offset, size_t offset,
void *p, void *p,
size_t count) size_t count,
size_t *nr_read)
{ {
kern_iovec_t iov = IOVEC(p, count); kern_iovec_t iov = IOVEC(p, count);
size_t r = 0;
return msg_read( return msg_read(
msg->msg_sender.e_channel, msg->msg_sender.e_channel,
msg->msg_sender.e_msg, msg->msg_sender.e_msg,
offset, offset,
&iov, &iov,
1, 1,
&r); nr_read);
} }
kern_status_t xpc_msg_write( kern_status_t xpc_msg_write(
const xpc_msg_t *msg, const xpc_msg_t *msg,
size_t offset, size_t offset,
const void *p, const void *p,
size_t count) size_t count,
size_t *nr_written)
{ {
kern_iovec_t iov = IOVEC(p, count); kern_iovec_t iov = IOVEC(p, count);
size_t w = 0;
return msg_write( return msg_write(
msg->msg_sender.e_channel, msg->msg_sender.e_channel,
msg->msg_sender.e_msg, msg->msg_sender.e_msg,
offset, offset,
&iov, &iov,
1, 1,
&w); nr_written);
}
kern_status_t xpc_msg_readv(
const xpc_msg_t *msg,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_read)
{
return msg_read(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
offset,
iov,
nr_iov,
nr_read);
}
kern_status_t xpc_msg_writev(
const xpc_msg_t *msg,
size_t offset,
kern_iovec_t *iov,
size_t nr_iov,
size_t *nr_written)
{
return msg_write(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
offset,
iov,
nr_iov,
nr_written);
} }
kern_status_t xpc_msg_reply( kern_status_t xpc_msg_reply(

View File

@@ -19,14 +19,12 @@ xpc_status_t xpc_string_read(
} }
kern_status_t status kern_status_t status
= xpc_msg_read(s->s_origin, s->s_offset, out, to_read); = xpc_msg_read(s->s_origin, s->s_offset, out, to_read, nr_read);
if (status != KERN_OK) { if (status != KERN_OK) {
return status; return status;
} }
out[to_read] = '\0'; out[to_read] = '\0';
/* TODO */
*nr_read = to_read;
return KERN_OK; return KERN_OK;
} }
@@ -47,14 +45,10 @@ xpc_status_t xpc_string_write(
to_write = s->s_max - 1; to_write = s->s_max - 1;
} }
kern_status_t status return xpc_msg_write(
= xpc_msg_write(s->s_origin, s->s_offset, in, to_write); s->s_origin,
if (status != KERN_OK) { s->s_offset,
return status; in,
} to_write,
nr_written);
/* TODO */
*nr_written = to_write;
return KERN_OK;
} }

View File

@@ -1,10 +0,0 @@
file(GLOB sources *.c)
add_executable(systemd ${sources})
target_link_libraries(systemd libc libc-runtime liblaunch libmango)
sysroot_add_program(
NAME systemd
BIN_DIR /usr/bin)
bsp_add_program(
NAME systemd
BIN_DIR /usr/bin)

View File

@@ -1,9 +0,0 @@
add_executable(test test.c)
target_link_libraries(test libc libc-runtime liblaunch)
sysroot_add_program(
NAME test
BIN_DIR /usr/bin)
bsp_add_program(
NAME test
BIN_DIR /usr/bin)

View File

@@ -1,157 +0,0 @@
#include <string.h>
const char *s
= "RHZVNYYFPCGZIKWYLOZAKKLZGKWXDPXSTWNSWDBVDCPUMTAZCRNGNHGQPAGEWVAOCJST"
"PBXVWPKXQAHGETDTDETVYAEQGNBLEQIPHGGWKEDJAULOVMZKNABLUUXOTMHJNAVLSGCZ"
"QIFHIUCBCIRZIOFVHBPSGVBBZSRAQZYRPMYBNJDFTWSUUZVBQZTBUFUDJDYKUXWHDMXD"
"JKBSNWLFPUDGRMQPBCWVJZHOTJBTMGUSXQUZVXLDKWIKINXRFJKSYJEKDAPRQPMQMJPS"
"ICCTMELLKDFFJXOXISIXNVANFHLRPYMNPYCMUOYSPAYCKYJKRBZENHXYRJWRYXZGETMJ"
"XBFTCMSIHZQSCMLESDFKGTTNMCZSXEFMGXZYPWVPODMYTLDUOKGPMTMFBTQQHPBHMNCM"
"LYRGGUAIRSFFBRSKXOLJBWEMEODRQLXZJDRSTXBJOKOMUQKCJVKFHDYXCUUDHDEITHNH"
"VQLJJQMLYWGIDVLYCEJTJFJQLTKSAPZGEEZKVLQPHIVJNJVTXJUGPZODIFXTQNLBSFLG"
"NSPMGLUSEBOFJWXFFRBHIHYGGTILVVOJRPOFOIGDFCHLAZXLSOUCPCLZCBVWGZVKGDON"
"RPYOTSRWUNAGQSPHSGEQHOLUSOZCQQGJBLPKQNGKOPCVKLACDBPAPXDMGKLFPUOFQDWY"
"INIKZPLVFSZZZZHAYKXTETJDPMBHKNRCRLXZHFENZCABDTZULCRHCCVZFETBEBEJFVKJ"
"ADWFSHKKSMMKGTIHPAIAMWXTRJILBMWMBDZGRPZXHMJVCWPKSNPYPPNSAVQDSMANBFZO"
"LJBYKDOZNAPZRWEQDIIZRPNGZGHQWPIONPSAMBNNZERYMIQOVHRGZFXWVUARJMFWNPQP"
"GHDCZABLOYHCBCXAIDSPMDKZVBBOKHAHGTEPRQAIBVWTFBQDGDJPQGMVAGQQVMULVPMG"
"UPGEJUIZZXQRQKRJUCKDDZFTAHAAHMJLSISGFFOXOYNMJCAPPQXAVFSAFFRPRTEQLNCX"
"JVKTHBPZLAEXSIGVJASAERWDGDQDXASXHRSSCNAUMRWSQDZTOJHJGJLLXMJSTXBHOYPH"
"ELYKSXNJSPWPMFAKOOTXXTOEBLYFSOIJDWAOCTHDFOEBEEXVUBXOJDUCJWQOUUDOJNZG"
"PULPYTAOQEXMHSGOOUXHAJOKRHOOMZYMBHQNTQDWZPCXATDEKTYLNBKNUEIINHQTEGTR"
"ZKLMAKIIHHZBQIPXLAGADCFDYWEOJVHFPEMRDIOJYAMWSWEUOPJFEDGRGJOQNTSHRIJY"
"JPTOSWYZXJCGXLYVOWKAFGULLNCKIUZDWUXTHNYSWMMCJGTFVVVPJHEKYQVFRWLIZBBK"
"CNCRITFZYTQZZGZHXELBEYXSVVYRFBGRFPRDROUXKUMAGFYOJRMCLLHJVMQFYOBCXSEL"
"OQAQTRMLSGDAXWMBRSQHCIYYMBQQHMUQOKIANZCBGKHLCPUVUEZVKDTTSOWKKWIUBAIW"
"SOCJAUALJFEQQXJBHRRZBFMJZZMIWTFKQDPOBFIGABJTHFLLSZPWWGGLHLYXKBODKBIV"
"GAYGIKHNMTMJHCPRBQYAACGSFZPJWXUTRZFCGTLFQBVHZBKYBRMYTTCGIDKYWVRPJDTX"
"RKXGOPOQLNSEIGHTSAXGPBROFHQACSIVSLCXTEDUOEPRMGJDYWTKEHCXWINUDCAZWAEY"
"RQDKZRZXKWGHVWJDYHGFLCGKCLYCVHZTWWXPDBKTMBKBASERMURDREKNYVOCPHFSEGBQ"
"LAUHDDCAPPGOAFZYJYXPPAQLUQVKSDEHPPDXMNWAAYLHXBFEFXRLSMQNIYDECYVVPHEE"
"WXFFPEYLSHBXLYJWRABFKJYMJNWAUMVYJKZRDMPUQJKWVNTPRMHTAQGNSDLFTXVNIAIJ"
"HOIISROAJCWEOAIHYMDGWEOABPGIMBTTGWYVJDZOOMUSHYDPCMKWDIXDGJCGTQVXWBKP"
"DBCVJJDYIAPXKINQXACEMTJRCIAENGTTMWXVSQCCXRDVNZZNQDZTTYJHQGXZIJIIKPAU"
"TQJDDQQEPGYZNKCKNMVFCRHUECPVFZYVUWVMSCIQZBVLSTNFAHDDEQRKDOUAQVRVQAVB"
"ZCEMAJRJBVWKVBNEIQWWQSJPUVUKMBJIISCWXGGMWANYYLPCXHCBARMFTFMDXWSMKXPW"
"DZUGFBSGGWXLOFGYJVIDWNTSGODTHQNCKPWRJENDZNSCEYZRLEPNNYVBNUZMXAUWNAJD"
"XGTOLUAAIAHMDJERSESVFSMMHJKHIVIBWZLEAXUKRSWJOTFODRBZIJBRJQTFBVRQHITD"
"TDBAJZCZUKSIZJYDXWTSRPLXULXHGEKMWMICUYVAGNGEICEMMVWLLYWTAKWNGLRYOCIG"
"BEYTLVAZFHBYIJPUAQHITKHPWAQNEBQVAYZEINLRCKUZILAQPAGBJDWWLGCPQZOZVDQP"
"MWTIOAFMEMFKLGVGGHTTKNERTLPPQFALZMCWSOMJQQZMRABNKBCYPFJOWQCXJKXTNOMJ"
"MXAWMPFBJHOYHVOBDNWTKHYTISUQMFSNVBGUHDQFYCSZLZAFABKYQSZRQGKXOXORQPSJ"
"NKRVVAXMMVVPBSWMTHUNXBLSVIOOQPLRPROIBBQGNQVOXQXRNNMSFGUZEIGIYMLMLYYL"
"VINTZYXYXHUFMTQFPDGSFFDVCDMEZXSGQMMGJWMWANFSZNHDIIHVJFOZGMHAOVRUWWVX"
"RCOJJKZLTMAOGSRWNNXPYDCQWSSOFWUKFPKQGYLFSMZBZBKWSBMMZMFPOYYMLVYHQQQF"
"HORVESQYIKEBBKSEUYXUFRNNXZPUYESZWAKQQPAWZUHYJLXRXBFPRFSCHIHHDVAIKYDZ"
"IDLVQBCSGOSGFOUKVMKTODAHQVTACKAONRDYENPGSQFKGKYQROFOEKMJXKFIAEKWNRJH"
"RZCCSMNSSHZNSRTBGFJJDWAPVIOBDCQKMDEMUIWGMETBUTCGMMGXLHWWTXXQYAPMQQGU"
"CHECLYRWNFKHGRWYZISFYKSGTJXKTKIMJKTUWOQFHXUVTOBYUCOZKLCQCUIURHSIGUAU"
"FFSNEHFLHNGBNVTGPKCVCQLHEHLJRWPGSWHKFMMXSSCVTCUOEEZOFOPTDRUPPCYTRSKI"
"NJBPLOHMHQLWKMVBSZLZVDZEKXKSCNWPZTGZUXRYJEPENAYFCEKCAMWQLNYDHCSUUSTJ"
"GFZCTKDQYPEZKOOJQTYMWHZDDTCMYUXCAKFXISWQZDVETOAYIANBRSXLYKOGGHEEEGAX"
"SRIASWZBXTFCHLKMXQDYNLZICZZANCBUVGWFWFHYAWVLQXTQPGPQGRGBEZVIIGZJUVQU"
"PNXEMZDIFXAKSHTCCBQSAXWFBNLRYQKXKXQHAFZTUICFQVYOXQEHASXNSVUTYKSVYTMH"
"UTPBEVILWSKGQXPAEEOPUSMGQVPWFMRZRIMJZRRQRIZBTTRROUWENBHUYVMOMVPFDLZH"
"XMXYRNASODBTLCNRDSLGPTZBZHKTSMHIVNFJOMOFPHDANVSVOYZSTKOQJLDPKLOMAYUU"
"CKWTOTDONTXKCEGVXKZNNFIUXHLJPFFNVMWSFPXZKROEIGQNGXWDRFJWDCUEGJCUJGVG"
"PHYKQEWVOHHPURHBBIEZCKQCFUFFBDXYRNOHAVJISOQYXMRXIEFEISFEZHLNTJXYEAKM"
"EKZPJQVQBKPXPFSOANBBJBAFJQEMPIELYUHYCHUTADTCLFXUQLXWTJEFLJXVBRQXYSIR"
"RPMTNMFMUCHQJEVXUSFYUUYJHLEQBHUQOTVADYQGRXVLUPQXVXEDIGNSCYNMKPWLFLHZ"
"LMQGPTMBDVUJOBSXDFHKSIEXJJQTURPNZVQDLUEJHQZOQSBMPMBEQOCOSEKVXIVSQIQL"
"GSQAUMIAHHLQCBCQWFJWHSYNRFFTBKORISDYNRSMPVERKRJBWGYJRXMKHJDAKRANHFDH"
"WTZOHYRVCTTUXCRAFNOLYPRGDYTXNSOTCDNFVVURJILWVDWOCGPQOZIGGNOEAHCBYGMC"
"XGXAADYMYDAUXPDFADTVEQTHZRGYASPJRDIKJUFIRXGMFSCIURDNFIDUUDEKPFGWECZC"
"OOFZWESHSPSOOBWZKIGODSLXCALULNOLQLCMMLSQDWJDTEOIYXFCLSLKJKGCGURXEEIN"
"SCUQTRDGMYXFZEFBATVSYVAJISCBVDBZAJAPKBBQTQNNRZYBLGWPCIORYJJEKIZXRRCG"
"ZHGQNMGWVNIANJXYJMWRCGDGDFFQISSZOWTQOKWRGXSGRUSJOHABJUEUIHNTLCXJQPNF"
"YUKTQCGRFGZOQWYLJOGOGSRDXESAOTHZVHBEOOYJZYTMOSUUXDQNKTQBVUMRBPJEJIBU"
"TOVXSGYSTADWQKFUEFWJDCAYTEYVZYDCQTHXJWYUESZSLRBKRAMLVVVBMEYSYFNBLKTY"
"UJRQBOKJQTYXTOFPWGWEEANVFYMAVRKMNJARUOKTZTMMJKNVFEVSECABUZGGUEHRJIHO"
"JODXJOOGFZWNURNEXBUCCUHUDYXBZTNJZSQGHAGYLJQSSJERWEGUFAJXGNBXDWVFSCEG"
"SUCLQLHHTRQADZIBKFCBBEXUDLPCFUDONSHUUCREKHDUBQBKMECPPOGFYIUZNUDKTILB"
"IHMYNAMJIDTJEQTVPFZDNONMWFIJEAUOLPWOZVKEFTXRCXNWHWPYDHLWNSWTMUEIBMSK"
"FWROAFBMEOJAVLMNCNWEMGRUDKRPENXCJQQGLPCODNOTGPOQFZTOBEBJIDAMMZARXTMC"
"EAHKYNTYZKWCUFYOSCOPICKIDAUSZHWNTVRRSTIMHFBUALQECIZKYFUYJHDTFDODXXNJ"
"AKZNUMYZSHIGZQQXBTORWFCGQFKFURMZYWBAQSHAJEASIYAFQZDOUHBJXODDUAWNKWVB"
"NABZSUNRULZDXKBRGVCKUIYVRVRMTDFSWCTCDYKBZDELJBDIHLOALYEKHNMECBWRZQBK"
"XLWFYJYECKOJOGXJYBKFSUQZKEUWBHEWNHSZKJPRQRMLRFLJWBDZEJQVYRAFQGEOGUBU"
"SVVWUGKXHSXHRXWCZKASIYPZZDLRUVBNBUQEEPZPHMSNUETUKMYWNJLEZWVOLZBQMLWE"
"YPPVBOTADNFNJWUZKDWRXCJCMDQPGPBIVAVQJVTHEPLXEKPSPJQFNGILKTUETORGMHGH"
"HHXTZIXUXPDLKNYGHNNTKAZFCGCUONFANKRXHGPQLPDJACZDMSSFPJHRPPGGSVEYKQHF"
"JKASAYIFKXXVEYRCLIMLDEUQWIHZXPLKDCHUFYAHLOQUJMJCXTHFAOSOEYWOMFAZHGPE"
"UNYKWLFYQPMRYXDVGWWMOLXHCHQADSYAAQMLBGGNQELFWMYHPWNIDOIFLGHGQUPCVPHS"
"WDGERQMWOZBWFHTOSINKTPXQLFGHLVALHCYSPKFBWSYTUHMZQNZSDAQTAZLPHSYZKROA"
"PSKJEWCRABAGYIIAYAUOVMTYIQOWYWHLLEXOOVZNLXOIPFNRYHDJYVTJLOHODYRBBBSB"
"NPQCNUZHYTWDAQSEBEMDSEDTKORHUCILESZYYYLJNRCFHAWNUMQHDQKXGCJIZOGBDVTU"
"PWNKAHKIRBHINKVRRBOPVAWCSPVMTNQQYDYLCKHPKRFYCAYUPGAOQLJSTHGMCXUUQIVI"
"MNPISKLETFEWNDDTDHLCQXNGRJJZHGJYYWNXKQIWXENKWQAGAXTCTLGWNVXDMMPHYPBQ"
"GWWNCWJWYVBVYOWOEJJPZAZGKJEQHPDBYUQBMOLOIMZXYXFOBNNPMGDCTXLCHBEBHCOS"
"HGKAEBGPLANNUHMOHWHAQEWFJSWPIFTWZNKWHKZYDXDAJODTHPXPIGVFYVDNWEQFKKIC"
"EBMGPSBVTPXODJVAYJAURNSFOCUNJROYEMOELHMIGLFDMJQFVEOSINHIWDUUIPNSBHEC"
"TKUFRERFNYCWSSGCYQWMXOQFCZPCSAVRBMSFZEYDBSWWHYLHIGGIDQJRTLNJOMWQVKES"
"KTFWQIRKJEMAZSMFQQSSTCXKOUZLJJWNYJJKSHPAOTEWEKKABTJDOFRGKVBMJFKFFVSP"
"GPMUCDWAFPHLKKZGEYTQNFJBGJTSATHNVDWRKSMLAJAPHYEJXYEKCTKDFGDILOIRDWLV"
"LAMTOCSMRMXYYHPHYBMKAVDRWYSXVPLZUBPAVUUQDNRCNYPKUSWBTCHJMIHQJNXXXXQX"
"LIUZQDFCTJBHELXALVTAJDFIPIFAKJKCPPPPXAVPTOUTLTIGMBUWOIERHBYOIMWTTXOY"
"KCZKDVRSARRBMSQFZGGSVPVBHKBYXZBITZDBQDBZLQNPVEQTXECOHOJKEXUUIBXSORPF"
"THLTMDDDOYSQZBGMBGZFYAJMHWZOLRUUJAIHOLSCIYGHMRAEIKFLFNLEMHOPKVRTJCMJ"
"DKBKJCMDBPGUGPPZBCXYRLHZUYPMIQOXYOCGKBEHZFHGAAKQINMHUNTSJHPPZGNKFREX"
"HGGFEFDAWMCMIXEDLUPDAXNCTHFDMHJPZOGJILKJXRUQBGXKDXTBZXSPZLZUCNCZZYRU"
"DRUEVXRELACIWMGUIBKEXSYTBIJTJPJJLCIQQBVJGXHPCTSHPASIIAMPATSDCTXZAPCJ"
"ESVMBOTOLKGHVRZSBVOBSAAKRPSAFYNPIDVFUMNMJRGKWOANKHZYCABHWIWUJFLDPSFY"
"SPBXQEFLNEEMIGMWWXYTXNTHRXUZQKXCMBLEHGRBFPSUMGMBJFFWTAEFCLDBOHMNAICE"
"YAZCTBCHKXEIBYUTQEAOVDJVOLTYDJJUCPSXUEPTFZPSJOMQDSSKBAHRIVYHQJFVUQJH"
"HRAQYZLYTOAWWIIPEUPQEBYSKTRETZEDWVALVPISUBTOWJZQLVRWKLLLMWEAZZIGMTRV"
"DXJHBFOTBFYSKQYJSNVKINMYRAMBFMBZUVHEEUWRRCMLAPOKKIODTFIIVTIPTBMVMZIP"
"HKDIQRFOKYTVDLAPPUMYNZBJMZMDDQDTXZWOMAJSJETWLGSAJDNNCODMAMCGADNXJGPP"
"GMPQXTZYICNPVATOCYCCGVSAKGCSGCPVUFGNGJPCRVZQXIDIZYCEBNMLMYHUMJZNHGCZ"
"TIYTNXTCGMGSBGLIDHYABMLEBGAHLOEYVOAMROXQAFDNEIZAOFWDETNEZWJFHTYOEVDH"
"RZDIZNSNBDCERUYZRLFWAANFAETBEWWPNNMUYXVBVDKMWPJUZLEPXOJAZOAYNKZDTBJO"
"MKXEMIAGHIQIHXPZGWDEQJKBNTDIWPLDANSOQJTGVPPSROOXGEBBWKLXMUEKZBKTTQTN"
"HILWSXGGYZZFYPGDVMNGLGGBSZJYWXGVHAACMVKQLPYXWWJMOQJJCXQOUIRCXPYCITBW"
"WCOKSSDXXWHHSOPANMWVIKJFLYNBPQAUHWKZEQBDVWDDULWFVBXUBJVOMHNAELALFGZT"
"FHSVLXJTMSOAKGBXKHKDEKVVFRZPKLTRRKCREVPXQYEVGIHAUNEJDLWERMKWJJBONLPW"
"BNTDWFILGFYOOAPNXVBDGGYDCZWUSJLPLZRVYAVSQFEXRZACHLLGGDEJGURDPYFCQUCX"
"OTNJJUJMMBEYSKJPKBGMQAAWOSPYAWDPJEQRLDJVZMRCYSKBAOQYWTJXSRRRMSFGNFRX"
"VEWFGPXVPZQXGRGOLKIYCCAOAGCZSHGPEGVMWETUWVZXZKCJVGQNEJBICWINFFHIUSUE"
"SVKYPVAOKBQEMQNKAXHFDETVNNFPQAXQXFJSKJCFLAHNRQUQPXYELGDYJDEETNEYGTMQ"
"MYIGQUDGOUMZDQORHNVDXBCJYBFTCDEMATBUCGAEKONTAIRCOHHKJFORZVDQSOWKDLKU"
"UOTTLLKQHVKVYOLJWNRRWXEOJMDZIKPMZFBBJCQSVTMCFFZDCWLRQDKAOKEXFVDZCPHE"
"UGNBVSILDBRPBJKNZXIWTNOZEDDESKOGYFOWPZJBQIQXKQERGWTJCUXGTOHLAOWDLGPF"
"RHVNLXVTKDDCWWZUAXKJZKPMOZCZCYVOIRCJNIJAMFRPAWNKFYAGKHNEPKPFTTRXXGTN"
"XFHFJXQWMKDSODYMNWJIFQZJOCYHUKYNYKXSLJNMBKCUXETKQTSZAXZUEERRGNBFDXJW"
"IKSVAVDNXLHJXVNDGLFZNZYTMJPDDXCOPGEROKJOGHXLDZJTSWOXIVCJKLYYTKANVFIF"
"KRVVEXSZXREAOBPVQRZUQKIWNMPTFUWARTQJCDTPEOVDHTDCWAWTTMNLRTOPYGPBROQA"
"QSMTGDCATMYQDJZQAUBQPOZLXDIJCKEVXDTPDNCHNJXMHNRVLWLKSAUYTHVOIYAAHUCY"
"XUWPHXMFXBDNBSNZIVKZANBYCHTUDOLHVVXGFDRDOIRCCRTZRNPWFTHSQRYTLGETDTGZ"
"KQWQPZYUTFFVFRQCAJAFDJAUMHPRXGUTLMFKOGXQHGOACGELSACTSNJTSOGNJAODFCIB"
"EQGGZETTRWOLAPRYJIGCYSUIMDCRHRGBKJFPDXVGPSPGDMBOLAVARRJSNDMZIOPKTAMA"
"NRZOSWGMPBPDBPCUADFMIEWOEBNNDFHUJCFMWXAFDKSWUTMMSQZSFBOGSSKOITDUGLLA"
"NFCZSGCDFDWUDTBPFKMHROQMIQRLCNGGCSFTNCVXSJJGPUZQREUASWLVOFVHRZPQUYGE"
"TBCJUSBKOJVBDWDEGXWBJPFTBFEALLVFFREQSGIONNYQFBFNKENZKSWLEWGEJJPZLRPV"
"RLDHLELHFXXIEXDJOSAUGITKSWYCPMEBLWOLAEJXXARMXQCBEFKLOOIYRBYVWLNZKNCA"
"ISOZEWVWPUDRGLYYKWWTNCWPZLYYDBKARCATEJHLYYQFNYATGYJIUNMVLEGUYBJVEVVM"
"WBVJYQEGPZUOJYLWNEMODVPHTWTLURFETDHELDHPGEQWLRKZRFCEORRGYSBIJHPVNSNZ"
"CAVXFCESMJIXGJPGLKDREKYGBPQSACESXAAHVQYFBSYWDPHDNTOZTEGSCISTBUMLDOQP"
"WNQCSJUAENKYFCYIYENHTIAARBRTOCYDVMHPCPRGWQVDIFLHWMZWRGCWQTAIKCAJAMLG"
"OKGURQTGNNUSCBKTPUXIGKDUWUGMTLCAOTKMXVTAEYWNWBTIQMLVDIEVBAGJMCWMMGZI"
"USESSUIHYSYOXHFLNZVTCVATIUVWGDETJUEHTVQBJDGHIIDFYHTFDIDPLNGXLIBMKAYG"
"DOZLOFKQXVWSQPRYUKAMGEICLKOMYNLWEMKLWDOPEEZGTXVDQWMULORFGNLKNVVCGQXQ"
"CUIYKIAMJSJVQJKRBNBIEELCZLMPQILCEBLZZTKCPBOQLTMZRGTNWHPIUYWMBCNGIABH"
"WIAILEDQVNWKJGYWMZYWOZGRHQOUFGCAETYUTLYZBCHKANZYPXTLMVREDIWBPAISSWKP"
"IJIBRLWPFXQOLOFIXLUGDVMXNPJWBMMZYJUKUZPPTGVCRIMITUTPYLJOIDQGOMYUFSJB"
"MRAZFVZSFZUSNJYDWBUDMFTFDBRCZCZZERWZSOXVAZISSEOMPKHESJRLUMZBBLBIXPZR"
"UYRFMLZQMMZWMNXULVXZQPOUKPMXISKOPTEDXASVPAIENMUWMBNGIVWVOQQXKGYEAMAT"
"YLDPYAASJSACUYILVJBXLHEMYKRKXEIVCDWKPQUBHACBNBGVTQLFDFPLAGUWUPBNBSIT"
"UEENOTZFWDWNNYZTHJIBDYMCERWQNSDKDDUPPXPJTGDYQTFNSRQZZSZBYGSQHRRGSVAQ"
"QEICLCSLMWQYXGGJEPJWZXKJUCFHJRACHRHLCRQWKXSUFJNBOMGWAIBKNWUDBJTFWVBW"
"UPIUAKBMXXDVVKBEUAEHMOELYCJVEFJEDFBTITDNTEGRAIOACOHFCVERCTRMUZHPRNPQ"
"YCFDKGTRGWFEJAXVTTBMIAYLJZEJAAEOBCTIXHYNDWPXIWOVGXSOLTXIBPBLHYKHIDGX"
"HHXNVRCMUXBZGFIEDZDBZOKSMKRNYTWJGJBIMQIOZQRFROWMLNYPDDKTRESDVHHJNRMN"
"GASH";
int main(void)
{
const char *s = "Hello, world!";
return strlen(s);
}

12
runlevel/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
file(GLOB runlevels *.runlevel)
foreach (f ${runlevels})
get_filename_component(name ${f} NAME_WLE)
bsp_add_file(
ID runlevel-${name}
SRC_PATH ${f}
DEST_DIR /etc/herdd/runlevels)
sysroot_add_file(
ID runlevel-${name}
SRC_PATH ${f}
DEST_DIR /etc/herdd/runlevels)
endforeach (f)

View File

@@ -0,0 +1,3 @@
[Runlevel]
Description=Minimal
Requires=nsd

View File

View File

@@ -0,0 +1,10 @@
file(GLOB sources *.c)
add_executable(herdd ${sources})
target_link_libraries(herdd libc libc-runtime libmango libpthread)
sysroot_add_program(
NAME herdd
BIN_DIR /usr/bin)
bsp_add_program(
NAME herdd
BIN_DIR /usr/bin)

67
services/herdd/main.c Normal file
View File

@@ -0,0 +1,67 @@
#include <errno.h>
#include <mango/log.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/remote.h>
#include <sys/types.h>
#include <unistd.h>
static void *thread_func(void *arg)
{
kern_logf("started thread with arg %p", arg);
errno = 100;
return (void *)0xdeadbeef;
}
int main(int argc, const char *argv[], const char *envp[])
{
sys_remote_set(SYS_REMOTE_NSD, 0, 0);
kern_logf("herdd");
kern_logf("args:");
for (int i = 0; i < argc; i++) {
kern_logf("[%d]: %s", i, argv[i]);
}
kern_logf("env:");
for (int i = 0; envp[i]; i++) {
kern_logf("[%d]: %s", i, envp[i]);
}
kern_logf("self = %p", pthread_self());
errno = 200;
#if 1
int dir = open("/", 0);
if (dir >= 0) {
kern_logf("opened '/'");
char buf[4096] = {0};
struct dentry *dent = (struct dentry *)buf;
long len = getdents(dir, dent, sizeof buf);
if (len < 0) {
kern_logf("getdents failed (%s)", strerror(errno));
} else {
for (long i = 0; i < len;) {
dent = (struct dentry *)(buf + i);
kern_logf(" - %s", dent->d_name);
i += dent->d_reclen;
}
}
close(dir);
} else {
kern_logf("open() failed: %s", strerror(errno));
}
#endif
pthread_t thread;
pthread_create(&thread, NULL, thread_func, (void *)0xdeafcafe);
kern_logf("started thread %p", thread);
void *ret = NULL;
pthread_join(thread, &ret);
kern_logf("thread returned %p", ret);
return 0;
}

View File

14
services/herdd/runlevel.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef RUNLEVEL_H_
#define RUNLEVEL_H_
#include <stddef.h>
#define RUNLEVEL_DESCRIPTION_MAX 64
struct runlevel {
char rl_description[RUNLEVEL_DESCRIPTION_MAX];
char **rl_requires;
size_t rl_requires_count;
};
#endif

0
services/herdd/service.c Normal file
View File

17
services/herdd/service.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef SERVICE_H_
#define SERVICE_H_
#define SVC_DESCRIPTION_MAX 64
enum service_role {
SVC_ROLE_NONE = 0x00u,
SVC_ROLE_NAMESPACE_PROVIDER = 0x01u,
};
struct service {
char s_description[SVC_DESCRIPTION_MAX];
enum service_role s_roles;
char *s_exec;
};
#endif

View File

@@ -1,10 +0,0 @@
file(GLOB sources *.c)
add_executable(ldd ${sources})
target_link_libraries(ldd libc-core libc-runtime libmango)
sysroot_add_program(
NAME ldd
BIN_DIR /usr/bin)
bsp_add_program(
NAME ldd
BIN_DIR /usr/bin)

View File

@@ -1,4 +0,0 @@
int main(void)
{
return 0;
}

View File

@@ -0,0 +1,15 @@
file(GLOB sources *.c)
rosetta_add_service(
NAME nsd
SOURCES ${sources}
CFG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/nsd.service)
target_link_libraries(nsd libc libc-runtime)
sysroot_add_service(
NAME nsd
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)
bsp_add_service(
NAME nsd
BIN_DIR /usr/bin
SVC_DIR /etc/herdd/services)

6
services/nsd/nsd.service Normal file
View File

@@ -0,0 +1,6 @@
[Unit]
Description=Namespace Service
[Service]
Exec=/usr/bin/nsd
Role=NamespaceProvider

View File

@@ -1,16 +1,19 @@
file(GLOB c_sources *.c *.h) file(GLOB c_sources *.c *.h)
file(GLOB arch_sources arch/${CMAKE_SYSTEM_PROCESSOR}/*.S) file(GLOB arch_sources arch/${CMAKE_SYSTEM_PROCESSOR}/*.S)
set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C)
add_executable(bootstrap ${c_sources} ${arch_sources}) add_executable(bootstrap ${c_sources} ${arch_sources})
target_link_libraries(bootstrap target_link_libraries(bootstrap
libmango libc-core libc-malloc libfs-static liblaunch libxpc-static libmango librosetta
libc-core libc-malloc libc-pthread
libfs-static
liblaunch
libxpc-static
interface::fs) interface::fs)
target_compile_options(bootstrap PRIVATE target_compile_options(bootstrap PRIVATE
-fno-stack-protector -nostdlib -ffreestanding) -fno-stack-protector -nostdlib -ffreestanding -fno-PIC)
target_link_options(bootstrap PRIVATE target_link_options(bootstrap PRIVATE
-static -nostdlib -ffreestanding) -static -nostdlib -ffreestanding)
#-T ${CMAKE_CURRENT_SOURCE_DIR}/arch/${TARGET_ARCH}/layout.ld)
set_target_properties(bootstrap PROPERTIES POSITIION_INDEPENDENT_CODE FALSE)

View File

@@ -7,16 +7,18 @@
#include <fs/context.h> #include <fs/context.h>
#include <heap/heap.h> #include <heap/heap.h>
#include <launch.h> #include <launch.h>
#include <mango/handle.h>
#include <mango/log.h> #include <mango/log.h>
#include <mango/msg.h> #include <mango/msg.h>
#include <mango/task.h> #include <mango/task.h>
#include <mango/types.h> #include <mango/types.h>
#include <pthread.h>
#include <rosetta/bootstrap.h> #include <rosetta/bootstrap.h>
#include <rosetta/fs.h> #include <rosetta/fs.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#define INIT_PATH "/usr/bin/test" #define INIT_PATH "/usr/bin/herdd"
static enum launch_status resolve_dependency( static enum launch_status resolve_dependency(
struct launch_ctx *ctx, struct launch_ctx *ctx,
@@ -29,14 +31,12 @@ static enum launch_status resolve_dependency(
name++; name++;
} }
snprintf(s, sizeof s, "searching for library %s", name); kern_tracef("searching for library %s", name);
kern_log(s);
struct tar *fs = arg; struct tar *fs = arg;
struct tar_file file = {0}; struct tar_file file = {0};
if (tar_open(fs, name, &file) != 0) { if (tar_open(fs, name, &file) != 0) {
snprintf(s, sizeof s, "cannot find library %s", name); kern_tracef("cannot find library %s", name);
kern_log(s);
return LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY; return LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY;
} }
@@ -142,7 +142,8 @@ int main(
}; };
struct launch_parameters params = { struct launch_parameters params = {
.p_executable = image, .p_exec_image = image,
.p_exec_path = INIT_PATH,
.p_parent_task = task, .p_parent_task = task,
.p_task_name = "init", .p_task_name = "init",
.p_local_address_space = address_space, .p_local_address_space = address_space,
@@ -169,6 +170,10 @@ int main(
return -1; return -1;
} }
kern_handle_close(result.r_task);
kern_handle_close(result.r_thread);
kern_handle_close(result.r_address_space);
heap_t heap = HEAP_INIT; heap_t heap = HEAP_INIT;
struct fs_allocator fs_allocator = { struct fs_allocator fs_allocator = {
@@ -192,37 +197,12 @@ int main(
(void *)bsp_base, (void *)bsp_base,
0); 0);
if (fs_status != FS_SUCCESS) { if (fs_status != FS_SUCCESS) {
kern_logf("cannot mount filesustem (%d)", fs_status); kern_logf("cannot mount filesystem (%d)", fs_status);
return -1; return -1;
} }
while (1) { while (1) {
fs_context_handle_request(fs); fs_context_handle_request(fs);
#if 0
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;
}
#endif
} }
return 0; return 0;

View File

@@ -11,6 +11,7 @@
#include <mango/vm.h> #include <mango/vm.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#include <xpc/buffer.h> #include <xpc/buffer.h>
struct tar_superblock { struct tar_superblock {
@@ -148,6 +149,24 @@ static struct tar_entry *entry_get_child(
return NULL; return NULL;
} }
static struct tar_entry *entry_get_child_at(struct tar_entry *entry, size_t at)
{
struct queue_entry *cur = queue_first(&entry->e_children);
while (cur) {
struct tar_entry *child
= QUEUE_CONTAINER(struct tar_entry, e_entry, cur);
if (at == 0) {
return child;
}
at--;
cur = queue_next(cur);
}
return NULL;
}
static const struct fs_dentry_ops dentry_ops = {}; static const struct fs_dentry_ops dentry_ops = {};
static enum fs_status dir_lookup( static enum fs_status dir_lookup(
@@ -189,18 +208,74 @@ static enum fs_status file_read(
char *src = (char *)entry->e_data + offset; char *src = (char *)entry->e_data + offset;
size_t w; size_t w;
xpc_buffer_write(buf, src, count, &w); xpc_buffer_write(buf, 0, src, count, &w);
offset += count; offset += w;
*seek = offset; *seek = offset;
return FS_SUCCESS; return FS_SUCCESS;
} }
static enum fs_status dir_readdir(
struct fs_file *f,
xpc_buffer_t *out,
off_t *seek)
{
off_t offset = *seek;
struct tar_entry *entry = entry_from_inode(fs_file_get_inode(f));
if (!entry) {
return FS_ERR_BAD_STATE;
}
size_t bytes_written = 0;
size_t available = xpc_buffer_capacity(out);
while (1) {
struct tar_entry *child = entry_get_child_at(entry, offset);
if (!child) {
break;
}
struct dentry dent = {0};
size_t name_len = strlen(child->e_dentry.d_name);
size_t to_write
= offsetof(struct dentry, d_name) + name_len + 1;
if (to_write > available) {
break;
}
dent.d_reclen = to_write;
kern_iovec_t iov[] = {
IOVEC(&dent, offsetof(struct dentry, d_name)),
IOVEC(child->e_dentry.d_name, name_len + 1),
};
size_t tmp = 0;
kern_status_t status
= xpc_buffer_writev(out, bytes_written, iov, 2, &tmp);
if (status != KERN_OK) {
break;
}
bytes_written += tmp;
available -= tmp;
offset++;
}
*seek = offset;
out->buf_len = bytes_written;
return FS_SUCCESS;
}
static const struct fs_file_ops file_ops = { static const struct fs_file_ops file_ops = {
.f_read = file_read, .f_read = file_read,
}; };
static const struct fs_file_ops dir_ops = {
.f_readdir = dir_readdir,
};
static const struct fs_inode_ops file_inode_ops = { static const struct fs_inode_ops file_inode_ops = {
.i_lookup = NULL, .i_lookup = NULL,
}; };
@@ -224,6 +299,7 @@ static struct tar_entry *create_dir_entry(
entry->e_inode.i_sb = &sb->sb_base; entry->e_inode.i_sb = &sb->sb_base;
entry->e_inode.i_mode = FS_INODE_DIR; entry->e_inode.i_mode = FS_INODE_DIR;
entry->e_inode.i_ops = &dir_inode_ops; entry->e_inode.i_ops = &dir_inode_ops;
entry->e_inode.i_fops = &dir_ops;
entry->e_dentry.d_sb = &sb->sb_base; entry->e_dentry.d_sb = &sb->sb_base;
entry->e_dentry.d_ops = &dentry_ops; entry->e_dentry.d_ops = &dentry_ops;

View File

@@ -1,8 +1,6 @@
file(GLOB c_sources *.c *.h) file(GLOB c_sources *.c *.h)
file(GLOB arch_sources arch/${CMAKE_SYSTEM_PROCESSOR}/*.S) file(GLOB arch_sources arch/${CMAKE_SYSTEM_PROCESSOR}/*.S)
set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C)
add_executable(ld ${c_sources} ${arch_sources}) add_executable(ld ${c_sources} ${arch_sources})
set_target_properties(ld PROPERTIES set_target_properties(ld PROPERTIES
POSITION_INDEPENDENT_CODE ON POSITION_INDEPENDENT_CODE ON

View File

@@ -0,0 +1,43 @@
.code64
.global _dl_runtime_resolve
.type _dl_runtime_resolve, @function
.extern dl_runtime_resolve
.type dl_runtime_resolve, @function
_dl_runtime_resolve:
// pop %rdi
// pop %rsi
pop %rax
pop %r11
push %rdi
push %rsi
push %rdx
push %rcx
push %r8
push %r9
push %rbx
push %r12
push %r13
push %r14
push %r15
mov %rax, %rdi
mov %r11, %rsi
call dl_runtime_resolve
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
jmp *%rax

691
sys/ld/btree.c Normal file
View File

@@ -0,0 +1,691 @@
/*
The Clear BSD License
Copyright (c) 2023 Max Wash
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
*/
/* templated AVL binary tree implementation
this file implements an extensible AVL binary tree data structure.
the primary rule of an AVL binary tree is that for a given node N,
the heights of N's left and right subtrees can differ by at most 1.
the height of a subtree is the length of the longest path between
the root of the subtree and a leaf node, including the root node itself.
the height of a leaf node is 1.
when a node is inserted into or deleted from the tree, this rule may
be broken, in which the tree must be rotated to restore the balance.
no more than one rotation is required for any insert operations,
while multiple rotations may be required for a delete operation.
there are four types of rotations that can be applied to a tree:
- left rotation
- right rotation
- double left rotations
- double right rotations
by enforcing the balance rule, for a tree with n nodes, the worst-case
performance for insert, delete, and search operations is guaranteed
to be O(log n).
this file intentionally excludes any kind of search function implementation.
it is up to the programmer to implement their own tree node type
using struct btree_node, and their own search function using struct btree.
this allows the programmer to define their own node types with complex
non-integer key types. btree.h contains a number of macros to help
define these functions. the macros do all the work, you just have to
provide a comparator function.
*/
#include "btree.h"
#include <stddef.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define IS_LEFT_CHILD(p, c) ((p) && (c) && ((p)->b_left == (c)))
#define IS_RIGHT_CHILD(p, c) ((p) && (c) && ((p)->b_right == (c)))
#define HAS_LEFT_CHILD(x) ((x) && ((x)->b_left))
#define HAS_RIGHT_CHILD(x) ((x) && ((x)->b_right))
#define HAS_NO_CHILDREN(x) ((x) && (!(x)->b_left) && (!(x)->b_right))
#define HAS_ONE_CHILD(x) \
((HAS_LEFT_CHILD(x) && !HAS_RIGHT_CHILD(x)) \
|| (!HAS_LEFT_CHILD(x) && HAS_RIGHT_CHILD(x)))
#define HAS_TWO_CHILDREN(x) (HAS_LEFT_CHILD(x) && HAS_RIGHT_CHILD(x))
#define HEIGHT(x) ((x) ? (x)->b_height : 0)
static inline void update_height(struct btree_node *x)
{
x->b_height = MAX(HEIGHT(x->b_left), HEIGHT((x->b_right))) + 1;
}
static inline int bf(struct btree_node *x)
{
int bf = 0;
if (!x) {
return bf;
}
if (x->b_right) {
bf += x->b_right->b_height;
}
if (x->b_left) {
bf -= x->b_left->b_height;
}
return bf;
}
/* perform a left rotation on a subtree
if you have a tree like this:
Z
/ \
X .
/ \
. Y
/ \
. .
and you perform a left rotation on node X,
you will get the following tree:
Z
/ \
Y .
/ \
X .
/ \
. .
note that this function does NOT update b_height for the rotated
nodes. it is up to you to call update_height_to_root().
*/
static void rotate_left(struct btree *tree, struct btree_node *x)
{
struct btree_node *y = x->b_right;
struct btree_node *p = x->b_parent;
if (y->b_left) {
y->b_left->b_parent = x;
}
x->b_right = y->b_left;
if (!p) {
tree->b_root = y;
} else if (x == p->b_left) {
p->b_left = y;
} else {
p->b_right = y;
}
x->b_parent = y;
y->b_left = x;
y->b_parent = p;
}
static void update_height_to_root(struct btree_node *x)
{
while (x) {
update_height(x);
x = x->b_parent;
}
}
/* perform a right rotation on a subtree
if you have a tree like this:
Z
/ \
. X
/ \
Y .
/ \
. .
and you perform a right rotation on node X,
you will get the following tree:
Z
/ \
. Y
/ \
. X
/ \
. .
note that this function does NOT update b_height for the rotated
nodes. it is up to you to call update_height_to_root().
*/
static void rotate_right(struct btree *tree, struct btree_node *y)
{
struct btree_node *x = y->b_left;
struct btree_node *p = y->b_parent;
if (x->b_right) {
x->b_right->b_parent = y;
}
y->b_left = x->b_right;
if (!p) {
tree->b_root = x;
} else if (y == p->b_left) {
p->b_left = x;
} else {
p->b_right = x;
}
y->b_parent = x;
x->b_right = y;
x->b_parent = p;
}
/* for a given node Z, perform a right rotation on Z's right child,
followed by a left rotation on Z itself.
if you have a tree like this:
Z
/ \
. X
/ \
Y .
/ \
. .
and you perform a double-left rotation on node Z,
you will get the following tree:
Y
/ \
/ \
Z X
/ \ / \
. . . .
note that, unlike rotate_left and rotate_right, this function
DOES update b_height for the rotated nodes (since it needs to be
done in a certain order).
*/
static void rotate_double_left(struct btree *tree, struct btree_node *z)
{
struct btree_node *x = z->b_right;
struct btree_node *y = x->b_left;
rotate_right(tree, x);
rotate_left(tree, z);
update_height(z);
update_height(x);
while (y) {
update_height(y);
y = y->b_parent;
}
}
/* for a given node Z, perform a left rotation on Z's left child,
followed by a right rotation on Z itself.
if you have a tree like this:
Z
/ \
X .
/ \
. Y
/ \
. .
and you perform a double-right rotation on node Z,
you will get the following tree:
Y
/ \
/ \
X Z
/ \ / \
. . . .
note that, unlike rotate_left and rotate_right, this function
DOES update b_height for the rotated nodes (since it needs to be
done in a certain order).
*/
static void rotate_double_right(struct btree *tree, struct btree_node *z)
{
struct btree_node *x = z->b_left;
struct btree_node *y = x->b_right;
rotate_left(tree, x);
rotate_right(tree, z);
update_height(z);
update_height(x);
while (y) {
update_height(y);
y = y->b_parent;
}
}
/* run after an insert operation. checks that the balance factor
of the local subtree is within the range -1 <= BF <= 1. if it
is not, rotate the subtree to restore balance.
note that at most one rotation should be required after a node
is inserted into the tree.
this function depends on all nodes in the tree having
correct b_height values.
@param w the node that was just inserted into the tree
*/
static void insert_fixup(struct btree *tree, struct btree_node *w)
{
struct btree_node *z = NULL, *y = NULL, *x = NULL;
z = w;
while (z) {
if (bf(z) >= -1 && bf(z) <= 1) {
goto next_ancestor;
}
if (IS_LEFT_CHILD(z, y)) {
if (IS_LEFT_CHILD(y, x)) {
rotate_right(tree, z);
update_height_to_root(z);
} else {
rotate_double_right(tree, z);
}
} else {
if (IS_LEFT_CHILD(y, x)) {
rotate_double_left(tree, z);
} else {
rotate_left(tree, z);
update_height_to_root(z);
}
}
next_ancestor:
x = y;
y = z;
z = z->b_parent;
}
}
/* run after a delete operation. checks that the balance factor
of the local subtree is within the range -1 <= BF <= 1. if it
is not, rotate the subtree to restore balance.
note that, unlike insert_fixup, multiple rotations may be required
to restore balance after a node is deleted.
this function depends on all nodes in the tree having
correct b_height values.
@param w one of the following:
- the parent of the node that was deleted if the node
had no children.
- the parent of the node that replaced the deleted node
if the deleted node had two children.
- the node that replaced the node that was deleted, if
the node that was deleted had one child.
*/
static void delete_fixup(struct btree *tree, struct btree_node *w)
{
struct btree_node *z = w;
while (z) {
if (bf(z) > 1) {
if (bf(z->b_right) >= 0) {
rotate_left(tree, z);
update_height_to_root(z);
} else {
rotate_double_left(tree, z);
}
} else if (bf(z) < -1) {
if (bf(z->b_left) <= 0) {
rotate_right(tree, z);
update_height_to_root(z);
} else {
rotate_double_right(tree, z);
}
}
z = z->b_parent;
}
}
/* updates b_height for all nodes between the inserted node and the root
of the tree, and calls insert_fixup.
@param node the node that was just inserted into the tree.
*/
void btree_insert_fixup(struct btree *tree, struct btree_node *node)
{
node->b_height = 0;
struct btree_node *cur = node;
while (cur) {
update_height(cur);
cur = cur->b_parent;
}
insert_fixup(tree, node);
}
/* remove a node from a tree.
this function assumes that `node` has no children, and therefore
doesn't need to be replaced.
updates b_height for all nodes between `node` and the tree root.
@param node the node to delete.
*/
static struct btree_node *remove_node_with_no_children(
struct btree *tree,
struct btree_node *node)
{
struct btree_node *w = node->b_parent;
struct btree_node *p = node->b_parent;
node->b_parent = NULL;
if (!p) {
tree->b_root = NULL;
} else if (IS_LEFT_CHILD(p, node)) {
p->b_left = NULL;
} else {
p->b_right = NULL;
}
while (p) {
update_height(p);
p = p->b_parent;
}
return w;
}
/* remove a node from a tree.
this function assumes that `node` has one child.
the child of `node` is inherited by `node`'s parent, and `node` is removed.
updates b_height for all nodes between the node that replaced
`node` and the tree root.
@param node the node to delete.
*/
static struct btree_node *replace_node_with_one_subtree(
struct btree *tree,
struct btree_node *node)
{
struct btree_node *p = node->b_parent;
struct btree_node *z = NULL;
if (HAS_LEFT_CHILD(node)) {
z = node->b_left;
} else {
z = node->b_right;
}
struct btree_node *w = z;
if (!p) {
tree->b_root = z;
} else if (IS_LEFT_CHILD(p, node)) {
p->b_left = z;
} else if (IS_RIGHT_CHILD(p, node)) {
p->b_right = z;
}
z->b_parent = p;
node->b_parent = NULL;
node->b_left = node->b_right = NULL;
while (z) {
update_height(z);
z = z->b_parent;
}
return w;
}
/* remove a node from a tree.
this function assumes that `node` has two children.
find the in-order successor Y of `node` (the largest node in `node`'s left
sub-tree), removes `node` from the tree and moves Y to where `node` used to
be.
if Y has a child (it will never have more than one), have Y's parent inherit
Y's child.
updates b_height for all nodes between the deepest node that was modified
and the tree root.
@param z the node to delete.
*/
static struct btree_node *replace_node_with_two_subtrees(
struct btree *tree,
struct btree_node *z)
{
/* x will replace z */
struct btree_node *x = z->b_left;
while (x->b_right) {
x = x->b_right;
}
/* y is the node that will replace x (if x has a left child) */
struct btree_node *y = x->b_left;
/* w is the starting point for the height update and fixup */
struct btree_node *w = x;
if (w->b_parent != z) {
w = w->b_parent;
}
if (y) {
w = y;
}
if (IS_LEFT_CHILD(x->b_parent, x)) {
x->b_parent->b_left = y;
} else if (IS_RIGHT_CHILD(x->b_parent, x)) {
x->b_parent->b_right = y;
}
if (y) {
y->b_parent = x->b_parent;
}
if (IS_LEFT_CHILD(z->b_parent, z)) {
z->b_parent->b_left = x;
} else if (IS_RIGHT_CHILD(z->b_parent, z)) {
z->b_parent->b_right = x;
}
x->b_parent = z->b_parent;
x->b_left = z->b_left;
x->b_right = z->b_right;
if (x->b_left) {
x->b_left->b_parent = x;
}
if (x->b_right) {
x->b_right->b_parent = x;
}
if (!x->b_parent) {
tree->b_root = x;
}
struct btree_node *cur = w;
while (cur) {
update_height(cur);
cur = cur->b_parent;
}
return w;
}
/* delete a node from the tree and re-balance it afterwards */
void btree_delete(struct btree *tree, struct btree_node *node)
{
struct btree_node *w = NULL;
if (HAS_NO_CHILDREN(node)) {
w = remove_node_with_no_children(tree, node);
} else if (HAS_ONE_CHILD(node)) {
w = replace_node_with_one_subtree(tree, node);
} else if (HAS_TWO_CHILDREN(node)) {
w = replace_node_with_two_subtrees(tree, node);
}
if (w) {
delete_fixup(tree, w);
}
node->b_left = node->b_right = node->b_parent = NULL;
}
struct btree_node *btree_first(struct btree *tree)
{
/* the first node in the tree is the node with the smallest key.
we keep moving left until we can't go any further */
struct btree_node *cur = tree->b_root;
if (!cur) {
return NULL;
}
while (cur->b_left) {
cur = cur->b_left;
}
return cur;
}
struct btree_node *btree_last(struct btree *tree)
{
/* the first node in the tree is the node with the largest key.
we keep moving right until we can't go any further */
struct btree_node *cur = tree->b_root;
if (!cur) {
return NULL;
}
while (cur->b_right) {
cur = cur->b_right;
}
return cur;
}
struct btree_node *btree_next(struct btree_node *node)
{
if (!node) {
return NULL;
}
/* there are two possibilities for the next node:
1. if `node` has a right sub-tree, every node in this sub-tree is
bigger than node. the in-order successor of `node` is the smallest
node in this subtree.
2. if `node` has no right sub-tree, we've reached the largest node in
the sub-tree rooted at `node`. we need to go back to our parent
and continue the search elsewhere.
*/
if (node->b_right) {
/* case 1: step into `node`'s right sub-tree and keep going
left to find the smallest node */
struct btree_node *cur = node->b_right;
while (cur->b_left) {
cur = cur->b_left;
}
return cur;
}
/* case 2: keep stepping back up towards the root of the tree.
if we encounter a step where we are our parent's left child,
we've found a parent with a value larger than us. this parent
is the in-order successor of `node` */
while (node->b_parent && node->b_parent->b_left != node) {
node = node->b_parent;
}
return node->b_parent;
}
struct btree_node *btree_prev(struct btree_node *node)
{
if (!node) {
return NULL;
}
/* there are two possibilities for the previous node:
1. if `node` has a left sub-tree, every node in this sub-tree is
smaller than `node`. the in-order predecessor of `node` is the
largest node in this subtree.
2. if `node` has no left sub-tree, we've reached the smallest node in
the sub-tree rooted at `node`. we need to go back to our parent
and continue the search elsewhere.
*/
if (node->b_left) {
/* case 1: step into `node`'s left sub-tree and keep going
right to find the largest node */
struct btree_node *cur = node->b_left;
while (cur->b_right) {
cur = cur->b_right;
}
return cur;
}
/* case 2: keep stepping back up towards the root of the tree.
if we encounter a step where we are our parent's right child,
we've found a parent with a value smaller than us. this parent
is the in-order predecessor of `node`. */
while (node->b_parent && node->b_parent->b_right != node) {
node = node->b_parent;
}
return node->b_parent;
}

475
sys/ld/btree.h Normal file
View File

@@ -0,0 +1,475 @@
/*
The Clear BSD License
Copyright (c) 2023 Max Wash
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
*/
#ifndef BTREE_H_
#define BTREE_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* if your custom structure contains a struct btree_node (i.e. it can be part of
a btree), you can use this macro to convert a struct btree_node* to a
your_type*
@param t the name of your custom type (something that can be passed to
offsetof)
@param m the name of the struct btree_node member variable within your custom
type.
@param v the struct btree_node pointer that you wish to convert. if this is
NULL, NULL will be returned.
*/
#define BTREE_CONTAINER(t, m, v) \
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
/* defines a simple node insertion function.
this function assumes that your nodes have simple integer keys that can be
compared with the usual operators.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
int key;
struct btree_node base;
}
You would use the following call to generate an insert function for a tree
with this node type:
BTREE_DEFINE_SIMPLE_INSERT(struct my_tree_node, base, key,
my_tree_node_insert);
Which would emit a function defined like:
static void my_tree_node_insert(struct btree *tree, struct my_tree_node
*node);
@param node_type your custom tree node type. usually a structure that
contains a struct btree_node member.
@param container_node_member the name of the struct btree_node member
variable within your custom type.
@param container_key_member the name of the key member variable within your
custom type.
@param function_name the name of the function to generate.
*/
#define BTREE_DEFINE_SIMPLE_INSERT( \
node_type, \
container_node_member, \
container_key_member, \
function_name) \
void function_name(struct btree *tree, node_type *node) \
{ \
if (!tree->b_root) { \
tree->b_root = &node->container_node_member; \
btree_insert_fixup( \
tree, \
&node->container_node_member); \
return; \
} \
\
struct btree_node *cur = tree->b_root; \
while (1) { \
node_type *cur_node = BTREE_CONTAINER( \
node_type, \
container_node_member, \
cur); \
struct btree_node *next = NULL; \
\
if (node->container_key_member \
> cur_node->container_key_member) { \
next = btree_right(cur); \
\
if (!next) { \
btree_put_right( \
cur, \
&node->container_node_member); \
break; \
} \
} else if ( \
node->container_key_member \
< cur_node->container_key_member) { \
next = btree_left(cur); \
\
if (!next) { \
btree_put_left( \
cur, \
&node->container_node_member); \
break; \
} \
} else { \
return; \
} \
\
cur = next; \
} \
\
btree_insert_fixup(tree, &node->container_node_member); \
}
/* defines a node insertion function.
this function should be used for trees with complex node keys that cannot be
directly compared. a comparator for your keys must be supplied.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
complex_key_t key;
struct btree_node base;
}
You would need to define a comparator function or macro with the following
signature:
int my_comparator(struct my_tree_node *a, struct my_tree_node *b);
Which implements the following:
return -1 if a < b
return 0 if a == b
return 1 if a > b
You would use the following call to generate an insert function for a tree
with this node type:
BTREE_DEFINE_INSERT(struct my_tree_node, base, key, my_tree_node_insert,
my_comparator);
Which would emit a function defined like:
static void my_tree_node_insert(struct btree *tree, struct my_tree_node
*node);
@param node_type your custom tree node type. usually a structure that
contains a struct btree_node member.
@param container_node_member the name of the struct btree_node member
variable within your custom type.
@param container_key_member the name of the key member variable within your
custom type.
@param function_name the name of the function to generate.
@param comparator the name of a comparator function or functional-macro that
conforms to the requirements listed above.
*/
#define BTREE_DEFINE_INSERT( \
node_type, \
container_node_member, \
container_key_member, \
function_name, \
comparator) \
void function_name(struct btree *tree, node_type *node) \
{ \
if (!tree->b_root) { \
tree->b_root = &node->container_node_member; \
btree_insert_fixup( \
tree, \
&node->container_node_member); \
return; \
} \
\
struct btree_node *cur = tree->b_root; \
while (1) { \
node_type *cur_node = BTREE_CONTAINER( \
node_type, \
container_node_member, \
cur); \
struct btree_node *next = NULL; \
int cmp = comparator(node, cur_node); \
\
if (cmp == 1) { \
next = btree_right(cur); \
\
if (!next) { \
btree_put_right( \
cur, \
&node->container_node_member); \
break; \
} \
} else if (cmp == -1) { \
next = btree_left(cur); \
\
if (!next) { \
btree_put_left( \
cur, \
&node->container_node_member); \
break; \
} \
} else { \
return; \
} \
\
cur = next; \
} \
\
btree_insert_fixup(tree, &node->container_node_member); \
}
/* defines a simple tree search function.
this function assumes that your nodes have simple integer keys that can be
compared with the usual operators.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
int key;
struct btree_node base;
}
You would use the following call to generate a search function for a tree
with this node type:
BTREE_DEFINE_SIMPLE_GET(struct my_tree_node, int, base, key,
my_tree_node_get);
Which would emit a function defined like:
static struct my_tree_node *my_tree_node_get(struct btree *tree, int key);
@param node_type your custom tree node type. usually a structure that
contains a struct btree_node member.
@param key_type the type name of the key embedded in your custom tree node
type. this type must be compatible with the builtin comparison operators.
@param container_node_member the name of the struct btree_node member
variable within your custom type.
@param container_key_member the name of the key member variable within your
custom type.
@param function_name the name of the function to generate.
*/
#define BTREE_DEFINE_SIMPLE_GET( \
node_type, \
key_type, \
container_node_member, \
container_key_member, \
function_name) \
node_type *function_name(struct btree *tree, key_type key) \
{ \
struct btree_node *cur = tree->b_root; \
while (cur) { \
node_type *cur_node = BTREE_CONTAINER( \
node_type, \
container_node_member, \
cur); \
if (key > cur_node->container_key_member) { \
cur = btree_right(cur); \
} else if (key < cur_node->container_key_member) { \
cur = btree_left(cur); \
} else { \
return cur_node; \
} \
} \
\
return NULL; \
}
/* perform an in-order traversal of a binary tree
If you have a tree defined like:
struct btree my_tree;
with nodes defined like:
struct my_tree_node {
int key;
struct btree_node base;
}
and you want to do something like:
foreach (struct my_tree_node *node : my_tree) { ... }
you should use this:
btree_foreach (struct my_tree_node, node, &my_tree, base) { ... }
@param iter_type the type name of the iterator variable. this should be the
tree's node type, and shouldn't be a pointer.
@param iter_name the name of the iterator variable.
@param tree_name a pointer to the tree to traverse.
@param node_member the name of the struct btree_node member variable within
the tree node type.
*/
#define btree_foreach(iter_type, iter_name, tree_name, node_member) \
for (iter_type *iter_name = BTREE_CONTAINER( \
iter_type, \
node_member, \
btree_first(tree_name)); \
iter_name; \
iter_name = BTREE_CONTAINER( \
iter_type, \
node_member, \
btree_next(&((iter_name)->node_member))))
/* perform an reverse in-order traversal of a binary tree
If you have a tree defined like:
struct btree my_tree;
with nodes defined like:
struct my_tree_node {
int key;
struct btree_node base;
}
and you want to do something like:
foreach (struct my_tree_node *node : reverse(my_tree)) { ... }
you should use this:
btree_foreach_r (struct my_tree_node, node, &my_tree, base) { ... }
@param iter_type the type name of the iterator variable. this should be the
tree's node type, and shouldn't be a pointer.
@param iter_name the name of the iterator variable.
@param tree_name a pointer to the tree to traverse.
@param node_member the name of the struct btree_node member variable within
the tree node type.
*/
#define btree_foreach_r(iter_type, iter_name, tree_name, node_member) \
for (iter_type *iter_name \
= BTREE_CONTAINER(iter_type, node_member, btree_last(tree_name)); \
iter_name; \
iter_name = BTREE_CONTAINER( \
iter_type, \
node_member, \
btree_prev(&((iter_name)->node_member))))
/* binary tree nodes. this *cannot* be used directly. you need to define a
custom node type that contains a member variable of type struct btree_node.
you would then use the supplied macros to define functions to manipulate your
custom binary tree.
*/
struct btree_node {
struct btree_node *b_parent, *b_left, *b_right;
unsigned short b_height;
};
/* binary tree. unlike struct btree_node, you can define variables of type
* struct btree. */
struct btree {
struct btree_node *b_root;
};
/* re-balance a binary tree after an insertion operation.
NOTE that, if you define an insertion function using BTREE_DEFINE_INSERT or
similar, this function will automatically called for you.
@param tree the tree to re-balance.
@param node the node that was just inserted into the tree.
*/
extern void btree_insert_fixup(struct btree *tree, struct btree_node *node);
/* delete a node from a binary tree and re-balance the tree afterwards.
@param tree the tree to delete from
@param node the node to delete.
*/
extern void btree_delete(struct btree *tree, struct btree_node *node);
/* get the first node in a binary tree.
this will be the node with the smallest key (i.e. the node that is
furthest-left from the root)
*/
extern struct btree_node *btree_first(struct btree *tree);
/* get the last node in a binary tree.
this will be the node with the largest key (i.e. the node that is
furthest-right from the root)
*/
extern struct btree_node *btree_last(struct btree *tree);
/* for any binary tree node, this function returns the node with the
* next-largest key value */
extern struct btree_node *btree_next(struct btree_node *node);
/* for any binary tree node, this function returns the node with the
* next-smallest key value */
extern struct btree_node *btree_prev(struct btree_node *node);
static inline bool btree_empty(const struct btree *tree)
{
return tree->b_root == NULL;
}
/* sets `child` as the immediate left-child of `parent` */
static inline void btree_put_left(
struct btree_node *parent,
struct btree_node *child)
{
parent->b_left = child;
child->b_parent = parent;
}
/* sets `child` as the immediate right-child of `parent` */
static inline void btree_put_right(
struct btree_node *parent,
struct btree_node *child)
{
parent->b_right = child;
child->b_parent = parent;
}
/* get the immediate left-child of `node` */
static inline struct btree_node *btree_left(struct btree_node *node)
{
return node->b_left;
}
/* get the immediate right-child of `node` */
static inline struct btree_node *btree_right(struct btree_node *node)
{
return node->b_right;
}
/* get the immediate parent of `node` */
static inline struct btree_node *btree_parent(struct btree_node *node)
{
return node->b_parent;
}
/* get the height of `node`.
the height of a node is defined as the length of the longest path
between the node and a leaf node.
this count includes the node itself, so the height of a leaf node will be 1.
*/
static inline unsigned short btree_height(struct btree_node *node)
{
return node->b_height;
}
#ifdef __cplusplus
}
#endif
#endif

947
sys/ld/elf.c Normal file
View File

@@ -0,0 +1,947 @@
#include "elf.h"
#include "image-list.h"
#include "ld.h"
#include "resolve.h"
#include <errno.h>
#include <fcntl.h>
#include <mango/config.h>
#include <mango/handle.h>
#include <mango/log.h>
#include <mango/vm.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define NEEDS_NOTHING 0
#define NEEDS_VDSO 1
#define NEEDS_MORE 2
#define ACL (PF_R | PF_W | PF_X)
#define ACCESS(x) ((x) & ACL)
/* TODO in case we ever support ELF32 images */
#define elf_class_bits(x) (64)
#define PAGE_SIZE (image->e_page_size)
#define PAGE_MASK (image->e_page_size - 1)
#define PAGE_OFFSET(v) ((v) & (PAGE_SIZE - 1))
#define PAGE_ALIGN_DOWN(v) (v) &= ~(PAGE_SIZE - 1)
#define PAGE_ALIGN_UP(v) \
do { \
if ((v) & (PAGE_SIZE - 1)) { \
v &= ~(PAGE_SIZE - 1); \
v += PAGE_SIZE; \
} \
} while (0)
#undef DEBUG_LOG
const char *elf_image_status_to_string(enum elf_image_status status)
{
#define ENUM_STR(s) \
case s: \
return #s
switch (status) {
ENUM_STR(ELF_IMAGE_NONE);
ENUM_STR(ELF_IMAGE_OPEN);
ENUM_STR(ELF_IMAGE_PARSED);
ENUM_STR(ELF_IMAGE_LOADED);
ENUM_STR(ELF_IMAGE_LINKED);
default:
return "UNKNOWN";
}
#undef ENUM_STR
}
static bool elf_validate_ehdr(elf_ehdr_t *hdr)
{
if (hdr->e_ident[EI_MAG0] != ELF_MAG0) {
return false;
}
if (hdr->e_ident[EI_MAG1] != ELF_MAG1) {
return false;
}
if (hdr->e_ident[EI_MAG2] != ELF_MAG2) {
return false;
}
if (hdr->e_ident[EI_MAG3] != ELF_MAG3) {
return false;
}
if (hdr->e_ident[EI_CLASS] != ELFCLASS64) {
return false;
}
if (hdr->e_machine != EM_X86_64) {
return false;
}
if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
return false;
}
if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
return false;
}
return true;
}
static int map_image(struct elf_image *image)
{
elf_phdr_t phdr;
size_t r = 0;
size_t data_offset = 0;
for (size_t i = 0; i < image->e_hdr.e_phnum; i++) {
off_t phdr_offset
= image->e_hdr.e_phoff + (i * image->e_hdr.e_phentsize);
lseek(image->e_fd, phdr_offset, SEEK_SET);
int r = read(image->e_fd, &phdr, sizeof phdr);
if (r < 0) {
return -r;
}
if (r != sizeof phdr) {
return ENOEXEC;
}
if (phdr.p_type != PT_LOAD) {
continue;
}
int prot = 0;
size_t offset = phdr.p_offset & ~PAGE_MASK;
phdr.p_flags &PF_R && (prot |= PROT_READ);
phdr.p_flags &PF_W && (prot |= PROT_WRITE);
phdr.p_flags &PF_X && (prot |= PROT_EXEC);
virt_addr_t vaddr = phdr.p_vaddr;
virt_addr_t vlimit = phdr.p_vaddr + phdr.p_memsz;
if (vaddr & PAGE_MASK) {
vaddr &= ~PAGE_MASK;
}
if (vlimit & PAGE_MASK) {
vlimit &= ~PAGE_MASK;
vlimit += PAGE_SIZE;
}
if (image->e_hdr.e_type == ET_DYN) {
vaddr += image->e_base;
vlimit += image->e_base;
}
int fd = image->e_fd;
int flags = MAP_SHARED | MAP_EXECUTABLE | MAP_FIXED;
if (phdr.p_flags & PF_W) {
fd = -1;
flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
offset = 0;
}
void *p
= mmap((void *)vaddr,
vlimit - vaddr,
prot,
flags,
fd,
offset);
if (p == MAP_FAILED) {
return EIO;
}
kern_tracef(
"mapped PHDR %u [%zx-%zx] at %p",
i,
phdr.p_vaddr,
phdr.p_vaddr + phdr.p_memsz,
p);
if (phdr.p_flags & PF_W) {
lseek(image->e_fd, phdr.p_offset, SEEK_SET);
void *dst = (void *)image->e_base + phdr.p_vaddr;
r = read(image->e_fd, dst, phdr.p_filesz);
if (r < 0) {
return -r;
}
}
}
kern_logf("ld: image %s -> %zx", image->e_leaf.l_name, image->e_base);
return SUCCESS;
}
static int parse_phdr(struct elf_image *image)
{
elf_phdr_t phdr;
size_t r = 0;
image->e_length = 0;
image->e_data_length = 0;
off_t vaddr, vlimit;
for (size_t i = 0; i < image->e_hdr.e_phnum; i++) {
off_t phdr_offset
= image->e_hdr.e_phoff + (i * image->e_hdr.e_phentsize);
lseek(image->e_fd, phdr_offset, SEEK_SET);
int r = read(image->e_fd, &phdr, sizeof phdr);
if (r < 0) {
return -r;
}
if (r != sizeof phdr) {
return ENOEXEC;
}
vaddr = phdr.p_vaddr;
vlimit = phdr.p_vaddr + phdr.p_memsz;
if (vaddr & (PAGE_SIZE - 1)) {
vaddr &= ~(PAGE_SIZE - 1);
}
if (vlimit & (PAGE_SIZE - 1)) {
vlimit &= ~(PAGE_SIZE - 1);
vlimit += PAGE_SIZE;
}
switch (phdr.p_type) {
case PT_DYNAMIC:
image->e_dynamic = phdr;
break;
case PT_LOAD:
image->e_length = MAX(image->e_length, vlimit);
break;
#if 0
case PT_INTERP: {
size_t r = 0;
vm_object_read(
image->e_image,
image->e_interp,
phdr.p_offset,
MIN(sizeof image->e_interp - 1, phdr.p_filesz),
&r);
image->e_interp[r] = 0;
break;
}
#endif
default:
break;
}
if (phdr.p_flags & PF_W) {
image->e_data_length
= MAX(image->e_data_length, vlimit - vaddr);
}
}
return SUCCESS;
}
#if 1
static elf_sym_t *get_dynsym(struct elf_image *image, size_t index)
{
elf_sym_t *sym = (elf_sym_t *)(image->e_base + image->e_dynsym
+ (index * image->e_dynsym_entsize));
if (!sym->st_value) {
return NULL;
}
return sym;
}
static void resolve_symbol(unsigned int slot)
{
kern_tracef("request for symbol %u", slot);
}
static int do_rela(struct elf_image *image, elf_rela_t *rela, bool lazy)
{
kern_tracef(
"do_rela(%p, %d, %d, %d)",
image,
rela->r_info,
rela->r_addend,
rela->r_offset);
int type = ELF64_R_TYPE(rela->r_info);
elf_sym_t *sym = NULL;
switch (type) {
case R_X86_64_JUMP_SLOT:
*(uint64_t *)(image->e_base + rela->r_offset) += image->e_base;
kern_tracef(
"JUMP_SLOT: offset=%zx, symbol=%zu, addend=%zx",
rela->r_offset,
ELF64_R_SYM(rela->r_info),
rela->r_addend);
break;
case R_X86_64_RELATIVE:
*(uint64_t *)(image->e_base + rela->r_offset)
= image->e_base + rela->r_addend;
kern_tracef(
"RELATIVE: offset=%zx, addend=%zx",
rela->r_offset,
rela->r_addend);
break;
default:
kern_trace("Unknown relocation type");
return ENOEXEC;
}
return SUCCESS;
}
static int relocate_pltrel(
struct elf_image *image,
off_t offset,
size_t size,
size_t entsize)
{
size_t entries = size / entsize;
elf_rela_t *rela = (elf_rela_t *)(image->e_base + offset);
int status = SUCCESS;
for (size_t i = 0; i < entries; i++) {
status = do_rela(image, rela, true);
if (status != SUCCESS) {
break;
}
rela = (elf_rela_t *)((char *)rela + entsize);
}
return status;
}
static int relocate_rela(
struct elf_image *image,
off_t offset,
size_t size,
size_t entsize)
{
size_t entries = size / entsize;
elf_rela_t *rela = (elf_rela_t *)(image->e_base + offset);
int status = SUCCESS;
for (size_t i = 0; i < entries; i++) {
status = do_rela(image, rela, false);
if (status != SUCCESS) {
break;
}
rela = (elf_rela_t *)((char *)rela + entsize);
}
return status;
}
static int relocate_rel(
struct elf_image *image,
off_t offset,
size_t size,
size_t entsize)
{
return ENOEXEC;
}
static int do_rel(
struct elf_image *image,
off_t offset,
size_t size,
size_t entsize)
{
kern_tracef("do_rel (unsupported)");
return ENOEXEC;
}
#endif
static int load_dependency(struct elf_image *image, const char *name)
{
kern_tracef("required library: %s", name);
return ENOEXEC;
}
static int parse_dynamic(struct elf_image *image)
{
if (image->e_dynamic.p_type != PT_DYNAMIC) {
return SUCCESS;
}
image->e_dyn = (elf_dyn_t *)(image->e_base + image->e_dynamic.p_vaddr);
int status = SUCCESS;
size_t nr_dyn = image->e_dynamic.p_filesz / sizeof *image->e_dyn;
for (size_t i = 0; i < nr_dyn; i++) {
if (image->e_dyn[i].d_tag == DT_NULL) {
break;
}
switch (image->e_dyn[i].d_tag) {
case DT_NEEDED:
image->e_nr_links++;
break;
case DT_STRTAB:
image->e_strtab = image->e_dyn[i].d_un.d_ptr;
break;
case DT_SYMTAB:
image->e_dynsym = image->e_dyn[i].d_un.d_ptr;
break;
case DT_SYMENT:
image->e_dynsym_entsize = image->e_dyn[i].d_un.d_val;
break;
case DT_PLTGOT:
image->e_got_plt = image->e_dyn[i].d_un.d_val;
break;
case DT_HASH:
image->e_hash_type = ELF_HASH_STANDARD;
image->e_hash_table = image->e_dyn[i].d_un.d_ptr;
break;
case DT_GNU_HASH:
image->e_hash_type = ELF_HASH_GNU;
image->e_hash_table = image->e_dyn[i].d_un.d_ptr;
break;
case DT_REL:
image->e_rel_offset[ELF_RT_REL]
= image->e_dyn[i].d_un.d_ptr;
break;
case DT_RELSZ:
image->e_rel_size[ELF_RT_REL]
= image->e_dyn[i].d_un.d_val;
break;
case DT_RELENT:
image->e_rel_entsize[ELF_RT_REL]
= image->e_dyn[i].d_un.d_val;
break;
case DT_RELA:
image->e_rel_offset[ELF_RT_RELA]
= image->e_dyn[i].d_un.d_ptr;
break;
case DT_RELASZ:
image->e_rel_size[ELF_RT_RELA]
= image->e_dyn[i].d_un.d_val;
break;
case DT_RELAENT:
image->e_rel_entsize[ELF_RT_RELA]
= image->e_dyn[i].d_un.d_val;
break;
case DT_PLTREL:
image->e_pltrel_type = image->e_dyn[i].d_un.d_val;
switch (image->e_pltrel_type) {
case DT_REL:
image->e_rel_entsize[ELF_RT_PLTREL] = 0;
break;
case DT_RELA:
image->e_rel_entsize[ELF_RT_PLTREL]
= sizeof(elf_rela_t);
break;
default:
break;
}
break;
case DT_JMPREL:
image->e_rel_offset[ELF_RT_PLTREL]
= image->e_dyn[i].d_un.d_ptr;
break;
case DT_PLTRELSZ:
image->e_rel_size[ELF_RT_PLTREL]
= image->e_dyn[i].d_un.d_val;
break;
default:
break;
}
image->e_dyn_count++;
}
return SUCCESS;
}
static int reserve_exec_region(struct elf_image *image)
{
void *base
= mmap(NULL,
image->e_length,
PROT_NONE,
MAP_ANONYMOUS | MAP_PRIVATE,
-1,
0);
if (base == MAP_FAILED) {
return ENOMEM;
}
image->e_base = (virt_addr_t)base;
return KERN_OK;
}
static int create_image_with_name(const char *name, struct elf_image **out)
{
struct elf_image *elf = malloc(sizeof *elf);
if (!elf) {
return ENOMEM;
}
memset(elf, 0x0, sizeof *elf);
snprintf(elf->e_leaf.l_name, sizeof elf->e_leaf.l_name, "%s", name);
kern_config_get(
KERN_CFG_PAGE_SIZE,
&elf->e_page_size,
sizeof elf->e_page_size);
*out = elf;
return SUCCESS;
}
int elf_image_open(const char *path, struct elf_image **out)
{
struct elf_image *elf = malloc(sizeof *elf);
if (!elf) {
return ENOMEM;
}
memset(elf, 0x0, sizeof *elf);
kern_config_get(
KERN_CFG_PAGE_SIZE,
&elf->e_page_size,
sizeof elf->e_page_size);
int fd = open(path, O_RDONLY);
if (fd < 0) {
elf_image_close(elf);
return -fd;
}
elf->e_status = ELF_IMAGE_OPEN;
elf->e_fd = fd;
*out = elf;
return SUCCESS;
}
int elf_image_parse(struct elf_image *img)
{
if (img->e_status != ELF_IMAGE_OPEN) {
return EINVAL;
}
int e = read(img->e_fd, &img->e_hdr, sizeof img->e_hdr);
if (e < 0) {
return -e;
}
if (e != sizeof img->e_hdr) {
return ENOEXEC;
}
if (!elf_validate_ehdr(&img->e_hdr)) {
return ENOEXEC;
}
e = parse_phdr(img);
if (e != SUCCESS) {
return e;
}
img->e_status = ELF_IMAGE_PARSED;
return SUCCESS;
}
int elf_image_load(struct elf_image *img)
{
if (img->e_status != ELF_IMAGE_PARSED) {
return EINVAL;
}
int e = reserve_exec_region(img);
if (e != SUCCESS) {
return e;
}
e = map_image(img);
if (e != SUCCESS) {
return e;
}
e = parse_dynamic(img);
if (e != SUCCESS) {
return e;
}
img->e_status = ELF_IMAGE_LOADED;
return SUCCESS;
}
int elf_image_link(struct elf_image *img)
{
if (img->e_status != ELF_IMAGE_LOADED) {
return EINVAL;
}
int status = SUCCESS;
if (img->e_rel_offset[ELF_RT_REL]) {
status = relocate_rel(
img,
img->e_rel_offset[ELF_RT_REL],
img->e_rel_size[ELF_RT_REL],
img->e_rel_entsize[ELF_RT_REL]);
if (status != SUCCESS) {
return status;
}
}
if (img->e_rel_offset[ELF_RT_RELA]) {
status = relocate_rela(
img,
img->e_rel_offset[ELF_RT_RELA],
img->e_rel_size[ELF_RT_RELA],
img->e_rel_entsize[ELF_RT_RELA]);
if (status != SUCCESS) {
return status;
}
}
#if 1
if (img->e_rel_offset[ELF_RT_PLTREL]) {
status = relocate_pltrel(
img,
img->e_rel_offset[ELF_RT_PLTREL],
img->e_rel_size[ELF_RT_PLTREL],
img->e_rel_entsize[ELF_RT_PLTREL]);
if (status != SUCCESS) {
return status;
}
}
#endif
*(uintptr_t *)(img->e_base + img->e_got_plt + 16)
= (uintptr_t)_dl_runtime_resolve;
*(uintptr_t *)(img->e_base + img->e_got_plt + 8) = (uintptr_t)img;
img->e_entry = (virt_addr_t)img->e_base + img->e_hdr.e_entry;
img->e_status = ELF_IMAGE_LINKED;
return SUCCESS;
}
int elf_image_collect_dependencies(
struct elf_image *img,
struct image_list *dest)
{
if (!img->e_nr_links || img->e_links) {
return SUCCESS;
}
kern_tracef("collecting dependencies for %s", img->e_leaf.l_name);
int nr_added = 0;
img->e_links = calloc(img->e_nr_links, sizeof(struct elf_image *));
for (size_t i = 0; i < img->e_dyn_count; i++) {
if (img->e_dyn[i].d_tag != DT_NEEDED) {
continue;
}
const char *name = (const char *)img->e_base + img->e_strtab
+ img->e_dyn[i].d_un.d_val;
struct elf_image *dep = NULL;
struct image_list_leaf *leaf = NULL;
if ((leaf = image_list_get(dest, name))) {
dep = QUEUE_CONTAINER(struct elf_image, e_leaf, leaf);
} else {
int status = create_image_with_name(name, &dep);
if (status != SUCCESS) {
return -status;
}
image_list_put(dest, &dep->e_leaf);
}
img->e_links[nr_added] = dep;
kern_tracef(
"%s dependency %u = %s",
img->e_leaf.l_name,
nr_added,
dep->e_leaf.l_name);
nr_added++;
}
return nr_added;
}
int elf_image_add_dependency(struct elf_image *img, struct elf_image *dep)
{
struct elf_image **deps = realloc(
img->e_links,
sizeof(struct elf_image *) * img->e_nr_links + 1);
if (!deps) {
return ENOMEM;
}
deps[img->e_nr_links++] = dep;
img->e_links = deps;
return SUCCESS;
}
void elf_image_close(struct elf_image *image)
{
if (image->e_fd) {
close(image->e_fd);
}
free(image);
}
static uint32_t std_hash(const char *name)
{
uint32_t h = 0, g;
for (; *name; name++) {
h = (h << 4) + *name;
if ((g = h & 0xf0000000)) {
h ^= g >> 24;
}
h &= ~g;
}
return h;
}
static uint32_t gnu_hash(const char *name)
{
uint32_t h = 5381;
for (; *name; name++) {
h = (h << 5) + h + *name;
}
return h;
}
static const elf_sym_t *find_symbol_stdhash(
struct elf_image *img,
const char *name,
uint32_t hash)
{
const uint32_t *hashtab
= (void *)((virt_addr_t)img->e_base + img->e_hash_table);
const char *strtab = (void *)((virt_addr_t)img->e_base + img->e_strtab);
const elf_sym_t *symtab
= (void *)((virt_addr_t)img->e_base + img->e_dynsym);
const uint32_t nbucket = hashtab[0];
const uint32_t nchain = hashtab[1];
const uint32_t *bucket = &hashtab[2];
const uint32_t *chain = &bucket[nbucket];
for (uint32_t i = bucket[hash % nbucket]; i; i = chain[i]) {
const elf_sym_t *sym = &symtab[i];
if (strcmp(name, strtab + sym->st_name) != 0) {
continue;
}
if (!sym->st_value) {
continue;
}
return sym;
}
return 0;
}
static const elf_sym_t *find_symbol_gnuhash(
struct elf_image *img,
const char *name,
uint32_t hash)
{
return 0;
}
static const elf_sym_t *find_symbol_slow(
struct elf_image *img,
const char *name)
{
return 0;
}
static const elf_sym_t *find_symbol(
struct elf_image *img,
const char *name,
uint32_t std_hash,
uint32_t gnu_hash)
{
switch (img->e_hash_type) {
case ELF_HASH_STANDARD:
return find_symbol_stdhash(img, name, std_hash);
case ELF_HASH_GNU:
return find_symbol_gnuhash(img, name, gnu_hash);
default:
return find_symbol_slow(img, name);
}
}
int elf_image_find_symbol(
struct elf_image *img,
const char *name,
struct elf_symbol *out)
{
uint32_t std_hash_val = std_hash(name);
uint32_t gnu_hash_val = gnu_hash(name);
const elf_sym_t *sym
= find_symbol(img, name, std_hash_val, gnu_hash_val);
if (sym) {
out->sym_container = img;
out->sym_info = sym;
return SUCCESS;
}
return ENOENT;
}
int elf_image_find_linked_symbol(
struct elf_image *img,
const char *name,
struct elf_symbol *out)
{
uint32_t std_hash_val = std_hash(name);
uint32_t gnu_hash_val = gnu_hash(name);
struct elf_image *candidate_container = NULL;
const elf_sym_t *candidate = NULL;
const elf_sym_t *sym = NULL;
kern_tracef("searching %p (%zx)", img, img->e_base);
sym = find_symbol(img, name, std_hash_val, gnu_hash_val);
if (sym) {
if (ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
kern_tracef(
"found %s:%s (weak): %zx",
img->e_leaf.l_name,
name,
sym->st_value);
candidate = sym;
candidate_container = img;
} else {
kern_tracef(
"found %s:%s (strong): %zx",
img->e_leaf.l_name,
name,
sym->st_value);
out->sym_container = img;
out->sym_info = sym;
return SUCCESS;
}
}
for (size_t i = 0; i < img->e_nr_links; i++) {
kern_tracef(
"searching %p (%zx)",
img->e_links[i],
img->e_links[i]->e_base);
sym = find_symbol(
img->e_links[i],
name,
std_hash_val,
gnu_hash_val);
if (!sym) {
continue;
}
if (ELF64_ST_BIND(sym->st_info) == STB_WEAK) {
kern_tracef(
"found %s:%s (weak): %zx",
img->e_links[i]->e_leaf.l_name,
name,
sym->st_value);
candidate = sym;
candidate_container = img->e_links[i];
} else {
kern_tracef(
"found %s:%s (strong): %zx",
img->e_links[i]->e_leaf.l_name,
name,
sym->st_value);
out->sym_container = img;
out->sym_info = sym;
return SUCCESS;
}
}
if (candidate) {
out->sym_container = candidate_container;
out->sym_info = candidate;
return SUCCESS;
}
return ENOENT;
}
virt_addr_t find_global_symbol(const char *name)
{
struct image_list *images = global_image_list();
if (!images) {
return 0;
}
struct image_list_iterator it;
image_list_iterator_begin(&it, images);
virt_addr_t candidate = 0;
struct elf_symbol sym = {0};
while (it.it_leaf) {
struct elf_image *image
= QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
int status = elf_image_find_symbol(image, name, &sym);
if (status == ENOENT) {
image_list_iterator_move_next(&it);
continue;
}
if (ELF64_ST_BIND(sym.sym_info->st_info) == STB_WEAK) {
kern_tracef(
"found %s:%s (weak): %zx",
sym.sym_container->e_leaf.l_name,
name,
sym.sym_info->st_value);
candidate = (virt_addr_t)sym.sym_container->e_base
+ sym.sym_info->st_value;
} else {
kern_tracef(
"found %s:%s (strong): %zx",
sym.sym_container->e_leaf.l_name,
name,
sym.sym_info->st_value);
return (virt_addr_t)sym.sym_container->e_base
+ sym.sym_info->st_value;
}
image_list_iterator_move_next(&it);
}
return candidate;
}

381
sys/ld/elf.h Normal file
View File

@@ -0,0 +1,381 @@
#ifndef LD_ELF_H_
#define LD_ELF_H_
#include "image-list.h"
#include <mango/types.h>
#include <stdint.h>
enum elf_image_status {
ELF_IMAGE_NONE = 0,
ELF_IMAGE_OPEN,
ELF_IMAGE_PARSED,
ELF_IMAGE_LOADED,
ELF_IMAGE_LINKED,
};
enum elf_hash_type {
ELF_HASH_NONE = 0,
ELF_HASH_STANDARD,
ELF_HASH_GNU,
};
enum elf_relocation_type {
ELF_RT_NONE = 0,
ELF_RT_REL,
ELF_RT_RELA,
ELF_RT_PLTREL,
ELF_RT_COUNT,
};
#define ELF_LOAD_ERR -1
#define ELF_LOADED_EXEC 0
#define ELF_LOADED_INTERP 1
#define ELF_MAG0 0x7f
#define ELF_MAG1 'E'
#define ELF_MAG2 'L'
#define ELF_MAG3 'F'
#define ELF_NIDENT 16
#define SHT_NONE 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_DYNAMIC 6
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_DYNSYM 11
/** Little endian. */
#define ELFDATA2LSB (1)
/** 64-bit. */
#define ELFCLASS64 (2)
/** x86_64 machine type. */
#define EM_X86_64 (62)
/** ELF current version. */
#define EV_CURRENT (1)
/** Dynamic section tags. */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_JMPREL 23
#define DT_GNU_HASH 0x6ffffef5
#define DT_AUXILIARY 0x7ffffffd
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GOT32 3
#define R_386_PLT32 4
#define R_386_GOTOFF 9
#define R_386_GOTPC 10
#define R_386_GOT32X 43
#define R_X86_64_64 1
#define R_X86_64_PC32 2
#define R_X86_64_GOT32 3
#define R_X86_64_PLT32 4
#define R_X86_64_COPY 5
#define R_X86_64_GLOB_DAT 6
#define R_X86_64_JUMP_SLOT 7
#define R_X86_64_RELATIVE 8
#define R_X86_64_GOTPCREL 9
#define R_X86_64_32 10
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
/* Section flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHN_UNDEF 0
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((elf_word_t)(i))
#define ELF64_ST_BIND(i) ((i) >> 4)
#define ELF64_ST_TYPE(i) ((i) & 0xf)
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_NUM 3
typedef uint64_t elf_addr_t;
typedef uint64_t elf_off_t;
typedef uint16_t elf_half_t;
typedef uint32_t elf_word_t;
typedef int32_t elf_sword_t;
typedef uint64_t elf_xword_t;
typedef int64_t elf_sxword_t;
/**
* ELF file header.
*/
typedef struct {
uint8_t e_ident[ELF_NIDENT];
elf_half_t e_type;
elf_half_t e_machine;
elf_word_t e_version;
elf_addr_t e_entry;
elf_off_t e_phoff;
elf_off_t e_shoff;
elf_word_t e_flags;
elf_half_t e_ehsize;
elf_half_t e_phentsize;
elf_half_t e_phnum;
elf_half_t e_shentsize;
elf_half_t e_shnum;
elf_half_t e_shstrndx;
} elf_ehdr_t;
/**
* ELF section header.
*/
typedef struct {
elf_word_t sh_name;
elf_word_t sh_type;
elf_xword_t sh_flags;
elf_addr_t sh_addr;
elf_off_t sh_offset;
elf_xword_t sh_size;
elf_word_t sh_link;
elf_word_t sh_info;
elf_xword_t sh_addralign;
elf_xword_t sh_entsize;
} elf_shdr_t;
/**
* ELF symbol.
*/
typedef struct {
elf_word_t st_name;
unsigned char st_info;
unsigned char st_other;
elf_half_t st_shndx;
elf_addr_t st_value;
elf_xword_t st_size;
} elf_sym_t;
/**
* ELF program header.
*/
typedef struct {
elf_word_t p_type;
elf_word_t p_flags;
elf_off_t p_offset;
elf_addr_t p_vaddr;
elf_addr_t p_paddr;
elf_xword_t p_filesz;
elf_xword_t p_memsz;
elf_xword_t p_align;
} elf_phdr_t;
/**
* Extended ELF relocation information.
*/
typedef struct {
elf_addr_t r_offset;
elf_xword_t r_info;
elf_sxword_t r_addend;
} elf_rela_t;
/**
* Dynamic section entries
*/
typedef struct {
elf_sxword_t d_tag;
union {
elf_xword_t d_val;
elf_addr_t d_ptr;
} d_un;
} elf_dyn_t;
/**
* Section header types.
*/
enum elf_stype {
ST_NONE = 0,
ST_PROGBITS = 1,
ST_SYMTAB = 2,
ST_STRTAB = 3,
ST_NOBITS = 8,
ST_REL = 9
};
/**
* Program header types.
*/
enum elf_ptype {
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6
};
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
/**
* ELF identification byte locations.
*/
enum elf_ident {
EI_MAG0 = 0,
EI_MAG1 = 1,
EI_MAG2 = 2,
EI_MAG3 = 3,
EI_CLASS = 4,
EI_DATA = 5,
EI_VERSION = 6,
EI_OSABI = 7,
EI_ABIVERSION = 8,
EI_PAD = 9
};
enum elf_type {
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
};
#define AT_NULL 0
#define AT_IGNORE 1
#define AT_EXECFD 2
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_ENTRY 9
#define AT_NOTELF 10
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_CLKTCK 17
#define AT_PLATFORM 15
#define AT_HWCAP 16
#define AT_FPUCW 18
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
#define AT_IGNOREPPC 22
#define AT_SECURE 23
#define AT_BASE_PLATFORM 24
#define AT_RANDOM 25
#define AT_HWCAP2 26
#define AT_EXECFN 31
#define AT_SYSINFO 32
#define AT_SYSINFO_EHDR 33
#define AT_L1I_CACHESHAPE 34
#define AT_L1D_CACHESHAPE 35
#define AT_L2_CACHESHAPE 36
#define AT_L3_CACHESHAPE 37
#define AT_ENTRY_COUNT 38
struct bootdata;
struct bootfs_file;
struct elf_image {
enum elf_image_status e_status;
struct image_list_leaf e_leaf;
int e_fd;
size_t e_page_size;
elf_ehdr_t e_hdr;
virt_addr_t e_base;
size_t e_length, e_data_length;
virt_addr_t e_entry;
virt_addr_t e_strtab;
enum elf_hash_type e_hash_type;
virt_addr_t e_hash_table;
virt_addr_t e_got_plt;
virt_addr_t e_dynsym;
size_t e_dynsym_entsize;
elf_phdr_t e_dynamic;
elf_dyn_t *e_dyn;
size_t e_dyn_count;
int e_pltrel_type;
off_t e_rel_offset[ELF_RT_COUNT];
size_t e_rel_size[ELF_RT_COUNT];
size_t e_rel_entsize[ELF_RT_COUNT];
struct elf_image **e_links;
size_t e_nr_links;
};
struct elf_symbol {
struct elf_image *sym_container;
const elf_sym_t *sym_info;
};
extern const char *elf_image_status_to_string(enum elf_image_status status);
extern int elf_image_open(const char *path, struct elf_image **out);
extern int elf_image_parse(struct elf_image *img);
extern int elf_image_load(struct elf_image *img);
extern int elf_image_collect_dependencies(
struct elf_image *img,
struct image_list *dest);
extern int elf_image_add_dependency(
struct elf_image *img,
struct elf_image *dep);
extern int elf_image_link(struct elf_image *img);
extern void elf_image_close(struct elf_image *img);
extern int elf_image_find_symbol(
struct elf_image *img,
const char *name,
struct elf_symbol *out);
extern int elf_image_find_symbol(
struct elf_image *img,
const char *name,
struct elf_symbol *out);
extern int elf_image_find_linked_symbol(
struct elf_image *img,
const char *name,
struct elf_symbol *out);
extern virt_addr_t find_global_symbol(const char *name);
#endif

16
sys/ld/hash.c Normal file
View File

@@ -0,0 +1,16 @@
#include <stdint.h>
#define BASIS 0xcbf29ce484222325
#define PRIME 0x100000001b3
uint64_t hash_string(const char *s)
{
uint64_t result = BASIS;
for (unsigned int i = 0; s[i]; i++) {
result ^= s[i];
result *= PRIME;
}
return result;
}

8
sys/ld/hash.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef HASH_H_
#define HASH_H_
#include <stdint.h>
extern uint64_t hash_string(const char *s);
#endif

211
sys/ld/image-list.c Normal file
View File

@@ -0,0 +1,211 @@
#include "image-list.h"
#include "hash.h"
#include <mango/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static BTREE_DEFINE_SIMPLE_GET(
struct image_list_entry,
uint64_t,
e_node,
e_hash,
get_entry);
static BTREE_DEFINE_SIMPLE_INSERT(
struct image_list_entry,
e_node,
e_hash,
put_entry);
void image_list_init(struct image_list *list)
{
memset(list, 0x0, sizeof *list);
}
void image_list_cleanup(struct image_list *list)
{
}
extern struct image_list_bucket *convert_to_bucket(
struct btree *tree,
struct image_list_leaf *leaf)
{
btree_delete(tree, &leaf->l_base.e_node);
struct image_list_bucket *bucket = malloc(sizeof *bucket);
if (!bucket) {
return NULL;
}
bucket->b_base.e_hash = leaf->l_base.e_hash;
bucket->b_base.e_type = IMAGE_LIST_ENTRY_BUCKET;
put_entry(tree, &bucket->b_base);
queue_push_back(&bucket->b_items, &leaf->l_base.e_entry);
return bucket;
}
extern void image_list_put(
struct image_list *list,
struct image_list_leaf *item)
{
uint64_t hash = hash_string(item->l_name);
item->l_base.e_type = IMAGE_LIST_ENTRY_LEAF;
item->l_base.e_hash = hash;
struct image_list_entry *entry = get_entry(&list->l_items, hash);
if (!entry) {
put_entry(&list->l_items, &item->l_base);
return;
}
if (entry->e_type == IMAGE_LIST_ENTRY_BUCKET) {
struct image_list_bucket *bucket
= (struct image_list_bucket *)entry;
queue_push_back(&bucket->b_items, &item->l_base.e_entry);
return;
}
struct image_list_leaf *leaf = (struct image_list_leaf *)entry;
struct image_list_bucket *bucket
= convert_to_bucket(&list->l_items, leaf);
if (!bucket) {
return;
}
queue_push_back(&bucket->b_items, &item->l_base.e_entry);
}
extern struct image_list_leaf *image_list_get(
struct image_list *list,
const char *name)
{
uint64_t hash = hash_string(name);
struct image_list_entry *entry = get_entry(&list->l_items, hash);
if (!entry) {
return NULL;
}
switch (entry->e_type) {
case IMAGE_LIST_ENTRY_LEAF: {
struct image_list_leaf *leaf = (struct image_list_leaf *)entry;
if (!strcmp(leaf->l_name, name)) {
return leaf;
}
break;
}
case IMAGE_LIST_ENTRY_BUCKET: {
struct image_list_bucket *bucket
= (struct image_list_bucket *)entry;
struct queue_entry *cur = queue_first(&bucket->b_items);
while (cur) {
struct image_list_leaf *leaf = QUEUE_CONTAINER(
struct image_list_leaf,
l_base.e_entry,
cur);
if (!strcmp(leaf->l_name, name)) {
return leaf;
}
cur = queue_next(cur);
break;
}
}
default:
break;
}
return NULL;
}
void image_list_iterator_begin(
struct image_list_iterator *it,
struct image_list *list)
{
memset(it, 0x0, sizeof *it);
struct btree_node *node = btree_first(&list->l_items);
if (!node) {
return;
}
while (1) {
it->it_cur = QUEUE_CONTAINER(
struct image_list_entry,
e_node,
node);
if (it->it_cur->e_type == IMAGE_LIST_ENTRY_LEAF) {
it->it_leaf = (struct image_list_leaf *)it->it_cur;
return;
}
struct image_list_bucket *bucket
= (struct image_list_bucket *)it->it_cur;
struct queue_entry *entry = queue_first(&bucket->b_items);
if (!entry) {
node = btree_next(node);
continue;
}
it->it_leaf = QUEUE_CONTAINER(
struct image_list_leaf,
l_base.e_entry,
entry);
break;
}
}
void image_list_iterator_move_next(struct image_list_iterator *it)
{
if (!it->it_cur || !it->it_leaf) {
return;
}
while (1) {
if (it->it_cur->e_type == IMAGE_LIST_ENTRY_LEAF) {
/* current entry is a leaf */
struct queue_entry *next
= queue_next(&it->it_leaf->l_base.e_entry);
if (next) {
it->it_leaf = QUEUE_CONTAINER(
struct image_list_leaf,
l_base.e_entry,
next);
}
}
struct btree_node *node = btree_next(&it->it_cur->e_node);
if (!node) {
it->it_cur = NULL;
it->it_leaf = NULL;
return;
}
it->it_cur = BTREE_CONTAINER(
struct image_list_entry,
e_node,
node);
if (it->it_cur->e_type == IMAGE_LIST_ENTRY_LEAF) {
/* next entry is a leaf */
it->it_leaf = (struct image_list_leaf *)it->it_cur;
return;
}
struct image_list_bucket *bucket
= (struct image_list_bucket *)it->it_cur;
struct queue_entry *entry = queue_first(&bucket->b_items);
if (!entry) {
continue;
}
it->it_leaf = QUEUE_CONTAINER(
struct image_list_leaf,
l_base.e_entry,
entry);
break;
}
}

59
sys/ld/image-list.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef IMAGE_LIST_H_
#define IMAGE_LIST_H_
#include "btree.h"
#include "queue.h"
#include <stdint.h>
#define IMAGE_NAME_MAX 256
enum image_list_entry_type {
IMAGE_LIST_ENTRY_NONE = 0,
IMAGE_LIST_ENTRY_LEAF,
IMAGE_LIST_ENTRY_BUCKET,
};
struct image_list_entry {
enum image_list_entry_type e_type;
uint64_t e_hash;
union {
struct btree_node e_node;
struct queue_entry e_entry;
};
};
struct image_list_bucket {
struct image_list_entry b_base;
struct queue b_items;
};
struct image_list_leaf {
struct image_list_entry l_base;
char l_name[IMAGE_NAME_MAX];
};
struct image_list {
struct btree l_items;
};
struct image_list_iterator {
struct image_list_entry *it_cur;
struct image_list_leaf *it_leaf;
};
extern void image_list_init(struct image_list *list);
extern void image_list_cleanup(struct image_list *list);
extern void image_list_put(
struct image_list *list,
struct image_list_leaf *item);
extern struct image_list_leaf *image_list_get(
struct image_list *list,
const char *name);
extern void image_list_iterator_begin(
struct image_list_iterator *it,
struct image_list *list);
extern void image_list_iterator_move_next(struct image_list_iterator *it);
#endif

8
sys/ld/ld.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef LD_H_
#define LD_H_
struct image_list;
extern struct image_list *global_image_list(void);
#endif

View File

@@ -1,7 +1,10 @@
#define MSG_IMPLEMENTATION #define MSG_IMPLEMENTATION
#define MSG_NO_MALLOC #define MSG_NO_MALLOC
#include "elf.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <heap/heap.h> #include <heap/heap.h>
#include <mango/log.h> #include <mango/log.h>
#include <mango/msg.h> #include <mango/msg.h>
@@ -10,6 +13,7 @@
#include <mango/vm.h> #include <mango/vm.h>
#include <rosetta/bootstrap.h> #include <rosetta/bootstrap.h>
#include <rosetta/fs.h> #include <rosetta/fs.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -17,88 +21,233 @@
#include <sys/remote.h> #include <sys/remote.h>
#include <unistd.h> #include <unistd.h>
static const char *search_paths[] = {
"/usr/lib",
};
static const size_t nr_search_paths
= sizeof search_paths / sizeof search_paths[0];
static struct image_list images = {0};
struct image_list *global_image_list(void)
{
return &images;
}
static void report_error(const char *name, int err, const char *msg, ...)
{
char buf[1024];
va_list arg;
va_start(arg, msg);
vsnprintf(buf, sizeof buf, msg, arg);
va_end(arg);
kern_logf("%s: %s: %s", name, buf, strerror(err));
}
static const char *get_image_name(const char *path)
{
const char *last_slash = NULL;
for (size_t i = 0; path[i]; i++) {
if (path[i] == '/') {
last_slash = path + i;
}
}
return last_slash ? last_slash + 1 : path;
}
static int find_image(struct elf_image *img)
{
const char *name = img->e_leaf.l_name;
char path[4096];
for (size_t i = 0; i < nr_search_paths; i++) {
snprintf(path, sizeof path, "%s/%s", search_paths[i], name);
int fd = open(path, O_RDONLY);
if (fd < 0) {
continue;
}
kern_tracef("found %s -> %s", name, path);
img->e_fd = fd;
img->e_status = ELF_IMAGE_OPEN;
return SUCCESS;
}
return ENOENT;
}
static int load_images(const char *task_name, struct image_list *list)
{
int status = SUCCESS;
struct image_list_iterator it;
image_list_iterator_begin(&it, list);
while (it.it_leaf) {
struct elf_image *image
= QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
kern_tracef(
"image: %s [%s]",
it.it_leaf->l_name,
elf_image_status_to_string(image->e_status));
int new_dependencies = 0;
switch (image->e_status) {
case ELF_IMAGE_NONE:
/* Find the image using its name */
status = find_image(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
case ELF_IMAGE_OPEN:
/* parse the image */
status = elf_image_parse(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
case ELF_IMAGE_PARSED:
/* load the image */
status = elf_image_load(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
case ELF_IMAGE_LOADED:
/* collect dependencies */
new_dependencies
= elf_image_collect_dependencies(image, list);
default:
break;
}
if (new_dependencies < 0) {
report_error(
task_name,
-new_dependencies,
"error while loading %s",
image->e_leaf.l_name);
return -new_dependencies;
}
if (new_dependencies > 0) {
image_list_iterator_begin(&it, list);
} else {
image_list_iterator_move_next(&it);
}
}
return SUCCESS;
}
static int link_images(const char *task_name, struct image_list *list)
{
int status = SUCCESS;
struct image_list_iterator it;
image_list_iterator_begin(&it, list);
kern_trace("linking all images");
while (it.it_leaf) {
struct elf_image *image
= QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
kern_tracef(
"image: %s [%s]",
it.it_leaf->l_name,
elf_image_status_to_string(image->e_status));
status = elf_image_link(image);
if (status != SUCCESS) {
report_error(
task_name,
status,
"error while loading %s",
image->e_leaf.l_name);
return status;
}
image_list_iterator_move_next(&it);
}
return SUCCESS;
}
int main(const struct rosetta_bootstrap *bs) int main(const struct rosetta_bootstrap *bs)
{ {
kern_logf("ld"); kern_tracef("ld");
kern_handle_t task, address_space;
task_self(&task);
task_get_address_space(task, &address_space);
for (size_t i = 0; i < bs->bs_argc; i++) { for (size_t i = 0; i < bs->bs_argc; i++) {
kern_logf("argv[%zu]: %s", i, bs->bs_argv[i]); kern_tracef("argv[%zu]: %s", i, bs->bs_argv[i]);
} }
sys_remote_set(SYS_REMOTE_NSD, 0, 0); sys_remote_set(SYS_REMOTE_NSD, 0, 0);
const char *path = "/usr/lib/libc.so"; const char *exec_path = bs->bs_argv[1];
int flags = 4; const char *task_name = bs->bs_argv[2];
const char *image_name = get_image_name(exec_path);
kern_logf("sending msg: open(%s, %d)", path, flags); image_list_init(&images);
int fd = open(path, flags);
if (fd < 0) { struct elf_image *exec = NULL;
kern_logf( int err = elf_image_open(exec_path, &exec);
"open(%s, %d) = %s (%s)", if (err != SUCCESS) {
path, report_error(
flags, task_name,
strerror_code(fd), err,
strerror(fd)); "error while loading %s",
exec_path);
return -1; return -1;
} }
kern_logf( snprintf(
"open(%s, %d) = %s (%s)", exec->e_leaf.l_name,
path, sizeof exec->e_leaf.l_name,
flags, "%s",
strerror_code(SUCCESS), image_name);
strerror(SUCCESS));
unsigned char buf[32] = {0}; image_list_put(&images, &exec->e_leaf);
int nr = read(fd, buf, sizeof buf); err = load_images(task_name, &images);
if (err != SUCCESS) {
if (nr < 0) {
kern_logf("read call failed (%s)", strerror(nr));
return -1; return -1;
} }
kern_logf("data: %x %c %c %c", buf[0], buf[1], buf[2], buf[3]); err = link_images(task_name, &images);
if (err != SUCCESS) {
void *p return -1;
= mmap(NULL,
0x1000,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE,
-1,
0);
if (p != MAP_FAILED) {
memset(p, 0x0, 0x1000);
kern_logf("mmap'd buffer at %p", p);
} else {
kern_logf("mmap buffer failed");
} }
void *lib struct image_list_iterator it;
= mmap(NULL, 0x2000, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0); image_list_iterator_begin(&it, &images);
if (lib != MAP_FAILED) {
kern_logf("mmap'd %s at %p", path, lib); while (it.it_leaf) {
unsigned char *tmp = lib; struct elf_image *image
kern_logf( = QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
"data[0]: %x %c %c %c", kern_tracef(
tmp[0], "image: %s [%s]",
tmp[1], it.it_leaf->l_name,
tmp[2], elf_image_status_to_string(image->e_status));
tmp[3]);
tmp += 0x1000; image_list_iterator_move_next(&it);
kern_logf(
"data[0x1000]: %02x %02x %02x %02x",
tmp[0],
tmp[1],
tmp[2],
tmp[3]);
} else {
kern_logf("mmap lib failed");
} }
kern_logf("ld finished"); kern_tracef("ld finished");
return 0; struct rosetta_bootstrap exec_bsinfo;
memcpy(&exec_bsinfo, bs, sizeof exec_bsinfo);
exec_bsinfo.bs_argc -= 2;
exec_bsinfo.bs_argv += 2;
int (*entry)(const struct rosetta_bootstrap *)
= (int (*)(const struct rosetta_bootstrap *))exec->e_entry;
return entry(&exec_bsinfo);
} }

138
sys/ld/queue.c Normal file
View File

@@ -0,0 +1,138 @@
#include "queue.h"
size_t queue_length(struct queue *q)
{
size_t i = 0;
struct queue_entry *x = q->q_first;
while (x) {
i++;
x = x->qe_next;
}
return i;
}
void queue_insert_before(
struct queue *q,
struct queue_entry *entry,
struct queue_entry *before)
{
struct queue_entry *x = before->qe_prev;
if (x) {
x->qe_next = entry;
} else {
q->q_first = entry;
}
entry->qe_prev = x;
before->qe_prev = entry;
entry->qe_next = before;
}
void queue_insert_after(
struct queue *q,
struct queue_entry *entry,
struct queue_entry *after)
{
struct queue_entry *x = after->qe_next;
if (x) {
x->qe_prev = entry;
} else {
q->q_last = entry;
}
entry->qe_prev = x;
after->qe_next = entry;
entry->qe_prev = after;
}
void queue_push_front(struct queue *q, struct queue_entry *entry)
{
if (q->q_first) {
q->q_first->qe_prev = entry;
}
entry->qe_next = q->q_first;
entry->qe_prev = NULL;
q->q_first = entry;
if (!q->q_last) {
q->q_last = entry;
}
}
void queue_push_back(struct queue *q, struct queue_entry *entry)
{
if (q->q_last) {
q->q_last->qe_next = entry;
}
entry->qe_prev = q->q_last;
entry->qe_next = NULL;
q->q_last = entry;
if (!q->q_first) {
q->q_first = entry;
}
}
struct queue_entry *queue_pop_front(struct queue *q)
{
struct queue_entry *x = q->q_first;
if (x) {
queue_delete(q, x);
}
return x;
}
struct queue_entry *queue_pop_back(struct queue *q)
{
struct queue_entry *x = q->q_last;
if (x) {
queue_delete(q, x);
}
return x;
}
void queue_delete(struct queue *q, struct queue_entry *entry)
{
if (!entry) {
return;
}
if (entry == q->q_first) {
q->q_first = q->q_first->qe_next;
}
if (entry == q->q_last) {
q->q_last = q->q_last->qe_prev;
}
if (entry->qe_next) {
entry->qe_next->qe_prev = entry->qe_prev;
}
if (entry->qe_prev) {
entry->qe_prev->qe_next = entry->qe_next;
}
entry->qe_next = entry->qe_prev = NULL;
}
void queue_delete_all(struct queue *q)
{
struct queue_entry *x = q->q_first;
while (x) {
struct queue_entry *next = x->qe_next;
x->qe_next = x->qe_prev = NULL;
x = next;
}
q->q_first = q->q_last = NULL;
}

100
sys/ld/queue.h Normal file
View File

@@ -0,0 +1,100 @@
#ifndef QUEUE_H_
#define QUEUE_H_
#include <stdbool.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#define QUEUE_CONTAINER(t, m, v) \
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
#define QUEUE_INIT ((struct queue) {.q_first = NULL, .q_last = NULL})
#define QUEUE_ENTRY_INIT \
((struct queue_entry) {.qe_next = NULL, .qe_prev = NULL})
#define queue_foreach(iter_type, iter_name, queue_name, node_member) \
for (iter_type *iter_name = (iter_type *)QUEUE_CONTAINER( \
iter_type, \
node_member, \
queue_first(queue_name)); \
iter_name; \
iter_name = (iter_type *)QUEUE_CONTAINER( \
iter_type, \
node_member, \
queue_next(&((iter_name)->node_member))))
#define queue_foreach_r(iter_type, iter_name, queue_name, node_member) \
for (iter_type *iter_name = (iter_type *)QUEUE_CONTAINER( \
iter_type, \
node_member, \
queue_last(queue_name)); \
iter_name; \
iter_name = (iter_type *)QUEUE_CONTAINER( \
iter_type, \
node_member, \
queue_prev(&((iter_name)->node_member))))
struct queue_entry {
struct queue_entry *qe_next;
struct queue_entry *qe_prev;
};
struct queue {
struct queue_entry *q_first;
struct queue_entry *q_last;
};
static inline void queue_init(struct queue *q)
{
memset(q, 0x00, sizeof *q);
}
static inline bool queue_empty(struct queue *q)
{
return q->q_first == NULL;
}
static inline struct queue_entry *queue_first(struct queue *q)
{
return q->q_first;
}
static inline struct queue_entry *queue_last(struct queue *q)
{
return q->q_last;
}
static inline struct queue_entry *queue_next(struct queue_entry *entry)
{
return entry->qe_next;
}
static inline struct queue_entry *queue_prev(struct queue_entry *entry)
{
return entry->qe_prev;
}
extern size_t queue_length(struct queue *q);
extern void queue_insert_before(
struct queue *q,
struct queue_entry *entry,
struct queue_entry *before);
extern void queue_insert_after(
struct queue *q,
struct queue_entry *entry,
struct queue_entry *after);
extern void queue_push_front(struct queue *q, struct queue_entry *entry);
extern void queue_push_back(struct queue *q, struct queue_entry *entry);
extern struct queue_entry *queue_pop_front(struct queue *q);
extern struct queue_entry *queue_pop_back(struct queue *q);
extern void queue_delete(struct queue *q, struct queue_entry *entry);
extern void queue_delete_all(struct queue *q);
#ifdef __cplusplus
}
#endif
#endif

51
sys/ld/resolve.c Normal file
View File

@@ -0,0 +1,51 @@
#include "elf.h"
#include <mango/log.h>
#include <stdint.h>
#include <stdio.h>
uintptr_t dl_runtime_resolve(struct elf_image *img, unsigned long sym_id)
{
unsigned long slot_id = sym_id;
switch (img->e_rel_entsize[ELF_RT_PLTREL]) {
case sizeof(elf_rela_t): {
elf_rela_t *rela
= (elf_rela_t *)((virt_addr_t)img->e_base
+ img->e_rel_offset[ELF_RT_PLTREL]);
elf_rela_t *rela_sym = &rela[sym_id];
kern_tracef(
"rela %u -> .dynsym %u, .got %u",
sym_id,
ELF64_R_SYM(rela_sym->r_info),
slot_id);
sym_id = ELF64_R_SYM(rela_sym->r_info);
/* the first three entries in the GOT are not symbols. */
slot_id += 3;
break;
}
default:
return 0;
}
elf_sym_t *sym
= (elf_sym_t *)((virt_addr_t)img->e_base + img->e_dynsym);
virt_addr_t *got
= (virt_addr_t *)((virt_addr_t)img->e_base + img->e_got_plt);
const char *sym_name = (const char *)img->e_base + img->e_strtab
+ sym[sym_id].st_name;
kern_tracef(
"%s: request for symbol %u: %s",
img->e_leaf.l_name,
sym_id,
sym_name);
#if 0
virt_addr_t sym_addr = elf_image_find_linked_symbol(img, sym_name);
#else
virt_addr_t sym_addr = find_global_symbol(sym_name);
#endif
kern_tracef("symbol %s = %zx", sym_name, sym_addr);
kern_tracef("slot %s = %zx", sym_name, &got[slot_id]);
got[slot_id] = sym_addr;
return sym_addr;
}

Some files were not shown because too many files have changed in this diff Show More