Compare commits

...

73 Commits

Author SHA1 Message Date
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
c11d55d675 meta: update kernel 2026-03-15 14:41:12 +00:00
a5cf0b050d ld: try reading multiple pages of mapped file 2026-03-15 14:41:07 +00:00
bd39cb11aa meta: update kernel 2026-03-15 09:50:38 +00:00
a01b5ddb11 cmake: add a simple does-the-os-boot-successfully test
the test will repeated boot the operating system and use the serial log to determine
if the boot was successful. if a problem is detected, a debugger is automatically
started and attached.
2026-03-15 09:49:51 +00:00
1e9fe24b39 ld: anonymous and file-backed mmap tests 2026-03-15 09:49:18 +00:00
9044281d1b bootstrap: use new libfs interface to handle requests 2026-03-15 09:48:47 +00:00
5dd99bb0a6 bootstrap: tar: fix pointer-alignment tar parsing issue 2026-03-15 09:47:58 +00:00
d03c750e4a cmake: ensure interface headers are regenerated when the corresponding .xpc file is changed 2026-03-15 09:47:03 +00:00
c66c7f3f3f x86_64: cmake: enable RDRAND support when running the kernel under qemu 2026-03-15 09:46:32 +00:00
29acfcee69 toolchain: xpcg: fix output header not being truncated 2026-03-15 09:45:31 +00:00
fea89d675e toolchain: xpcg: fix incorrect variable/type names in output header 2026-03-15 09:45:08 +00:00
eb8d9c3512 interface: fs: add error code result to fs.map() 2026-03-15 09:44:32 +00:00
0c56c645ac lib: fs: implement memory-mapped file i/o 2026-03-15 09:43:49 +00:00
68b7783f32 lib: xpc: implement non-blocking msg receive function 2026-03-15 09:43:22 +00:00
ea2b0d3986 lib: xpc: implement writing to local buffers 2026-03-15 09:43:00 +00:00
c9ccebacfc lib: launch: update to use new address-space api 2026-03-15 09:42:22 +00:00
5ad5f57a76 lib: c: update libheap to use new address-space api 2026-03-15 09:42:03 +00:00
f441d633b2 lib: c: implement mmap() 2026-03-15 09:41:25 +00:00
9ea3441fcc lib: c: move io sys headers to include/sys 2026-03-15 09:40:37 +00:00
86ca343cf0 interface: fs: remove old ifc definition file 2026-03-10 19:20:18 +00:00
130 changed files with 6031 additions and 945 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

@@ -1,3 +1,4 @@
include(System-Disk) include(System-Disk)
include(QEMU) include(QEMU)
include(Bochs) include(Bochs)
include(Test)

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

@@ -8,7 +8,8 @@ find_program(LLDB lldb)
find_program(GDB gdb) find_program(GDB gdb)
set(patched_kernel ${CMAKE_CURRENT_BINARY_DIR}/kernel/${kernel_name}.elf32) set(patched_kernel ${CMAKE_CURRENT_BINARY_DIR}/kernel/${kernel_name}.elf32)
set(generic_flags -m 1G) set(generic_flags -m 128M -cpu qemu64,+rdrand)
set(no_debug_flags) set(no_debug_flags)
if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux") if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")

35
arch/x86_64/Test.cmake Normal file
View File

@@ -0,0 +1,35 @@
find_package(Python COMPONENTS Interpreter)
if (NOT Python_EXECUTABLE)
message(STATUS "QEMU: Cannot find python. Direct-kernel boot testing unavailable")
return()
endif ()
find_program(QEMU qemu-system-${TARGET_ARCH} REQUIRED)
if (NOT QEMU)
message(STATUS "QEMU: Cannot find qemu-system-${TARGET_ARCH}. Direct-kernel boot testing unavailable")
return()
endif ()
set(patched_kernel ${CMAKE_CURRENT_BINARY_DIR}/kernel/${kernel_name}.elf32)
set(generic_flags -m 1G -cpu qemu64,+rdrand)
set(this_dir ${CMAKE_SOURCE_DIR}/arch/${CMAKE_SYSTEM_PROCESSOR})
set(no_debug_flags)
if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
message(STATUS "QEMU: Enabling KVM acceleration")
set(no_debug_flags ${no_debug_flags} -enable-kvm)
else ()
message(STATUS "QEMU: Host system is not Linux. KVM acceleration unavailable")
endif ()
message(STATUS "Test: Enable direct-kernel boot testing with QEMU")
add_custom_target(test-successful-boot
COMMAND
${this_dir}/test/successful-boot
${Python_EXECUTABLE}
${this_dir}/test/check-results
${QEMU}
${patched_kernel}
${sys_dir}/${bsp_name}
USES_TERMINAL
DEPENDS ${patched_kernel} bsp)

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
# vim: ft=python
import sys
def log(f, msg):
print(msg)
f.write(msg)
f.write('\n')
def successful_boot(boot_log, out):
nr_panic = boot_log.count("---[ kernel panic")
if nr_panic == 1:
log(out, "Kernel panic!")
return 1
if nr_panic > 1:
log(out, "Multiple kernel panics!")
return 1
nr_boots = boot_log.count('Mango kernel version')
if nr_boots == 0:
log(out, "Kernel didn't start!")
return 1
if nr_boots > 1:
log(out, "Kernel rebooted during test!")
return 1
nr_finish = boot_log.count("ld finished")
if nr_finish == 0:
log(out, "Didn't reach end of boot sequence!")
return 1
if nr_finish > 1:
log(out, "Boot sequence performed multiple times!")
return 1
return 0
tests = {
'successful-boot': successful_boot,
}
test_name = sys.argv[1]
boot_log_path = sys.argv[2]
out_path = sys.argv[3]
boot_log_file = open(boot_log_path, 'r')
boot_log = boot_log_file.read()
boot_log_file.close()
out_file = open(out_path, 'a')
exit(tests[test_name](boot_log, out_file))

View File

@@ -0,0 +1,69 @@
#!/bin/bash
# vim: ft=bash
log_dir="test-results/successful-boot"
rm -rf $log_dir
mkdir -p $log_dir
logfile="$log_dir/main.log"
log() {
if [ -n "$logfile" ]; then
printf '%s\n' "$@" >> "$logfile"
fi
printf '%s\n' "$@"
}
log "Running boot test. Press Ctrl+\\ to stop."
declare -i result
declare -i count
declare -i pass
declare -i fail
count=0
pass=0
fail=0
python=$1
validation_script=$2
qemu=$3
kernel=$4
initrd=$5
while true; do
log "Test $count"
result_file="$log_dir/$count.log"
$qemu \
-kernel $kernel \
-initrd $initrd \
-serial file:$result_file \
-cpu qemu64,+rdrand \
--append kernel.early-console=ttyS0 -s > /dev/null &
qemu_id=$!
sleep 1.2
$python $validation_script successful-boot $result_file $logfile
result=$?
count=$count+1
if [ $result -eq 0 ]; then
pass=$pass+1
else
mv $result_file "$result_file.FAIL"
fail=$fail+1
lldb \
-o "file kernel/mango_kernel.debug" \
-o "gdb-remote localhost:1234"
fi
kill -INT $qemu_id
log "---------------"
log "Total tests: $count"
log "Pass: $pass"
log "Fail: $fail"
log "---------------"
done

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

@@ -21,6 +21,7 @@ function(add_interface)
add_custom_command( add_custom_command(
OUTPUT ${header_path} OUTPUT ${header_path}
COMMAND ${XPCG} ${arg_PATH} COMMAND ${XPCG} ${arg_PATH}
DEPENDS ${arg_PATH}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${arg_PARENT_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${arg_PARENT_DIR}
COMMENT "Generating interface: ${arg_NAME}") COMMENT "Generating interface: ${arg_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

@@ -1,4 +0,0 @@
interface fs {
msg open(string path, int flags) -> (int err);
msg read(size count) -> (int err, bytebuf data);
}

View File

@@ -6,4 +6,6 @@ func close[1]() -> (err: int);
func read[2](count: size) -> (err: int, nr_read: size, data: buffer); func read[2](count: size) -> (err: int, nr_read: size, 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) -> (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);

2
kernel

Submodule kernel updated: de520cdd2d...110f625f04

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,15 @@
#include <errno.h> #include <errno.h>
#include <mango/log.h>
#include <mango/status.h> #include <mango/status.h>
static int __errno = 32;
int __attribute__((weak)) * __errno_location(void)
{
kern_log("using builtin errno");
return &__errno;
}
#if defined(BUILD_STATIC) #if defined(BUILD_STATIC)
int __set_errno(int err) int __set_errno(int err)
{ {
@@ -12,6 +21,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;
}

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

@@ -9,8 +9,10 @@
#define PROT_READ 0x02u #define PROT_READ 0x02u
#define PROT_WRITE 0x04u #define PROT_WRITE 0x04u
#define MAP_FAILED ((void *)-1)
#define MAP_SHARED 0x01u #define MAP_SHARED 0x01u
#define MAP_SHARED_VALIDATE 0x03u #define MAP_SHARED_VALIDATE 0x02u
#define MAP_PRIVATE 0x04u #define MAP_PRIVATE 0x04u
#define MAP_32BIT 0x08u #define MAP_32BIT 0x08u
#define MAP_ANON MAP_ANONYMOUS #define MAP_ANON MAP_ANONYMOUS
@@ -39,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,10 @@
#ifndef SYS_TYPES_H_
#define SYS_TYPES_H_
#include <mango/types.h>
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#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,6 @@ 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);
#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>
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

@@ -1,6 +1,170 @@
#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> #include <sys/mman.h>
static vm_prot_t vm_prot_from_mmap_prot(int prot)
{
vm_prot_t vm_prot = VM_PROT_USER;
if (prot & PROT_READ) {
vm_prot |= VM_PROT_READ;
}
if (prot & PROT_WRITE) {
vm_prot |= VM_PROT_WRITE;
}
if (prot & PROT_EXEC) {
vm_prot |= VM_PROT_EXEC;
}
return vm_prot;
}
static int get_vmo_anon(
int fd,
int prot,
int flags,
size_t length,
kern_handle_t *out)
{
vm_prot_t vm_prot = vm_prot_from_mmap_prot(prot);
kern_status_t status = vm_object_create(NULL, 0, length, vm_prot, out);
return __errno_from_kern_status(status);
}
static int get_vmo(
int fd,
int prot,
int flags,
size_t length,
kern_handle_t *out)
{
if (fd == -1) {
return get_vmo_anon(fd, prot, flags, length, out);
}
int err = 0;
kern_status_t status = fs_map(fd, prot, flags, &err, out);
if (status != KERN_OK) {
return __errno_from_kern_status(status);
}
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)
{ {
return NULL; int tmp = 0;
if (flags & MAP_SHARED) {
tmp++;
}
if (flags & MAP_SHARED_VALIDATE) {
tmp++;
}
if (flags & MAP_PRIVATE) {
tmp++;
}
if (tmp != 1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
if ((flags & MAP_ANONYMOUS) && fd != -1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
if (!(flags & MAP_ANONYMOUS) && fd == -1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
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) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
status = task_get_address_space(self, &address_space);
kern_handle_close(self);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
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;
int err = get_vmo(fd, prot, flags, length, &vmo);
if (err != SUCCESS) {
kern_handle_close(address_space);
__set_errno(err);
return MAP_FAILED;
}
virt_addr_t map_address = 0;
vm_prot_t vm_prot = vm_prot_from_mmap_prot(prot);
if (addr && (flags & MAP_FIXED)) {
status = address_space_map(
address_space,
(virt_addr_t)addr,
vmo,
offset,
length,
vm_prot,
&map_address);
} else {
status = address_space_map(
address_space,
MAP_ADDRESS_ANY,
vmo,
offset,
length,
vm_prot,
&map_address);
}
kern_handle_close(vmo);
kern_handle_close(address_space);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
return (void *)map_address;
} }

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

@@ -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

@@ -38,14 +38,10 @@ static kern_status_t init_heap_region(heap_t *heap)
task_get_address_space(self, &address_space); task_get_address_space(self, &address_space);
kern_handle_close(self); kern_handle_close(self);
kern_status_t status = vm_region_create( kern_status_t status = address_space_reserve(
address_space, address_space,
"libc-heap", MAP_ADDRESS_ANY,
9,
VM_REGION_ANY_OFFSET,
HEAP_REGION_SIZE, HEAP_REGION_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&heap->heap_region,
&heap->heap_base); &heap->heap_base);
kern_handle_close(address_space); kern_handle_close(address_space);
@@ -72,9 +68,14 @@ static kern_status_t expand_heap(heap_t *heap)
virt_addr_t base = 0; virt_addr_t base = 0;
status = vm_region_map_relative( kern_handle_t self, address_space;
heap->heap_region, task_self(&self);
heap->heap_sys_alloc, task_get_address_space(self, &address_space);
kern_handle_close(self);
status = address_space_map(
address_space,
heap->heap_base + heap->heap_sys_alloc,
vmo, vmo,
0, 0,
HEAP_EXPAND_INCREMENT, HEAP_EXPAND_INCREMENT,
@@ -90,7 +91,7 @@ static kern_status_t expand_heap(heap_t *heap)
void *heap_expand(heap_t *heap, size_t size) void *heap_expand(heap_t *heap, size_t size)
{ {
kern_status_t status = KERN_OK; kern_status_t status = KERN_OK;
if (heap->heap_region == KERN_HANDLE_INVALID) { if (!heap->heap_base) {
status = init_heap_region(heap); status = init_heap_region(heap);
} }

View File

@@ -6,7 +6,6 @@ struct liballoc_minor;
#define HEAP_INIT \ #define HEAP_INIT \
{ \ { \
.heap_region = KERN_HANDLE_INVALID, \
.heap_liballoc = { \ .heap_liballoc = { \
.l_pageSize = 4096, \ .l_pageSize = 4096, \
.l_pageCount = 16, \ .l_pageCount = 16, \

View File

@@ -12,7 +12,6 @@ typedef enum heap_result {
} heap_result_t; } heap_result_t;
typedef struct heap { typedef struct heap {
kern_handle_t heap_region;
/* amount of space requested from the heap by the user */ /* amount of space requested from the heap by the user */
size_t heap_req_alloc; size_t heap_req_alloc;
/* amount of space requested from the system by the heap */ /* amount of space requested from the system by the heap */

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,12 @@
#include "pthread.h"
#include <mango/log.h>
#include <pthread.h>
#include <stdio.h>
int *__errno_location(void)
{
struct __pthread *self = pthread_self();
kern_logf("using pthread errno %p", &self->thr_errno);
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

@@ -1,6 +1,7 @@
#include "btree.h" #include "btree.h"
#include "file.h" #include "file.h"
#include "interface.h" #include "interface.h"
#include "mapping.h"
#include <fs/allocator.h> #include <fs/allocator.h>
#include <fs/context.h> #include <fs/context.h>
@@ -8,9 +9,16 @@
#include <fs/inode.h> #include <fs/inode.h>
#include <fs/status.h> #include <fs/status.h>
#include <fs/superblock.h> #include <fs/superblock.h>
#include <mango/handle.h>
#include <mango/log.h> #include <mango/log.h>
#include <mango/object.h>
#include <mango/signal.h>
#include <mango/task.h>
#include <mango/vm.h>
#include <stdio.h> #include <stdio.h>
#define TEMP_OBJECT_SIZE 0x10000
BTREE_DEFINE_SIMPLE_GET(struct fs_file, unsigned long, f_node, f_id, get_file); BTREE_DEFINE_SIMPLE_GET(struct fs_file, unsigned long, f_node, f_id, get_file);
BTREE_DEFINE_SIMPLE_INSERT(struct fs_file, f_node, f_id, put_file); BTREE_DEFINE_SIMPLE_INSERT(struct fs_file, f_node, f_id, put_file);
@@ -18,12 +26,21 @@ struct fs_context {
struct fs_superblock *ctx_sb; struct fs_superblock *ctx_sb;
struct fs_allocator *ctx_alloc; struct fs_allocator *ctx_alloc;
struct btree ctx_filelist; struct btree ctx_filelist;
kern_handle_t ctx_vm_controller;
kern_handle_t ctx_channel;
kern_handle_t ctx_temp_object;
void *ctx_temp_object_buf;
struct fs_vtable ctx_vtable; struct fs_vtable ctx_vtable;
}; };
struct fs_context *fs_context_create(struct fs_allocator *alloc) struct fs_context *fs_context_create(struct fs_allocator *alloc)
{ {
kern_handle_t self, address_space;
task_self(&self);
task_get_address_space(self, &address_space);
kern_handle_close(self);
struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx); struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx);
if (!ctx) { if (!ctx) {
return NULL; return NULL;
@@ -31,10 +48,50 @@ struct fs_context *fs_context_create(struct fs_allocator *alloc)
memset(ctx, 0x0, sizeof *ctx); memset(ctx, 0x0, sizeof *ctx);
kern_status_t status = vm_controller_create(&ctx->ctx_vm_controller);
if (status != KERN_OK) {
fs_free(alloc, ctx);
return NULL;
}
status = vm_object_create(
NULL,
0,
TEMP_OBJECT_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&ctx->ctx_temp_object);
if (status != KERN_OK) {
kern_handle_close(ctx->ctx_vm_controller);
fs_free(alloc, ctx);
return NULL;
}
virt_addr_t temp_buffer;
status = address_space_map(
address_space,
MAP_ADDRESS_ANY,
ctx->ctx_temp_object,
0,
TEMP_OBJECT_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&temp_buffer);
kern_handle_close(address_space);
if (status != KERN_OK) {
kern_handle_close(ctx->ctx_temp_object);
kern_handle_close(ctx->ctx_vm_controller);
fs_free(alloc, ctx);
return NULL;
}
ctx->ctx_temp_object_buf = (void *)temp_buffer;
ctx->ctx_alloc = alloc; ctx->ctx_alloc = alloc;
ctx->ctx_vtable.open = fs_msg_open; ctx->ctx_vtable.open = fs_msg_open;
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.seek = fs_msg_seek;
ctx->ctx_vtable.map = fs_msg_map;
return ctx; return ctx;
} }
@@ -73,6 +130,112 @@ enum fs_status fs_context_unmount_filesystem(struct fs_context *ctx)
return FS_ERR_NOT_IMPLEMENTED; return FS_ERR_NOT_IMPLEMENTED;
} }
void fs_context_set_channel(struct fs_context *ctx, kern_handle_t channel)
{
ctx->ctx_channel = channel;
}
kern_handle_t fs_context_get_vm_controller(const struct fs_context *ctx)
{
return ctx->ctx_vm_controller;
}
static enum fs_status handle_msg(struct fs_context *ctx)
{
xpc_msg_t msg;
kern_status_t status = xpc_msg_recv_nowait(ctx->ctx_channel, &msg);
if (status == KERN_NO_ENTRY) {
return FS_SUCCESS;
}
if (status != KERN_OK) {
kern_tracef("message recv error %d", status);
return FS_ERR_INTERNAL_FAILURE;
}
switch (msg.msg_header.hdr_interface) {
case INTERFACE_FS:
status = fs_context_dispatch_msg(ctx, &msg);
break;
default:
kern_tracef(
"unknown message protocol %u",
msg.msg_header.hdr_interface);
xpc_msg_reply_error(&msg, KERN_UNSUPPORTED);
break;
}
return FS_SUCCESS;
}
static enum fs_status handle_page_request(struct fs_context *ctx)
{
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_tracef(
"received page request [%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) {
length = TEMP_OBJECT_SIZE;
}
char *dst = ctx->ctx_temp_object_buf;
xpc_buffer_t buf = XPC_LOCAL_BUFFER_OUT(dst, TEMP_OBJECT_SIZE);
enum fs_status status = fs_file_read_at(
mapping->m_file,
&buf,
packet.req_offset,
length);
if (status != FS_SUCCESS) {
kern_tracef("map-read failed with code %d", status);
return status;
}
vm_controller_supply_pages(
ctx->ctx_vm_controller,
mapping->m_vmo,
packet.req_offset,
ctx->ctx_temp_object,
0,
packet.req_length);
return FS_SUCCESS;
}
enum fs_status fs_context_handle_request(struct fs_context *ctx)
{
kern_wait_item_t waiters[] = {
{
.w_handle = ctx->ctx_channel,
.w_waitfor = CHANNEL_SIGNAL_MSG_RECEIVED,
},
{
.w_handle = ctx->ctx_vm_controller,
.w_waitfor = VM_CONTROLLER_SIGNAL_REQUEST_RECEIVED,
},
};
const size_t nr_waiters = sizeof waiters / sizeof waiters[0];
kern_status_t kstatus = kern_object_wait(waiters, nr_waiters);
if (kstatus != KERN_OK) {
return FS_ERR_INTERNAL_FAILURE;
}
if (waiters[0].w_observed & CHANNEL_SIGNAL_MSG_RECEIVED) {
return handle_msg(ctx);
}
if (waiters[1].w_observed & VM_CONTROLLER_SIGNAL_REQUEST_RECEIVED) {
return handle_page_request(ctx);
}
return FS_SUCCESS;
}
struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id) struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id)
{ {
struct fs_file *f = get_file(&ctx->ctx_filelist, id); struct fs_file *f = get_file(&ctx->ctx_filelist, id);

View File

@@ -25,9 +25,22 @@ enum fs_status fs_file_read(
return status; return status;
} }
enum fs_status fs_file_write( enum fs_status fs_file_read_at(
struct fs_file *f, struct fs_file *f,
struct xpc_buffer *buf, struct xpc_buffer *buf,
off_t offset,
size_t count)
{
if (!f->f_ops || !f->f_ops->f_read) {
return FS_ERR_NOT_IMPLEMENTED;
}
return f->f_ops->f_read(f, buf, count, &offset);
}
enum fs_status fs_file_write(
struct fs_file *f,
const struct xpc_buffer *buf,
size_t count) size_t count)
{ {
if (!f->f_ops || !f->f_ops->f_write) { if (!f->f_ops || !f->f_ops->f_write) {

View File

@@ -2,6 +2,7 @@
#define _FS_FILE_H_ #define _FS_FILE_H_
#include "btree.h" #include "btree.h"
#include "queue.h"
#include <fs/dentry.h> #include <fs/dentry.h>
#include <fs/file.h> #include <fs/file.h>
@@ -18,6 +19,8 @@ struct fs_file {
off_t f_seek; off_t f_seek;
struct fs_inode *f_inode; struct fs_inode *f_inode;
struct fs_dentry *f_dent; struct fs_dentry *f_dent;
struct queue f_mappings;
}; };
#endif #endif

View File

@@ -30,6 +30,12 @@ extern enum fs_status fs_context_mount_filesystem(
enum fs_mount_flags flags); enum fs_mount_flags flags);
extern enum fs_status fs_context_unmount_filesystem(struct fs_context *ctx); extern enum fs_status fs_context_unmount_filesystem(struct fs_context *ctx);
extern void fs_context_set_channel(
struct fs_context *ctx,
kern_handle_t channel);
extern kern_handle_t fs_context_get_vm_controller(const struct fs_context *ctx);
extern enum fs_status fs_context_handle_request(struct fs_context *ctx);
extern struct fs_file *fs_context_open_file( extern struct fs_file *fs_context_open_file(
struct fs_context *ctx, struct fs_context *ctx,
unsigned long id); unsigned long id);

View File

@@ -27,9 +27,14 @@ extern enum fs_status fs_file_read(
struct fs_file *f, struct fs_file *f,
struct xpc_buffer *buf, struct xpc_buffer *buf,
size_t count); size_t count);
extern enum fs_status fs_file_write( extern enum fs_status fs_file_read_at(
struct fs_file *f, struct fs_file *f,
struct xpc_buffer *buf, struct xpc_buffer *buf,
off_t offset,
size_t count);
extern enum fs_status fs_file_write(
struct fs_file *f,
const struct xpc_buffer *buf,
size_t count); size_t count);
#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

@@ -17,9 +17,8 @@ extern kern_status_t fs_msg_open(
int *out_err, int *out_err,
void *arg); void *arg);
extern kern_status_t fs_msg_close( extern kern_status_t fs_msg_close(
const struct msg_endpoint *sender, xpc_context_t *ctx,
const char *path, const xpc_endpoint_t *sender,
int flags,
int *out_err, int *out_err,
void *arg); void *arg);
@@ -31,5 +30,29 @@ extern kern_status_t fs_msg_read(
size_t *out_nr_read, 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(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
const xpc_buffer_t *data,
int *out_err,
size_t *out_nr_written,
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(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
int prot,
int flags,
int *out_err,
kern_handle_t *out_vmo,
void *arg);
#endif #endif

View File

@@ -0,0 +1,14 @@
#include "../interface.h"
#include <errno.h>
#include <mango/status.h>
extern kern_status_t fs_msg_close(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
int *out_err,
void *arg)
{
*out_err = ENOSYS;
return KERN_OK;
}

112
lib/libfs/interface/map.c Normal file
View File

@@ -0,0 +1,112 @@
#include "../file.h"
#include "../mapping.h"
#include <errno.h>
#include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
#include <mango/handle.h>
#include <mango/log.h>
#include <mango/vm.h>
#include <stdio.h>
#include <sys/mman.h>
static int create_file_mapping(
struct fs_context *ctx,
int prot,
int flags,
struct fs_file *f,
struct file_mapping **out)
{
if ((flags & MAP_SHARED) && f->f_inode->i_shared_mapping) {
*out = f->f_inode->i_shared_mapping;
return SUCCESS;
}
struct file_mapping *mapping = fs_context_alloc(ctx, sizeof *mapping);
if (!mapping) {
return ENOMEM;
}
memset(mapping, 0x0, sizeof *mapping);
vm_prot_t vm_prot = VM_PROT_USER;
if (prot & PROT_READ) {
vm_prot |= VM_PROT_READ;
}
if (prot & PROT_WRITE) {
vm_prot |= VM_PROT_WRITE;
}
if (prot & PROT_EXEC) {
vm_prot |= VM_PROT_EXEC;
}
kern_handle_t vmo = KERN_HANDLE_INVALID;
kern_status_t status = vm_controller_create_object(
fs_context_get_vm_controller(ctx),
f->f_dent->d_name,
strlen(f->f_dent->d_name),
(equeue_key_t)mapping,
f->f_inode->i_size,
vm_prot,
&vmo);
if (status != KERN_OK) {
fs_context_free(ctx, mapping);
return __errno_from_kern_status(status);
}
mapping->m_file = f;
mapping->m_vmo = vmo;
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);
*out_err = SUCCESS;
*out_vmo = vmo;
return KERN_OK;
}

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,7 +41,7 @@ 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;
} }

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

@@ -0,0 +1,29 @@
#include <errno.h>
#include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
extern kern_status_t fs_msg_write(
xpc_context_t *xpc,
const xpc_endpoint_t *sender,
const xpc_buffer_t *data,
int *out_err,
size_t *out_nr_written,
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;
}
size_t start = fs_file_get_cursor(f);
enum fs_status status = fs_file_write(f, data, data->buf_len);
size_t end = fs_file_get_cursor(f);
*out_err = fs_status_to_errno(status);
*out_nr_written = end - start;
return KERN_OK;
}

22
lib/libfs/mapping.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef MAPPING_H_
#define MAPPING_H_
#include "queue.h"
#include <mango/types.h>
struct fs_file;
enum file_mapping_type {
FILE_MAPPING_PRIVATE,
FILE_MAPPING_SHARED,
};
struct file_mapping {
enum file_mapping_type m_type;
struct fs_file *m_file;
kern_handle_t m_vmo;
struct queue_entry m_entry;
};
#endif

138
lib/libfs/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
lib/libfs/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

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

@@ -160,15 +160,10 @@ static kern_status_t create_exec_regions(struct elf_image *image)
image->e_total_size); image->e_total_size);
kern_status_t status = KERN_OK; kern_status_t status = KERN_OK;
if (image->e_local_space != KERN_HANDLE_INVALID) { if (image->e_local_space != KERN_HANDLE_INVALID) {
status = vm_region_create( status = address_space_reserve(
image->e_local_space, image->e_local_space,
NULL, MAP_ADDRESS_ANY,
0,
VM_REGION_ANY_OFFSET,
image->e_total_size, image->e_total_size,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC
| VM_PROT_USER,
&image->e_local_exec,
&image->e_local_base); &image->e_local_base);
} }
@@ -177,22 +172,18 @@ static kern_status_t create_exec_regions(struct elf_image *image)
} }
if (image->e_remote_space != KERN_HANDLE_INVALID) { if (image->e_remote_space != KERN_HANDLE_INVALID) {
status = vm_region_create( status = address_space_reserve(
image->e_remote_space, image->e_remote_space,
NULL, MAP_ADDRESS_ANY,
0,
VM_REGION_ANY_OFFSET,
image->e_total_size, image->e_total_size,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC
| VM_PROT_USER,
&image->e_remote_exec,
&image->e_remote_base); &image->e_remote_base);
} }
if (status != KERN_OK) { if (status != KERN_OK) {
vm_region_kill(image->e_local_exec); address_space_release(
kern_handle_close(image->e_local_exec); image->e_local_space,
image->e_local_exec = KERN_HANDLE_INVALID; image->e_local_base,
image->e_total_size);
return status; return status;
} }
@@ -200,6 +191,19 @@ static kern_status_t create_exec_regions(struct elf_image *image)
return KERN_OK; return KERN_OK;
} }
static kern_status_t release_exec_regions(struct elf_image *image)
{
address_space_release(
image->e_local_space,
image->e_local_base,
image->e_total_size);
address_space_release(
image->e_remote_space,
image->e_remote_base,
image->e_total_size);
return KERN_OK;
}
static enum launch_status map_executable(struct elf_image *image) static enum launch_status map_executable(struct elf_image *image)
{ {
elf_phdr_t phdr; elf_phdr_t phdr;
@@ -256,10 +260,10 @@ static enum launch_status map_executable(struct elf_image *image)
return LAUNCH_ERR_IMAGE_DATA_LOAD_FAILED; return LAUNCH_ERR_IMAGE_DATA_LOAD_FAILED;
} }
if (image->e_local_exec != KERN_HANDLE_INVALID) { if (image->e_local_space != KERN_HANDLE_INVALID) {
status = vm_region_map_relative( status = address_space_map(
image->e_local_exec, image->e_local_space,
phdr.p_vaddr, image->e_local_base + phdr.p_vaddr,
vmo, vmo,
offset, offset,
phdr.p_memsz, phdr.p_memsz,
@@ -271,10 +275,10 @@ static enum launch_status map_executable(struct elf_image *image)
return LAUNCH_ERR_MEMORY_MAP_FAILED; return LAUNCH_ERR_MEMORY_MAP_FAILED;
} }
if (image->e_remote_exec != KERN_HANDLE_INVALID) { if (image->e_remote_space != KERN_HANDLE_INVALID) {
status = vm_region_map_relative( status = address_space_map(
image->e_remote_exec, image->e_remote_space,
phdr.p_vaddr, image->e_remote_base + phdr.p_vaddr,
vmo, vmo,
offset, offset,
phdr.p_memsz, phdr.p_memsz,
@@ -330,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;
@@ -499,8 +525,6 @@ void elf_image_init(struct elf_image *out)
out->e_data = KERN_HANDLE_INVALID; out->e_data = KERN_HANDLE_INVALID;
out->e_local_space = KERN_HANDLE_INVALID; out->e_local_space = KERN_HANDLE_INVALID;
out->e_remote_space = KERN_HANDLE_INVALID; out->e_remote_space = KERN_HANDLE_INVALID;
out->e_local_exec = KERN_HANDLE_INVALID;
out->e_remote_exec = KERN_HANDLE_INVALID;
} }
enum launch_status elf_image_load( enum launch_status elf_image_load(
@@ -547,6 +571,11 @@ enum launch_status elf_image_load(
return status; return status;
} }
status = release_exec_regions(image);
if (status != KERN_OK) {
return status;
}
status = relocate(image); status = relocate(image);
if (status != LAUNCH_OK) { if (status != LAUNCH_OK) {
return status; return status;
@@ -557,9 +586,9 @@ enum launch_status elf_image_load(
void elf_image_cleanup(struct elf_image *image) void elf_image_cleanup(struct elf_image *image)
{ {
vm_region_unmap_relative(image->e_local_exec, 0, image->e_total_size); address_space_unmap(
image->e_local_space,
image->e_local_base,
image->e_total_size);
kern_handle_close(image->e_data); kern_handle_close(image->e_data);
vm_region_kill(image->e_local_exec);
kern_handle_close(image->e_local_exec);
kern_handle_close(image->e_remote_exec);
} }

View File

@@ -292,7 +292,6 @@ struct elf_image {
size_t e_page_size; size_t e_page_size;
kern_handle_t e_image, e_data; kern_handle_t e_image, e_data;
kern_handle_t e_local_space, e_remote_space; kern_handle_t e_local_space, e_remote_space;
kern_handle_t e_local_exec, e_remote_exec;
virt_addr_t e_local_base, e_remote_base; virt_addr_t e_local_base, e_remote_base;
elf_ehdr_t e_hdr; elf_ehdr_t e_hdr;
elf_phdr_t e_dynamic; elf_phdr_t e_dynamic;

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,
@@ -157,17 +177,17 @@ enum launch_status launch_ctx_execute(
} }
virt_addr_t remote_stack_buf, local_stack_buf; virt_addr_t remote_stack_buf, local_stack_buf;
kstatus = vm_region_map_relative( kstatus = address_space_map(
remote_address_space, remote_address_space,
VM_REGION_ANY_OFFSET, MAP_ADDRESS_ANY,
stack_vmo, stack_vmo,
0, 0,
STACK_SIZE, STACK_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&remote_stack_buf); &remote_stack_buf);
kstatus = vm_region_map_relative( kstatus = address_space_map(
params->p_local_address_space, params->p_local_address_space,
VM_REGION_ANY_OFFSET, MAP_ADDRESS_ANY,
stack_vmo, stack_vmo,
0, 0,
STACK_SIZE, STACK_SIZE,
@@ -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

@@ -1,4 +1,5 @@
#include <mango/status.h> #include <mango/status.h>
#include <string.h>
#include <xpc/buffer.h> #include <xpc/buffer.h>
#include <xpc/msg.h> #include <xpc/msg.h>
@@ -36,8 +37,7 @@ kern_status_t xpc_buffer_write(
size_t len, size_t len,
size_t *nr_written) size_t *nr_written)
{ {
if ((buf->buf_flags & (XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE)) if (!(buf->buf_flags & XPC_BUFFER_F_OUT)) {
!= (XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE)) {
return KERN_BAD_STATE; return KERN_BAD_STATE;
} }
@@ -46,14 +46,16 @@ kern_status_t xpc_buffer_write(
to_write = buf->buf_max; to_write = buf->buf_max;
} }
kern_status_t status if (!(buf->buf_flags & XPC_BUFFER_F_REMOTE)) {
= xpc_msg_write(buf->buf_origin, buf->buf_offset, in, to_write); memcpy(buf->buf_ptr, in, to_write);
if (status != KERN_OK) { *nr_written = to_write;
return status; return KERN_OK;
} }
/* TODO */ return xpc_msg_write(
*nr_written = to_write; buf->buf_origin,
buf->buf_offset,
return KERN_OK; in,
to_write,
nr_written);
} }

View File

@@ -16,7 +16,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) \
{ \
.buf_flags = XPC_BUFFER_F_OUT, \
.buf_ptr = (ptr), \
.buf_max = (size), \
} }
struct xpc_msg; struct xpc_msg;
@@ -39,9 +45,6 @@ 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 {
/* fields that are only valid if F_OUT is set */
struct {
/* only valid if F_OUT is set. specifies the maximum /* only valid if F_OUT is set. specifies the maximum
* number of chars that can be written to buf_buf, * number of chars that can be written to buf_buf,
* including the null terminator. */ * including the null terminator. */
@@ -49,17 +52,11 @@ typedef struct xpc_buffer {
/* only valid if F_OUT is set. /* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or * if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */ * allocated via xpc_context_alloc */
const char *buf_ptr; void *buf_ptr;
}; /* valid for F_IN and F_OUT. offset of the buffer data
/* 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 * within the associated message. used when reading
* buffer data from a message. */ * buffer data from a message. */
size_t buf_offset; 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

View File

@@ -29,6 +29,7 @@ extern void xpc_msg_header_init(
unsigned short func); unsigned short func);
extern bool xpc_msg_header_validate(const xpc_msg_header_t *msg); extern bool xpc_msg_header_validate(const xpc_msg_header_t *msg);
extern kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out); extern kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out);
extern kern_status_t xpc_msg_recv_nowait(kern_handle_t channel, xpc_msg_t *out);
extern kern_status_t xpc_msg_read( extern kern_status_t xpc_msg_read(
const xpc_msg_t *msg, const xpc_msg_t *msg,
size_t offset, size_t offset,
@@ -38,7 +39,8 @@ 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_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,8 +41,6 @@ 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 {
struct {
/* only valid if F_OUT is set. specifies the maximum /* only valid if F_OUT is set. specifies the maximum
* number of chars that can be written to s_buf, * number of chars that can be written to s_buf,
* including the null terminator. */ * including the null terminator. */
@@ -51,15 +49,11 @@ typedef struct xpc_string {
* if F_FREE_ON_DISCARD is set, must be either NULL or * if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */ * allocated via xpc_context_alloc */
const char *s_buf; 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

@@ -1,4 +1,6 @@
#include <mango/msg.h> #include <mango/msg.h>
#include <mango/object.h>
#include <mango/signal.h>
#include <string.h> #include <string.h>
#include <xpc/msg.h> #include <xpc/msg.h>
@@ -20,8 +22,25 @@ bool xpc_msg_header_validate(const xpc_msg_header_t *msg)
return msg->hdr_magic == XPC_MSG_MAGIC; return msg->hdr_magic == XPC_MSG_MAGIC;
} }
kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out) static kern_status_t __msg_recv(
kern_handle_t channel,
xpc_msg_t *out,
bool nowait)
{ {
kern_status_t status = KERN_OK;
if (!nowait) {
kern_wait_item_t wait = {
.w_handle = channel,
.w_waitfor = CHANNEL_SIGNAL_MSG_RECEIVED,
};
status = kern_object_wait(&wait, 1);
if (status != KERN_OK) {
return status;
}
}
kern_iovec_t iov = IOVEC(&out->msg_header, sizeof out->msg_header); kern_iovec_t iov = IOVEC(&out->msg_header, sizeof out->msg_header);
kern_msg_t msg = { kern_msg_t msg = {
.msg_data = &iov, .msg_data = &iov,
@@ -29,7 +48,8 @@ kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out)
.msg_handles = out->msg_handles, .msg_handles = out->msg_handles,
.msg_handles_count = KERN_MSG_MAX_HANDLES, .msg_handles_count = KERN_MSG_MAX_HANDLES,
}; };
kern_status_t status = msg_recv(channel, &msg);
status = msg_recv(channel, &msg);
if (status != KERN_OK) { if (status != KERN_OK) {
return status; return status;
} }
@@ -46,6 +66,25 @@ kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out)
return KERN_OK; return KERN_OK;
} }
kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out)
{
kern_status_t status = KERN_OK;
while (1) {
status = __msg_recv(channel, out, false);
if (status != KERN_NO_ENTRY) {
break;
}
}
return status;
}
kern_status_t xpc_msg_recv_nowait(kern_handle_t channel, xpc_msg_t *out)
{
return __msg_recv(channel, out, true);
}
kern_status_t xpc_msg_read( kern_status_t xpc_msg_read(
const xpc_msg_t *msg, const xpc_msg_t *msg,
size_t offset, size_t offset,
@@ -67,17 +106,17 @@ 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_reply( kern_status_t xpc_msg_reply(

View File

@@ -47,14 +47,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)

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

@@ -0,0 +1,43 @@
#include <errno.h>
#include <mango/log.h>
#include <pthread.h>
#include <stdio.h>
#include <string.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[])
{
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;
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);
kern_logf("errno...");
kern_logf("%u", errno);
kern_logf("...errno");
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 = {
@@ -185,17 +190,20 @@ int main(
return -1; return -1;
} }
fs_context_set_channel(fs, channel);
enum fs_status fs_status = fs_context_mount_filesystem( enum fs_status fs_status = fs_context_mount_filesystem(
fs, fs,
tar_mount, tar_mount,
(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);
#if 0
xpc_msg_t msg; xpc_msg_t msg;
kern_status_t status = xpc_msg_recv(channel, &msg); kern_status_t status = xpc_msg_recv(channel, &msg);
if (status != KERN_OK) { if (status != KERN_OK) {
@@ -219,6 +227,7 @@ int main(
kern_logf("message reply error %d", status); kern_logf("message reply error %d", status);
continue; continue;
} }
#endif
} }
return 0; return 0;

View File

@@ -74,8 +74,10 @@ int tar_open(struct tar *tar, const char *path, struct tar_file *out)
} }
s += header.size; s += header.size;
if ((uintptr_t)s % (sizeof *bin_header)) {
s += ((sizeof *bin_header) s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header))); - ((uintptr_t)s % (sizeof *bin_header)));
}
bin_header = (struct tar_bin_header *)s; bin_header = (struct tar_bin_header *)s;
} }
@@ -189,7 +191,7 @@ static enum fs_status file_read(
size_t w; size_t w;
xpc_buffer_write(buf, src, count, &w); xpc_buffer_write(buf, src, count, &w);
offset += count; offset += w;
*seek = offset; *seek = offset;
return FS_SUCCESS; return FS_SUCCESS;
@@ -382,8 +384,10 @@ static enum fs_status build_dentry_tree(
} }
s += header.size; s += header.size;
if ((uintptr_t)s % (sizeof *bin_header)) {
s += ((sizeof *bin_header) s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header))); - ((uintptr_t)s % (sizeof *bin_header)));
}
bin_header = (struct tar_bin_header *)s; bin_header = (struct tar_bin_header *)s;
} }

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;
}

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