Compare commits

..

55 Commits

Author SHA1 Message Date
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
99 changed files with 5458 additions and 719 deletions

View File

@@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 3.14)
project(Rosetta C CXX ASM)
include(CheckPIESupported)
check_pie_supported()
set(sys_dir ${CMAKE_CURRENT_BINARY_DIR}/sys)
set(kernel_name mango_kernel)

View File

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

View File

@@ -16,6 +16,11 @@ 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_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_C_LINK_OPTIONS_PIE "-pie")
set(CMAKE_C_LINK_PIE_SUPPORTED TRUE)
set(CMAKE_C_LINK_NO_PIE_SUPPORTED TRUE)
set(CMAKE_C_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)
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)
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

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

View File

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

View File

@@ -28,3 +28,5 @@ bsp_add_library(
target_link_libraries(libc libmango libxpc-static interface::fs)
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1)
add_subdirectory(pthread)

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

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 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 *memcpy(void *dst, const void *src, size_t len);

View File

@@ -9,8 +9,10 @@
#define PROT_READ 0x02u
#define PROT_WRITE 0x04u
#define MAP_FAILED ((void *)-1)
#define MAP_SHARED 0x01u
#define MAP_SHARED_VALIDATE 0x03u
#define MAP_SHARED_VALIDATE 0x02u
#define MAP_PRIVATE 0x04u
#define MAP_32BIT 0x08u
#define MAP_ANON MAP_ANONYMOUS
@@ -39,5 +41,6 @@ extern void *mmap(
int flags,
int fd,
off_t offset);
extern int munmap(void *addr, size_t length);
#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_
#include <stddef.h>
#include <sys/types.h>
extern int open(const char *path, int flags);
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 write(int fd, const void *buf, size_t count);
extern off_t lseek(int fd, off_t offset, int whence);
#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>
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)
{
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
LIB_DIR /usr/lib)
target_compile_definitions(libc-malloc PRIVATE ENABLE_GLOBAL_HEAP=1)
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);
kern_handle_close(self);
kern_status_t status = vm_region_create(
kern_status_t status = address_space_reserve(
address_space,
"libc-heap",
9,
VM_REGION_ANY_OFFSET,
MAP_ADDRESS_ANY,
HEAP_REGION_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&heap->heap_region,
&heap->heap_base);
kern_handle_close(address_space);
@@ -72,9 +68,14 @@ static kern_status_t expand_heap(heap_t *heap)
virt_addr_t base = 0;
status = vm_region_map_relative(
heap->heap_region,
heap->heap_sys_alloc,
kern_handle_t self, address_space;
task_self(&self);
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,
0,
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)
{
kern_status_t status = KERN_OK;
if (heap->heap_region == KERN_HANDLE_INVALID) {
if (!heap->heap_base) {
status = init_heap_region(heap);
}

View File

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

View File

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

View File

@@ -0,0 +1,42 @@
set(source_dirs thread)
foreach (dir ${source_dirs})
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
set(sources ${sources} ${dir_sources})
set(headers ${headers} ${dir_headers})
endforeach (dir)
file(GLOB sys_sources
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.c
${CMAKE_CURRENT_SOURCE_DIR}/sys/${CMAKE_SYSTEM_PROCESSOR}/*.S)
set_property(SOURCE ${sys_sources} PROPERTY LANGUAGE C)
set(sources ${sources} ${sys_sources})
set(headers ${headers} ${CMAKE_CURRENT_SOURCE_DIR}/include/pthread.h)
set(public_include_dir ${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(STATIC
NAME libc-pthread
PUBLIC_INCLUDE_DIRS ${public_include_dir}
SOURCES ${sources}
HEADERS ${headers})
rosetta_add_library(SHARED
NAME libpthread
PUBLIC_INCLUDE_DIRS ${public_include_dir}
SOURCES ${sources}
HEADERS ${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)
target_link_libraries(libc-pthread libc-io libmango)
target_link_libraries(libpthread libmango 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,24 @@
#ifndef _THREAD_PTHREAD_H_
#define _THREAD_PTHREAD_H_
#include <mango/types.h>
enum pthread_flags {
THREAD_DETACHED = 0x01u,
};
struct __pthread {
struct __pthread *thr_self;
enum pthread_flags thr_flags;
kern_handle_t thr_handle;
void *thr_map_base;
size_t thr_map_size;
void *thr_result;
};
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

View File

@@ -6,6 +6,9 @@
.extern main
.type main, @function
.extern task_exit
.type task_exit, @function
_start:
# Args (as provided by the ABI)
# %rdi: int argc
@@ -13,4 +16,7 @@ _start:
# %rdx: kern_handle_t task
# %rcx: kern_handle_t address_space
call main
mov %rax, %rdi
call task_exit
1: jmp 1b

View File

@@ -1,6 +1,7 @@
#include "btree.h"
#include "file.h"
#include "interface.h"
#include "mapping.h"
#include <fs/allocator.h>
#include <fs/context.h>
@@ -8,9 +9,16 @@
#include <fs/inode.h>
#include <fs/status.h>
#include <fs/superblock.h>
#include <mango/handle.h>
#include <mango/log.h>
#include <mango/object.h>
#include <mango/signal.h>
#include <mango/task.h>
#include <mango/vm.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_INSERT(struct fs_file, f_node, f_id, put_file);
@@ -18,12 +26,21 @@ struct fs_context {
struct fs_superblock *ctx_sb;
struct fs_allocator *ctx_alloc;
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_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);
if (!ctx) {
return NULL;
@@ -31,10 +48,50 @@ struct fs_context *fs_context_create(struct fs_allocator *alloc)
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_vtable.open = fs_msg_open;
ctx->ctx_vtable.close = fs_msg_close;
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;
}
@@ -73,6 +130,112 @@ enum fs_status fs_context_unmount_filesystem(struct fs_context *ctx)
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 *f = get_file(&ctx->ctx_filelist, id);

View File

@@ -25,9 +25,22 @@ enum fs_status fs_file_read(
return status;
}
enum fs_status fs_file_write(
enum fs_status fs_file_read_at(
struct fs_file *f,
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)
{
if (!f->f_ops || !f->f_ops->f_write) {

View File

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

View File

@@ -30,6 +30,12 @@ extern enum fs_status fs_context_mount_filesystem(
enum fs_mount_flags flags);
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(
struct fs_context *ctx,
unsigned long id);

View File

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

View File

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

View File

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

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

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

@@ -160,15 +160,10 @@ static kern_status_t create_exec_regions(struct elf_image *image)
image->e_total_size);
kern_status_t status = KERN_OK;
if (image->e_local_space != KERN_HANDLE_INVALID) {
status = vm_region_create(
status = address_space_reserve(
image->e_local_space,
NULL,
0,
VM_REGION_ANY_OFFSET,
MAP_ADDRESS_ANY,
image->e_total_size,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC
| VM_PROT_USER,
&image->e_local_exec,
&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) {
status = vm_region_create(
status = address_space_reserve(
image->e_remote_space,
NULL,
0,
VM_REGION_ANY_OFFSET,
MAP_ADDRESS_ANY,
image->e_total_size,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC
| VM_PROT_USER,
&image->e_remote_exec,
&image->e_remote_base);
}
if (status != KERN_OK) {
vm_region_kill(image->e_local_exec);
kern_handle_close(image->e_local_exec);
image->e_local_exec = KERN_HANDLE_INVALID;
address_space_release(
image->e_local_space,
image->e_local_base,
image->e_total_size);
return status;
}
@@ -200,6 +191,19 @@ static kern_status_t create_exec_regions(struct elf_image *image)
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)
{
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;
}
if (image->e_local_exec != KERN_HANDLE_INVALID) {
status = vm_region_map_relative(
image->e_local_exec,
phdr.p_vaddr,
if (image->e_local_space != KERN_HANDLE_INVALID) {
status = address_space_map(
image->e_local_space,
image->e_local_base + phdr.p_vaddr,
vmo,
offset,
phdr.p_memsz,
@@ -271,10 +275,10 @@ static enum launch_status map_executable(struct elf_image *image)
return LAUNCH_ERR_MEMORY_MAP_FAILED;
}
if (image->e_remote_exec != KERN_HANDLE_INVALID) {
status = vm_region_map_relative(
image->e_remote_exec,
phdr.p_vaddr,
if (image->e_remote_space != KERN_HANDLE_INVALID) {
status = address_space_map(
image->e_remote_space,
image->e_remote_base + phdr.p_vaddr,
vmo,
offset,
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),
rela->r_addend);
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:
kern_trace("Unknown relocation type");
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_local_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(
@@ -547,6 +571,11 @@ enum launch_status elf_image_load(
return status;
}
status = release_exec_regions(image);
if (status != KERN_OK) {
return status;
}
status = relocate(image);
if (status != LAUNCH_OK) {
return status;
@@ -557,9 +586,9 @@ enum launch_status elf_image_load(
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);
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;
kern_handle_t e_image, e_data;
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;
elf_ehdr_t e_hdr;
elf_phdr_t e_dynamic;

View File

@@ -45,7 +45,9 @@ struct launch_ctx {
struct launch_parameters {
kern_handle_t p_parent_task;
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;

View File

@@ -38,6 +38,7 @@ static kern_handle_t get_library(
static virt_addr_t write_bootstrap_data(
struct stack_writer *stack,
const char *interpreter,
const struct launch_parameters *params)
{
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_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;
if (bs->bs_argc > 0) {
int argc = bs->bs_argc;
virt_addr_t remote_argv;
argv = stack_writer_put(
stack,
@@ -73,13 +80,22 @@ static virt_addr_t write_bootstrap_data(
bs->bs_envp = (const char **)remote_envp;
}
for (size_t i = 0; i < params->p_argc; i++) {
size_t i = 0, j = 0;
if (interpreter) {
virt_addr_t arg_ptr;
stack_writer_put_string(stack, params->p_argv[i], &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 (; i < bs->bs_argc; i++, j++) {
virt_addr_t arg_ptr;
stack_writer_put_string(stack, params->p_argv[j], &arg_ptr);
argv[i] = (const char *)arg_ptr;
}
for (size_t i = 0; i < params->p_envc; i++) {
for (size_t i = 0; i < bs->bs_envc; i++) {
virt_addr_t env_ptr;
stack_writer_put_string(stack, params->p_envp[i], &env_ptr);
envp[i] = (const char *)env_ptr;
@@ -118,16 +134,20 @@ enum launch_status launch_ctx_execute(
return LAUNCH_ERR_TASK_CREATION_FAILED;
}
char interp_path[4096];
interp_path[0] = 0;
struct elf_image image;
elf_image_init(&image);
enum launch_status status = elf_image_load(
&image,
params->p_executable,
params->p_exec_image,
params->p_local_address_space,
remote_address_space);
if (status == LAUNCH_ERR_INTERPRETER_REQUIRED) {
snprintf(interp_path, sizeof interp_path, "%s", image.e_interp);
kern_handle_t interp = get_library(
ctx,
image.e_interp,
@@ -157,17 +177,17 @@ enum launch_status launch_ctx_execute(
}
virt_addr_t remote_stack_buf, local_stack_buf;
kstatus = vm_region_map_relative(
kstatus = address_space_map(
remote_address_space,
VM_REGION_ANY_OFFSET,
MAP_ADDRESS_ANY,
stack_vmo,
0,
STACK_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&remote_stack_buf);
kstatus = vm_region_map_relative(
kstatus = address_space_map(
params->p_local_address_space,
VM_REGION_ANY_OFFSET,
MAP_ADDRESS_ANY,
stack_vmo,
0,
STACK_SIZE,
@@ -187,7 +207,7 @@ enum launch_status launch_ctx_execute(
&stack,
local_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;
@@ -208,7 +228,10 @@ enum launch_status launch_ctx_execute(
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);
return LAUNCH_OK;

View File

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

View File

@@ -16,7 +16,13 @@
.buf_flags = XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE, \
.buf_origin = (msg), \
.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;
@@ -39,27 +45,18 @@ typedef enum xpc_buffer_flags {
typedef struct xpc_buffer {
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
* number of chars that can be written to buf_buf,
* including the null terminator. */
size_t buf_max;
/* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */
const char *buf_ptr;
};
/* fields that are only valid if F_IN is set */
struct {
/* only valid if F_IN is set. offset of the buffer data
* within the associated message. used when reading
* buffer data from a message. */
size_t buf_offset;
};
};
/* only valid if F_OUT is set. specifies the maximum
* number of chars that can be written to buf_buf,
* including the null terminator. */
size_t buf_max;
/* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */
void *buf_ptr;
/* valid for F_IN and F_OUT. offset of the buffer data
* within the associated message. used when reading
* buffer data from a message. */
size_t buf_offset;
/* only valid if F_REMOTE is set.
* 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);
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_nowait(kern_handle_t channel, xpc_msg_t *out);
extern kern_status_t xpc_msg_read(
const xpc_msg_t *msg,
size_t offset,
@@ -38,7 +39,8 @@ extern kern_status_t xpc_msg_write(
const xpc_msg_t *msg,
size_t offset,
const void *p,
size_t count);
size_t count,
size_t *nr_written);
extern kern_status_t xpc_msg_reply(
const xpc_msg_t *msg,

View File

@@ -18,7 +18,7 @@
.s_flags = XPC_STRING_F_OUT | XPC_STRING_F_REMOTE, \
.s_origin = (msg), \
.s_offset = (offset), \
.s_len = (size), \
.s_max = (size), \
}
struct xpc_msg;
@@ -41,25 +41,19 @@ typedef enum xpc_string_flags {
typedef struct xpc_string {
xpc_string_flags_t s_flags;
union {
struct {
/* only valid if F_OUT is set. specifies the maximum
* number of chars that can be written to s_buf,
* including the null terminator. */
size_t s_max;
/* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */
const char *s_buf;
};
/* only valid if F_OUT is set. specifies the maximum
* number of chars that can be written to s_buf,
* including the null terminator. */
size_t s_max;
/* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */
const char *s_buf;
struct {
/* only valid if F_IN is set. offset of the string data
* within the associated message. used when reading
* string data from a message. */
size_t s_offset;
};
};
/* valid for F_IN and F_OUT. offset of the string data
* within the associated message. used when reading
* string data from a message. */
size_t s_offset;
/* only valid if F_REMOTE is set.
* 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/object.h>
#include <mango/signal.h>
#include <string.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;
}
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_msg_t msg = {
.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_count = KERN_MSG_MAX_HANDLES,
};
kern_status_t status = msg_recv(channel, &msg);
status = msg_recv(channel, &msg);
if (status != KERN_OK) {
return status;
}
@@ -46,6 +66,25 @@ kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out)
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(
const xpc_msg_t *msg,
size_t offset,
@@ -67,17 +106,17 @@ kern_status_t xpc_msg_write(
const xpc_msg_t *msg,
size_t offset,
const void *p,
size_t count)
size_t count,
size_t *nr_written)
{
kern_iovec_t iov = IOVEC(p, count);
size_t w = 0;
return msg_write(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
offset,
&iov,
1,
&w);
nr_written);
}
kern_status_t xpc_msg_reply(

View File

@@ -47,14 +47,10 @@ xpc_status_t xpc_string_write(
to_write = s->s_max - 1;
}
kern_status_t status
= xpc_msg_write(s->s_origin, s->s_offset, in, to_write);
if (status != KERN_OK) {
return status;
}
/* TODO */
*nr_written = to_write;
return KERN_OK;
return xpc_msg_write(
s->s_origin,
s->s_offset,
in,
to_write,
nr_written);
}

View File

@@ -1,4 +1,14 @@
int main(void)
#include <mango/log.h>
#include <stdio.h>
int main(int argc, const char *argv[])
{
kern_logf("systemd");
kern_logf("args:");
for (int i = 0; i < argc; i++) {
kern_logf("[%d]: %s", i, argv[i]);
}
return 0;
}

View File

@@ -1,3 +1,5 @@
#include <mango/log.h>
#include <stdio.h>
#include <string.h>
const char *s
@@ -152,6 +154,14 @@ const char *s
int main(void)
{
const char *s = "Hello, world!";
return strlen(s);
kern_logf("Test 1");
kern_logf("Test 2");
kern_logf("Test 3");
const char *text = "Hello, world!";
char s2[32];
snprintf(s2, sizeof s2, "%s", text);
size_t v = strlen(s);
kern_logf("%s, %zu", s2, v);
return 0;
}

View File

@@ -6,11 +6,12 @@ set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C)
add_executable(bootstrap ${c_sources} ${arch_sources})
target_link_libraries(bootstrap
libmango libc-core libc-malloc libfs-static liblaunch libxpc-static
libmango libc-core libc-malloc libc-pthread libfs-static liblaunch libxpc-static
interface::fs)
target_compile_options(bootstrap PRIVATE
-fno-stack-protector -nostdlib -ffreestanding)
-fno-stack-protector -nostdlib -ffreestanding -fno-PIC)
target_link_options(bootstrap PRIVATE
-static -nostdlib -ffreestanding)
#-T ${CMAKE_CURRENT_SOURCE_DIR}/arch/${TARGET_ARCH}/layout.ld)
-static -nostdlib -ffreestanding)
set_target_properties(bootstrap PROPERTIES POSITIION_INDEPENDENT_CODE FALSE)

View File

@@ -7,16 +7,18 @@
#include <fs/context.h>
#include <heap/heap.h>
#include <launch.h>
#include <mango/handle.h>
#include <mango/log.h>
#include <mango/msg.h>
#include <mango/task.h>
#include <mango/types.h>
#include <pthread.h>
#include <rosetta/bootstrap.h>
#include <rosetta/fs.h>
#include <stdint.h>
#include <stdio.h>
#define INIT_PATH "/usr/bin/test"
#define INIT_PATH "/usr/bin/systemd"
static enum launch_status resolve_dependency(
struct launch_ctx *ctx,
@@ -29,14 +31,12 @@ static enum launch_status resolve_dependency(
name++;
}
snprintf(s, sizeof s, "searching for library %s", name);
kern_log(s);
kern_tracef("searching for library %s", name);
struct tar *fs = arg;
struct tar_file file = {0};
if (tar_open(fs, name, &file) != 0) {
snprintf(s, sizeof s, "cannot find library %s", name);
kern_log(s);
kern_tracef("cannot find library %s", name);
return LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY;
}
@@ -142,7 +142,8 @@ int main(
};
struct launch_parameters params = {
.p_executable = image,
.p_exec_image = image,
.p_exec_path = INIT_PATH,
.p_parent_task = task,
.p_task_name = "init",
.p_local_address_space = address_space,
@@ -169,6 +170,10 @@ int main(
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;
struct fs_allocator fs_allocator = {
@@ -185,17 +190,20 @@ int main(
return -1;
}
fs_context_set_channel(fs, channel);
enum fs_status fs_status = fs_context_mount_filesystem(
fs,
tar_mount,
(void *)bsp_base,
0);
if (fs_status != FS_SUCCESS) {
kern_logf("cannot mount filesustem (%d)", fs_status);
kern_logf("cannot mount filesystem (%d)", fs_status);
return -1;
}
while (1) {
fs_context_handle_request(fs);
#if 0
xpc_msg_t msg;
kern_status_t status = xpc_msg_recv(channel, &msg);
if (status != KERN_OK) {
@@ -219,6 +227,7 @@ int main(
kern_logf("message reply error %d", status);
continue;
}
#endif
}
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 += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header)));
if ((uintptr_t)s % (sizeof *bin_header)) {
s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header)));
}
bin_header = (struct tar_bin_header *)s;
}
@@ -189,7 +191,7 @@ static enum fs_status file_read(
size_t w;
xpc_buffer_write(buf, src, count, &w);
offset += count;
offset += w;
*seek = offset;
return FS_SUCCESS;
@@ -382,8 +384,10 @@ static enum fs_status build_dentry_tree(
}
s += header.size;
s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header)));
if ((uintptr_t)s % (sizeof *bin_header)) {
s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header)));
}
bin_header = (struct tar_bin_header *)s;
}

View File

@@ -0,0 +1,47 @@
.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 %rsp
push %rbp
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
pop %rbp
pop %rsp
jmp *%rax

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View File

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

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

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

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

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

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

@@ -0,0 +1,22 @@
#include "elf.h"
#include <mango/log.h>
#include <stdint.h>
#include <stdio.h>
uintptr_t dl_runtime_resolve(struct elf_image *img, unsigned long sym_id)
{
elf_sym_t *sym
= (elf_sym_t *)((virt_addr_t)img->e_base + img->e_dynsym);
const char *sym_name = (const char *)img->e_base + img->e_strtab
+ sym[sym_id + 1].st_name;
// kern_logf("%s: request for symbol %s", img->e_leaf.l_name, sym_name);
virt_addr_t sym_addr = elf_image_find_linked_symbol(img, sym_name);
virt_addr_t *sym_slot
= (virt_addr_t *)((virt_addr_t)img->e_base + img->e_got_plt
+ ((sym_id + 3) * sizeof(virt_addr_t)));
// kern_logf("symbol %s = %zx", sym_name, sym_addr);
// kern_logf("slot %s = %zx", sym_name, sym_slot);
*sym_slot = sym_addr;
return sym_addr;
}

7
sys/ld/resolve.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef RESOLVE_H_
#define RESOLVE_H_
extern void _dl_runtime_resolve(void);
extern virt_addr_t dl_runtime_resolve(unsigned int slot);
#endif

View File

@@ -8,7 +8,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
find_package(Bluelib REQUIRED COMPONENTS Core Ds Term Cmd Io)
find_package(FX REQUIRED COMPONENTS Core Ds Term Cmd Io)
add_subdirectory(
../kernel/tools

View File

@@ -1,212 +0,0 @@
#[=======================================================================[.rst:
FindBluelib
------------
Find the Bluelib library and header directories
Imported Targets
^^^^^^^^^^^^^^^^
This module defines the following :prop_tgt:`IMPORTED` target:
``Bluelib::Bluelib``
The Bluelib library, if found
Result Variables
^^^^^^^^^^^^^^^^
This module will set the following variables in your project:
``Bluelib_FOUND``
true if the Bluelib C headers and libraries were found
``Bluelib_INCLUDE_DIR``
directories containing the Bluelib C headers.
``Bluelib_LIBRARY``
the C library to link against
Hints
^^^^^
The user may set the environment variable ``Bluelib_PREFIX`` to the root
directory of a Bluelib library installation.
#]=======================================================================]
set (Bluelib_SEARCH_PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr/local/share
/usr
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
${Bluelib_PREFIX}
$ENV{Bluelib_PREFIX})
if (Bluelib_STATIC)
set(_lib_suffix "-s")
endif ()
set(supported_components
Core Ds Term Cmd Io Serial Compress
Core-MM)
set(components ${Bluelib_FIND_COMPONENTS})
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
if (NOT components)
set(components ${supported_components})
endif ()
set(required_vars)
foreach (component ${components})
if (NOT "${component}" IN_LIST supported_components)
message(FATAL_ERROR "'${component}' is not a valid Bluelib module.\nSupported modules: ${supported_components_string_list}")
endif ()
string(TOLOWER ${component} header_name)
string(REPLACE "-mm" "" header_name "${header_name}")
string(TOLOWER ${component} lib_name)
set(lib_name ${lib_name}${_lib_suffix})
set(cmake_lib_name ${component})
string(REPLACE "-" "_" cmake_lib_name "${cmake_lib_name}")
if (NOT Bluelib_${cmake_lib_dir}_INCLUDE_DIR)
find_path(Bluelib_${cmake_lib_name}_INCLUDE_DIR
NAMES blue/${header_name}.h blue/${header_name}.hpp
${Bluelib_FIND_ARGS}
PATH_SUFFIXES include
PATHS ${Bluelib_SEARCH_PATHS})
endif ()
if (NOT Bluelib_${cmake_lib_dir}_LIBRARY)
find_library(Bluelib_${cmake_lib_name}_LIBRARY
NAMES blue-${lib_name} ${Bluelib_FIND_ARGS}
PATH_SUFFIXES lib
PATHS ${Bluelib_SEARCH_PATHS})
else ()
# on Windows, ensure paths are in canonical format (forward slahes):
file(TO_CMAKE_PATH "${Bluelib_${cmake_lib_name}_LIBRARY}" Bluelib_${cmake_lib_name}_LIBRARY)
endif()
list(APPEND required_vars Bluelib_${cmake_lib_name}_INCLUDE_DIR Bluelib_${cmake_lib_name}_LIBRARY)
endforeach (component)
unset(Bluelib_FIND_ARGS)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Bluelib
REQUIRED_VARS ${required_vars})
if (Bluelib_FOUND)
set(created_targets)
foreach (component ${components})
string(TOLOWER ${component} header_name)
string(REPLACE "-mm" "" header_name "${header_name}")
string(TOLOWER ${component} lib_name)
set(lib_name ${lib_name}${_lib_suffix})
set(cmake_lib_name ${component})
string(REPLACE "-" "_" cmake_lib_name "${cmake_lib_name}")
if(NOT TARGET Bluelib::${component})
add_library(Bluelib::${component} UNKNOWN IMPORTED)
set_target_properties(Bluelib::${component} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Bluelib_${cmake_lib_name}_INCLUDE_DIR}")
target_compile_definitions(Bluelib::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
if (Bluelib_STATIC)
target_compile_definitions(Bluelib::${component} INTERFACE BLUELIB_STATIC=1)
endif ()
set_target_properties(Bluelib::${component} PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${Bluelib_${cmake_lib_name}_LIBRARY}")
set(created_targets ${created_targets} ${component})
endif ()
endforeach (component)
foreach (component ${created_targets})
if ("${component}" STREQUAL "Ds")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Ds' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Ds INTERFACE Bluelib::Core)
endif ()
if ("${component}" STREQUAL "Term")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Term INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Serial")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Serial INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Cmd")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Term)
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Cmd INTERFACE Bluelib::Core Bluelib::Ds Bluelib::Term)
endif ()
if ("${component}" STREQUAL "Io")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET Bluelib::Ds)
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Io INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Compress")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Compress' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Compress INTERFACE Bluelib::Core Bluelib::Ds)
endif ()
if ("${component}" STREQUAL "Core-MM")
if (NOT TARGET Bluelib::Core)
message(FATAL_ERROR "Bluelib: Module 'Core-MM' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(Bluelib::Core-MM INTERFACE Bluelib::Core)
endif ()
endforeach (component)
endif()

View File

@@ -0,0 +1,189 @@
#[=======================================================================[.rst:
FindFX
------------
Find the FX library and header directories
Imported Targets
^^^^^^^^^^^^^^^^
This module defines the following :prop_tgt:`IMPORTED` target:
``FX::FX``
The FX library, if found
Result Variables
^^^^^^^^^^^^^^^^
This module will set the following variables in your project:
``FX_FOUND``
true if the FX C headers and libraries were found
``FX_INCLUDE_DIR``
directories containing the FX C headers.
``FX_LIBRARY``
the C library to link against
Hints
^^^^^
The user may set the environment variable ``FX_PREFIX`` to the root
directory of a FX library installation.
#]=======================================================================]
set (FX_SEARCH_PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr/local/share
/usr
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
${FX_PREFIX}
$ENV{FX_PREFIX})
if (FX_STATIC)
set(_lib_suffix "-s")
endif ()
set(supported_components Core Ds Term Cmd Io Serial Compress)
set(components ${FX_FIND_COMPONENTS})
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
if (NOT components)
set(components ${supported_components})
endif ()
set(required_vars)
foreach (component ${components})
if (NOT "${component}" IN_LIST supported_components)
message(FATAL_ERROR "'${component}' is not a valid FX module.\nSupported modules: ${supported_components_string_list}")
endif ()
string(TOLOWER ${component} header_name)
set(lib_name ${header_name}${_lib_suffix})
if (NOT FX_${component}_INCLUDE_DIR)
find_path(FX_${component}_INCLUDE_DIR
NAMES fx/${header_name}.h ${FX_FIND_ARGS}
PATH_SUFFIXES include
PATHS ${FX_SEARCH_PATHS})
endif ()
if (NOT FX_${component}_LIBRARY)
find_library(FX_${component}_LIBRARY
NAMES fx-${lib_name} ${FX_FIND_ARGS}
PATH_SUFFIXES lib
PATHS ${FX_SEARCH_PATHS})
else ()
# on Windows, ensure paths are in canonical format (forward slahes):
file(TO_CMAKE_PATH "${FX_${component}_LIBRARY}" FX_${component}_LIBRARY)
endif()
list(APPEND required_vars FX_${component}_INCLUDE_DIR FX_${component}_LIBRARY)
endforeach (component)
unset(FX_FIND_ARGS)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FX
REQUIRED_VARS ${required_vars})
if (FX_FOUND)
set(created_targets)
foreach (component ${components})
string(TOLOWER ${component} header_name)
set(lib_name ${header_name}${_lib_suffix})
if(NOT TARGET FX::${component})
add_library(FX::${component} UNKNOWN IMPORTED)
set_target_properties(FX::${component} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FX_${component}_INCLUDE_DIR}")
target_compile_definitions(FX::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
if (FX_STATIC)
target_compile_definitions(FX::${component} INTERFACE FX_STATIC=1)
endif ()
set_target_properties(FX::${component} PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${FX_${component}_LIBRARY}")
set(created_targets ${created_targets} ${component})
endif ()
endforeach (component)
foreach (component ${created_targets})
if ("${component}" STREQUAL "Ds")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Ds' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Ds INTERFACE FX::Core)
endif ()
if ("${component}" STREQUAL "Term")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Term' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Term' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Term INTERFACE FX::Core FX::Ds)
endif ()
if ("${component}" STREQUAL "Serial")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Serial INTERFACE FX::Core FX::Ds)
endif ()
if ("${component}" STREQUAL "Cmd")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Term)
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Cmd INTERFACE FX::Core FX::Ds FX::Term)
endif ()
if ("${component}" STREQUAL "Io")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Io' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Io' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Io INTERFACE FX::Core FX::Ds)
endif ()
if ("${component}" STREQUAL "Compress")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Compress' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Compress INTERFACE FX::Core FX::Ds)
endif ()
endforeach (component)
endif()

View File

@@ -4,4 +4,4 @@ file(GLOB sources
add_executable(xpcg ${sources})
target_link_libraries(xpcg Bluelib::Core Bluelib::Ds Bluelib::Cmd Bluelib::Io)
target_link_libraries(xpcg FX::Core FX::Ds FX::Cmd FX::Io)

View File

@@ -4,14 +4,14 @@
#include "../../msg.h"
#include "../../type.h"
#include <blue/core/hash.h>
#include <blue/io/file.h>
#include <blue/io/path.h>
#include <fx/core/hash.h>
#include <fx/io/file.h>
#include <fx/io/path.h>
#include <stdarg.h>
#include <stddef.h>
struct emit_ctx {
b_stream *ctx_out;
fx_stream *ctx_out;
size_t ctx_max_handle_params;
};
@@ -19,23 +19,23 @@ static void emit(struct emit_ctx *ctx, const char *format, ...)
{
va_list arg;
va_start(arg, format);
b_stream_write_vfmt(ctx->ctx_out, NULL, format, arg);
fx_stream_write_vfmt(ctx->ctx_out, NULL, format, arg);
va_end(arg);
}
static void emit_indent(struct emit_ctx *ctx)
{
b_stream_push_indent(ctx->ctx_out, 4);
fx_stream_push_indent(ctx->ctx_out, 4);
}
static void emit_indent_zero(struct emit_ctx *ctx)
{
b_stream_push_indent(ctx->ctx_out, -100);
fx_stream_push_indent(ctx->ctx_out, -100);
}
static void emit_unindent(struct emit_ctx *ctx)
{
b_stream_pop_indent(ctx->ctx_out);
fx_stream_pop_indent(ctx->ctx_out);
}
static int emit_include(struct emit_ctx *ctx, const char *path, bool system)
@@ -53,15 +53,15 @@ static int emit_header_guard_start(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_string *header_guard = b_string_create();
b_string_append_cstrf(header_guard, "%s_H_", iface->if_name);
b_string_toupper(header_guard);
fx_string *header_guard = fx_string_create();
fx_string_append_cstrf(header_guard, "%s_H_", iface->if_name);
fx_string_toupper(header_guard);
emit(ctx,
"#ifndef %s\n#define %s\n\n",
b_string_ptr(header_guard),
b_string_ptr(header_guard));
b_string_unref(header_guard);
fx_string_ptr(header_guard),
fx_string_ptr(header_guard));
fx_string_unref(header_guard);
return 0;
}
@@ -76,15 +76,15 @@ static int emit_header_guard_end(
static size_t get_msg_handle_params(const struct msg_definition *msg)
{
size_t count = 0;
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
if (param->p_type->ty_id == TYPE_HANDLE) {
count++;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return count;
@@ -93,17 +93,17 @@ static size_t get_msg_handle_params(const struct msg_definition *msg)
static size_t get_max_handle_params(const struct interface_definition *iface)
{
size_t count = 0;
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
size_t msg_count = get_msg_handle_params(msg);
if (msg_count > count) {
count = msg_count;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return count;
@@ -113,51 +113,51 @@ static int emit_interface_id_macros(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_string *iface_define_name = b_string_create();
b_string_append_cstr(iface_define_name, iface->if_name);
b_string_toupper(iface_define_name);
fx_string *iface_define_name = fx_string_create();
fx_string_append_cstr(iface_define_name, iface->if_name);
fx_string_toupper(iface_define_name);
uint32_t protocol_id = iface->if_id;
emit(ctx,
"/* %s protocol ID */\n#define INTERFACE_%s 0x%08xU\n\n",
iface->if_name,
b_string_ptr(iface_define_name),
fx_string_ptr(iface_define_name),
protocol_id);
b_string_unref(iface_define_name);
fx_string_unref(iface_define_name);
b_string *msg_name = b_string_create();
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_string *msg_name = fx_string_create();
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
b_string_clear(msg_name);
b_string_append_cstrf(
= fx_unbox(struct msg_definition, entry, msg_entry);
fx_string_clear(msg_name);
fx_string_append_cstrf(
msg_name,
"%s.%s",
iface->if_name,
msg->msg_name);
emit(ctx, "/* %s message ID */\n", b_string_ptr(msg_name));
emit(ctx, "/* %s message ID */\n", fx_string_ptr(msg_name));
uint16_t msg_id = msg->msg_id;
b_string_clear(msg_name);
b_string_append_cstrf(
fx_string_clear(msg_name);
fx_string_append_cstrf(
msg_name,
"%s_%s",
iface->if_name,
msg->msg_name);
b_string_toupper(msg_name);
fx_string_toupper(msg_name);
emit(ctx,
"#define MSG_%s 0x%04xU\n",
b_string_ptr(msg_name),
fx_string_ptr(msg_name),
msg_id);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx, "\n");
b_string_unref(msg_name);
fx_string_unref(msg_name);
return 0;
}
@@ -176,10 +176,12 @@ static int emit_msg_struct_member(
case TYPE_SIZE:
emit(ctx, "uint64_t %s;\n", param->p_name);
break;
case TYPE_OFFSET:
emit(ctx, "int64_t %s;\n", param->p_name);
break;
case TYPE_STRING:
case TYPE_BUFFER:
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
emit(ctx, "uint16_t %s_len;\n", param->p_name);
emit(ctx, "uint32_t %s_len;\n", param->p_name);
break;
default:
break;
@@ -192,33 +194,41 @@ static int emit_msg_struct_params(
struct emit_ctx *ctx,
const struct msg_definition *msg)
{
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
case TYPE_BUFFER:
emit(ctx, "uint32_t %s_offset;\n", param->p_name);
break;
default:
break;
}
emit_msg_struct_member(ctx, param);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
emit(ctx, "uint16_t %s_max;\n", param->p_name);
emit(ctx, "uint32_t %s_offset;\n", param->p_name);
emit(ctx, "uint32_t %s_max;\n", param->p_name);
break;
case TYPE_BUFFER:
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
emit(ctx, "uint32_t %s_offset;\n", param->p_name);
emit(ctx, "uint32_t %s_max;\n", param->p_name);
break;
default:
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return 0;
@@ -228,12 +238,13 @@ static int emit_msg_struct_results(
struct emit_ctx *ctx,
const struct msg_definition *msg)
{
b_queue_entry *entry = b_queue_first(&msg->msg_results);
fx_queue_entry *entry = fx_queue_first(&msg->msg_results);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
emit_msg_struct_member(ctx, param);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return 0;
@@ -244,7 +255,7 @@ static int emit_interface_msg_struct(
const struct interface_definition *iface,
const struct msg_definition *msg)
{
b_string *tmp = b_string_create();
fx_string *tmp = fx_string_create();
emit(ctx, "struct %s_%s_msg {\n", iface->if_name, msg->msg_name);
emit_indent(ctx);
@@ -277,7 +288,7 @@ static int emit_interface_msg_struct(
emit_unindent(ctx);
emit(ctx, "};\n");
b_string_unref(tmp);
fx_string_unref(tmp);
return 0;
}
@@ -285,14 +296,14 @@ static int emit_interface_msg_structs(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
emit_interface_msg_struct(ctx, iface, msg);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx, "\n");
@@ -304,10 +315,10 @@ static int emit_interface_msg_function_send_impl(
const struct interface_definition *iface,
const struct msg_definition *msg)
{
b_string *iface_ucase = b_string_create_from_cstr(iface->if_name);
b_string_toupper(iface_ucase);
b_string *msg_ucase = b_string_create_from_cstr(msg->msg_name);
b_string_toupper(msg_ucase);
fx_string *iface_ucase = fx_string_create_from_cstr(iface->if_name);
fx_string_toupper(iface_ucase);
fx_string *msg_ucase = fx_string_create_from_cstr(msg->msg_name);
fx_string_toupper(msg_ucase);
emit(ctx,
"struct %s_%s_msg msg_data = {0};\n",
@@ -316,12 +327,12 @@ static int emit_interface_msg_function_send_impl(
emit(ctx,
"xpc_msg_header_init(&msg_data.msg_header, INTERFACE_%s, "
"MSG_%s_%s);\n",
b_string_ptr(iface_ucase),
b_string_ptr(iface_ucase),
b_string_ptr(msg_ucase));
fx_string_ptr(iface_ucase),
fx_string_ptr(iface_ucase),
fx_string_ptr(msg_ucase));
b_string_unref(iface_ucase);
b_string_unref(msg_ucase);
fx_string_unref(iface_ucase);
fx_string_unref(msg_ucase);
emit(ctx, "uint32_t in_offset = sizeof msg_data;\n\n");
emit(ctx, "uint32_t out_offset = sizeof msg_data;\n\n");
@@ -329,13 +340,14 @@ static int emit_interface_msg_function_send_impl(
size_t nr_req_handles = 0;
size_t nr_resp_handles = 0;
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
case TYPE_SIZE:
case TYPE_OFFSET:
emit(ctx,
"msg_data.msg_request.%s = %s;\n\n",
param->p_name,
@@ -362,7 +374,7 @@ static int emit_interface_msg_function_send_impl(
break;
case TYPE_BUFFER:
emit(ctx,
"msg_data.msg_request.%s_offset = offset;\n",
"msg_data.msg_request.%s_offset = in_offset;\n",
param->p_name);
emit(ctx,
"msg_data.msg_request.%s_len = %s_len;\n",
@@ -376,13 +388,13 @@ static int emit_interface_msg_function_send_impl(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
case TYPE_BUFFER:
@@ -403,7 +415,7 @@ static int emit_interface_msg_function_send_impl(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx, "kern_iovec_t req_iov[] = {\n");
@@ -411,10 +423,10 @@ static int emit_interface_msg_function_send_impl(
emit(ctx, "IOVEC(&msg_data, sizeof msg_data),\n");
size_t nr_req_iov = 1;
entry = b_queue_first(&msg->msg_params);
entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
@@ -429,7 +441,7 @@ static int emit_interface_msg_function_send_impl(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit_unindent(ctx);
@@ -446,10 +458,10 @@ static int emit_interface_msg_function_send_impl(
emit(ctx, "IOVEC(&msg_data, sizeof msg_data),\n");
size_t nr_resp_iov = 1;
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
@@ -464,7 +476,7 @@ static int emit_interface_msg_function_send_impl(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit_unindent(ctx);
@@ -511,10 +523,10 @@ static int emit_interface_msg_function_send_impl(
"if (msg_data.msg_header.hdr_status != KERN_OK) return "
"msg_data.msg_header.hdr_status;\n\n");
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_HANDLE:
emit(ctx, "*out_%s = ", param->p_name);
@@ -540,7 +552,7 @@ static int emit_interface_msg_function_send_impl(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx, "return status;\n");
@@ -563,10 +575,10 @@ static int emit_interface_msg_function_send(
emit(ctx, "kern_handle_t port");
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
case TYPE_INT:
@@ -578,6 +590,9 @@ static int emit_interface_msg_function_send(
case TYPE_SIZE:
emit(ctx, "size_t %s", param->p_name);
break;
case TYPE_OFFSET:
emit(ctx, "off_t %s", param->p_name);
break;
case TYPE_STRING:
emit(ctx, "const char *%s", param->p_name);
break;
@@ -589,13 +604,13 @@ static int emit_interface_msg_function_send(
default:
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
case TYPE_INT:
@@ -604,6 +619,9 @@ static int emit_interface_msg_function_send(
case TYPE_SIZE:
emit(ctx, "size_t *out_%s", param->p_name);
break;
case TYPE_OFFSET:
emit(ctx, "off_t *out_%s", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx, "kern_handle_t *out_%s", param->p_name);
break;
@@ -622,7 +640,7 @@ static int emit_interface_msg_function_send(
default:
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx, ")");
@@ -663,10 +681,10 @@ static int emit_interface_dispatcher_impl_msg(
"status = xpc_msg_read(msg, 0, &" MSG_STRUCT_NAME
", sizeof " MSG_STRUCT_NAME ");\n");
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx,
@@ -681,6 +699,12 @@ static int emit_interface_dispatcher_impl_msg(
param->p_name,
param->p_name);
break;
case TYPE_OFFSET:
emit(ctx,
"off_t %s = " MSG_STRUCT_NAME ".msg_request.%s;\n",
param->p_name,
param->p_name);
break;
case TYPE_STRING:
emit(ctx,
"xpc_string_t %s = "
@@ -693,7 +717,7 @@ static int emit_interface_dispatcher_impl_msg(
break;
case TYPE_BUFFER:
emit(ctx,
"xpc_string_t %s = "
"xpc_buffer_t %s = "
"XPC_BUFFER_IN(msg, " MSG_STRUCT_NAME
".msg_request.%s_offset, " MSG_STRUCT_NAME
".msg_request.%s_len);\n",
@@ -705,13 +729,13 @@ static int emit_interface_dispatcher_impl_msg(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx, "int %s = 0;\n", param->p_name);
@@ -719,6 +743,9 @@ static int emit_interface_dispatcher_impl_msg(
case TYPE_SIZE:
emit(ctx, "size_t %s = 0;\n", param->p_name);
break;
case TYPE_OFFSET:
emit(ctx, "off_t %s = 0;\n", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx,
"kern_handle_t %s = KERN_HANDLE_INVALID;\n",
@@ -748,16 +775,16 @@ static int emit_interface_dispatcher_impl_msg(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx, "status = vtable->%s(\n", msg->msg_name);
emit_indent(ctx);
emit(ctx, "ctx,\n&msg->msg_sender");
entry = b_queue_first(&msg->msg_params);
entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
@@ -769,15 +796,15 @@ static int emit_interface_dispatcher_impl_msg(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n&%s", param->p_name);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx, ",\narg);\n");
@@ -789,12 +816,14 @@ static int emit_interface_dispatcher_impl_msg(
emit(ctx, MSG_STRUCT_NAME ".msg_header.hdr_status = 0;\n");
size_t handle_index = 0;
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
case TYPE_SIZE:
case TYPE_OFFSET:
emit(ctx,
MSG_STRUCT_NAME ".msg_response.%s = %s;\n",
param->p_name,
@@ -811,7 +840,7 @@ static int emit_interface_dispatcher_impl_msg(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit(ctx,
@@ -820,10 +849,10 @@ static int emit_interface_dispatcher_impl_msg(
emit(ctx, "kern_msg_handle_t out_handles[] = {\n");
emit_indent(ctx);
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_HANDLE:
emit(ctx,
@@ -834,7 +863,7 @@ static int emit_interface_dispatcher_impl_msg(
break;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit_unindent(ctx);
emit(ctx, "};\n");
@@ -850,41 +879,41 @@ static int emit_interface_dispatcher_impl(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_string *iface_ucase = b_string_create_from_cstr(iface->if_name);
b_string_toupper(iface_ucase);
b_string *msg_ucase = b_string_create();
fx_string *iface_ucase = fx_string_create_from_cstr(iface->if_name);
fx_string_toupper(iface_ucase);
fx_string *msg_ucase = fx_string_create();
emit(ctx,
"if (msg->msg_header.hdr_interface != INTERFACE_%s) return "
"KERN_INVALID_ARGUMENT;\n\n",
b_string_ptr(iface_ucase));
fx_string_ptr(iface_ucase));
emit(ctx, "kern_status_t status = KERN_OK;\n");
emit(ctx, "switch (msg->msg_header.hdr_func) {\n");
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
b_string_clear(msg_ucase);
b_string_append_cstr(msg_ucase, msg->msg_name);
b_string_toupper(msg_ucase);
fx_string_clear(msg_ucase);
fx_string_append_cstr(msg_ucase, msg->msg_name);
fx_string_toupper(msg_ucase);
emit(ctx,
"case MSG_%s_%s: {\n",
b_string_ptr(iface_ucase),
b_string_ptr(msg_ucase));
fx_string_ptr(iface_ucase),
fx_string_ptr(msg_ucase));
emit_indent(ctx);
emit_interface_dispatcher_impl_msg(ctx, iface, msg);
emit(ctx, "break;\n");
emit_unindent(ctx);
emit(ctx, "}\n");
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
b_string_unref(iface_ucase);
fx_string_unref(iface_ucase);
emit(ctx, "default:\n");
emit_indent(ctx);
@@ -933,10 +962,10 @@ static int emit_interface_functions(
const struct interface_definition *iface,
bool prototype_only)
{
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
emit_interface_msg_function_send(
ctx,
@@ -944,7 +973,7 @@ static int emit_interface_functions(
msg,
prototype_only);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit_interface_dispatcher(ctx, iface, prototype_only);
@@ -963,10 +992,10 @@ static int emit_interface_vtable_entry(
emit(ctx, "const xpc_endpoint_t *sender");
size_t i = 0;
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
@@ -976,6 +1005,9 @@ static int emit_interface_vtable_entry(
case TYPE_SIZE:
emit(ctx, "size_t %s", param->p_name);
break;
case TYPE_OFFSET:
emit(ctx, "off_t %s", param->p_name);
break;
case TYPE_BUFFER:
emit(ctx, "const xpc_buffer_t *%s", param->p_name);
break;
@@ -990,13 +1022,13 @@ static int emit_interface_vtable_entry(
}
i++;
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
@@ -1012,6 +1044,9 @@ static int emit_interface_vtable_entry(
case TYPE_SIZE:
emit(ctx, "size_t *out_%s", param->p_name);
break;
case TYPE_OFFSET:
emit(ctx, "off_t *out_%s", param->p_name);
break;
case TYPE_BUFFER:
emit(ctx, "xpc_buffer_t *out_%s", param->p_name);
break;
@@ -1020,7 +1055,7 @@ static int emit_interface_vtable_entry(
}
i++;
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
if (i > 0) {
@@ -1042,14 +1077,14 @@ static int emit_interface_vtable(
emit(ctx, "struct %s_vtable {\n", iface->if_name);
emit_indent(ctx);
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
emit_interface_vtable_entry(ctx, iface, msg);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
emit_unindent(ctx);
@@ -1092,16 +1127,16 @@ static int emit_header(
static int emit_interface(const struct interface_definition *iface)
{
char path[4096];
b_file *file = NULL;
fx_file *file = NULL;
snprintf(path, sizeof path, "%s.h", iface->if_name);
b_result result = b_file_open(
fx_result result = fx_file_open(
NULL,
B_RV_PATH(path),
B_FILE_WRITE_ONLY | B_FILE_CREATE,
FX_RV_PATH(path),
FX_FILE_WRITE_ONLY | FX_FILE_CREATE | FX_FILE_TRUNCATE,
&file);
if (b_result_is_error(result)) {
b_throw(result);
if (fx_result_is_error(result)) {
fx_throw(result);
fprintf(stderr, "cannot create C header file %s\n", path);
return -1;
}
@@ -1112,7 +1147,7 @@ static int emit_interface(const struct interface_definition *iface)
};
int err = emit_header(&ctx, iface);
b_file_unref(file);
fx_file_unref(file);
return err;
}

View File

@@ -47,6 +47,10 @@ const struct type *ctx_get_type(struct ctx *ctx, const char *name)
return ctx_get_builtin_type(ctx, TYPE_SIZE);
}
if (!strcmp(name, "offset")) {
return ctx_get_builtin_type(ctx, TYPE_OFFSET);
}
if (!strcmp(name, "buffer")) {
return ctx_get_builtin_type(ctx, TYPE_BUFFER);
}

View File

@@ -2,7 +2,7 @@
#include "msg.h"
#include <blue/ds/string.h>
#include <fx/ds/string.h>
#include <stdlib.h>
#include <string.h>
@@ -17,7 +17,7 @@ struct interface_definition *interface_definition_create(
memset(out, 0x0, sizeof *out);
out->if_name = b_strdup(name);
out->if_name = fx_strdup(name);
out->if_id = id;
return out;
@@ -25,12 +25,12 @@ struct interface_definition *interface_definition_create(
void interface_definition_destroy(struct interface_definition *iface)
{
b_queue_entry *entry = b_queue_pop_front(&iface->if_msg);
fx_queue_entry *entry = fx_queue_pop_front(&iface->if_msg);
while (entry) {
struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
msg_definition_destroy(msg);
entry = b_queue_pop_front(&iface->if_msg);
entry = fx_queue_pop_front(&iface->if_msg);
}
free(iface->if_name);
@@ -41,15 +41,15 @@ bool interface_definition_has_msg(
const struct interface_definition *iface,
const char *name)
{
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
if (!strcmp(msg->msg_name, name)) {
return true;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return false;
@@ -59,5 +59,5 @@ void interface_definition_add_msg(
struct interface_definition *iface,
struct msg_definition *msg)
{
b_queue_push_back(&iface->if_msg, &msg->msg_entry);
fx_queue_push_back(&iface->if_msg, &msg->msg_entry);
}

View File

@@ -1,14 +1,14 @@
#ifndef XPCG_INTERFACE_H_
#define XPCG_INTERFACE_H_
#include <blue/core/queue.h>
#include <fx/core/queue.h>
struct msg_definition;
struct interface_definition {
char *if_name;
long long if_id;
b_queue if_msg;
fx_queue if_msg;
};
extern struct interface_definition *interface_definition_create(

View File

@@ -3,12 +3,12 @@
#include "line-source.h"
#include "token.h"
#include <blue/core/hash.h>
#include <blue/core/misc.h>
#include <blue/core/queue.h>
#include <blue/ds/dict.h>
#include <blue/ds/number.h>
#include <blue/ds/string.h>
#include <fx/core/hash.h>
#include <fx/core/misc.h>
#include <fx/core/queue.h>
#include <fx/ds/dict.h>
#include <fx/ds/number.h>
#include <fx/ds/string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
@@ -21,10 +21,10 @@
#define LEX_TOKEN_DEF(i, n) {.id = (i), .name = (n)}
#define IS_VALID_IDENT_CHAR(c) \
(b_wchar_is_alnum(c) || c == '.' || c == '-' || c == '_')
(fx_wchar_is_alnum(c) || c == '.' || c == '-' || c == '_')
#define IS_VALID_IDENT_START_CHAR(c) \
(b_wchar_is_alpha(c) || c == '.' || c == '_')
#define IS_VALID_REG_START_CHAR(c) (b_wchar_is_alnum(c) || c == '.' || c == '_')
(fx_wchar_is_alpha(c) || c == '.' || c == '_')
#define IS_VALID_REG_START_CHAR(c) (fx_wchar_is_alnum(c) || c == '.' || c == '_')
static struct lex_token_def symbols[] = {
LEX_TOKEN_DEF(SYM_COMMA, ","),
@@ -51,27 +51,27 @@ static struct lex_symbol_node *get_symbol_node(
struct lex_symbol_node *node,
char c)
{
b_queue_entry *entry = b_queue_first(&node->s_children);
fx_queue_entry *entry = fx_queue_first(&node->s_children);
while (entry) {
struct lex_symbol_node *child
= b_unbox(struct lex_symbol_node, entry, s_entry);
= fx_unbox(struct lex_symbol_node, entry, s_entry);
if (child->s_char == c) {
return child;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return NULL;
}
static b_string *get_temp_string(struct lex *lex)
static fx_string *get_temp_string(struct lex *lex)
{
if (!lex->lex_temp) {
lex->lex_temp = b_string_create();
lex->lex_temp = fx_string_create();
}
b_string_clear(lex->lex_temp);
fx_string_clear(lex->lex_temp);
return lex->lex_temp;
}
@@ -97,7 +97,7 @@ static enum status put_symbol(
child->s_def = NULL;
child->s_char = c;
b_queue_push_back(&tree->s_children, &child->s_entry);
fx_queue_push_back(&tree->s_children, &child->s_entry);
tree = child;
}
@@ -107,12 +107,12 @@ static enum status put_symbol(
static void destroy_symbol_tree(struct lex_symbol_node *tree)
{
b_queue_entry *entry = b_queue_first(&tree->s_children);
fx_queue_entry *entry = fx_queue_first(&tree->s_children);
while (entry) {
struct lex_symbol_node *node
= b_unbox(struct lex_symbol_node, entry, s_entry);
b_queue_entry *next = b_queue_next(entry);
b_queue_delete(&tree->s_children, entry);
= fx_unbox(struct lex_symbol_node, entry, s_entry);
fx_queue_entry *next = fx_queue_next(entry);
fx_queue_delete(&tree->s_children, entry);
destroy_symbol_tree(node);
@@ -168,12 +168,12 @@ struct lex *lex_create(struct line_source *src)
void lex_destroy(struct lex *lex)
{
b_queue_entry *entry = b_queue_first(&lex->lex_queue);
fx_queue_entry *entry = fx_queue_first(&lex->lex_queue);
while (entry) {
struct token *tok = b_unbox(struct token, entry, tok_entry);
b_queue_entry *next = b_queue_next(entry);
b_queue_delete(&lex->lex_queue, entry);
struct token *tok = fx_unbox(struct token, entry, tok_entry);
fx_queue_entry *next = fx_queue_next(entry);
fx_queue_delete(&lex->lex_queue, entry);
token_destroy(tok);
@@ -185,7 +185,7 @@ void lex_destroy(struct lex *lex)
}
if (lex->lex_temp) {
b_string_unref(lex->lex_temp);
fx_string_unref(lex->lex_temp);
}
free(lex);
@@ -245,7 +245,7 @@ static enum status push_token(struct lex *lex, struct token *tok)
tok->tok_location.s_start = lex->lex_token_start;
tok->tok_location.s_end = lex->lex_token_end;
b_queue_push_back(&lex->lex_queue, &tok->tok_entry);
fx_queue_push_back(&lex->lex_queue, &tok->tok_entry);
return SUCCESS;
}
@@ -326,7 +326,7 @@ static enum status push_int(struct lex *lex, unsigned long long v)
static enum status read_line_comment(struct lex *lex)
{
while (true) {
b_wchar c = line_source_getc(lex->lex_source);
fx_wchar c = line_source_getc(lex->lex_source);
if (c == -ERR_EOF || c == '\n') {
break;
@@ -345,14 +345,14 @@ static enum status read_number(struct lex *lex, bool negate)
int token_len = 0;
int base = 10;
int dots = 0;
b_string *str = get_temp_string(lex);
fx_string *str = get_temp_string(lex);
if (!negate) {
set_token_start(lex);
}
while (true) {
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
if (c == -ERR_EOF) {
break;
}
@@ -372,7 +372,7 @@ static enum status read_number(struct lex *lex, bool negate)
return ERR_BAD_SYNTAX;
}
if (b_wchar_is_space(c) || b_wchar_is_punct(c)) {
if (fx_wchar_is_space(c) || fx_wchar_is_punct(c)) {
break;
}
@@ -404,7 +404,7 @@ static enum status read_number(struct lex *lex, bool negate)
return ERR_BAD_SYNTAX;
}
b_string_append_wc(str, c);
fx_string_append_wc(str, c);
set_token_end(lex);
line_source_getc(lex->lex_source);
token_len++;
@@ -414,7 +414,7 @@ static enum status read_number(struct lex *lex, bool negate)
return push_int(lex, 0);
}
const char *s = b_string_ptr(str);
const char *s = fx_string_ptr(str);
char *ep = NULL;
/* negative numbers will be lexed as a hyphen followed by a positive
@@ -447,15 +447,15 @@ static enum token_keyword find_keyword(const char *s)
static enum status read_ident(struct lex *lex, enum token_type type)
{
int dots = 0;
b_string *str = get_temp_string(lex);
b_wchar prev = 0;
fx_string *str = get_temp_string(lex);
fx_wchar prev = 0;
if (type == TOK_NONE) {
set_token_start(lex);
}
while (1) {
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
if ((c == '.' || c == '-') && prev == c) {
return ERR_BAD_SYNTAX;
@@ -470,7 +470,7 @@ static enum status read_ident(struct lex *lex, enum token_type type)
}
prev = c;
b_string_append_wc(str, c);
fx_string_append_wc(str, c);
set_token_end(lex);
line_source_getc(lex->lex_source);
}
@@ -479,7 +479,7 @@ static enum status read_ident(struct lex *lex, enum token_type type)
type = dots > 0 ? TOK_NAME : TOK_WORD;
}
char *s = b_string_steal(str);
char *s = fx_string_steal(str);
enum token_keyword kw = find_keyword(s);
if (kw != KW_NONE) {
free(s);
@@ -491,9 +491,9 @@ static enum status read_ident(struct lex *lex, enum token_type type)
static enum status read_string(struct lex *lex)
{
b_string *str = get_temp_string(lex);
fx_string *str = get_temp_string(lex);
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
bool esc = false;
if (c != '"') {
@@ -503,13 +503,13 @@ static enum status read_string(struct lex *lex)
line_source_getc(lex->lex_source);
while (1) {
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
if (esc) {
switch (c) {
case '\\':
case '"':
b_string_append_wc(str, c);
fx_string_append_wc(str, c);
break;
default:
return ERR_BAD_SYNTAX;
@@ -531,11 +531,11 @@ static enum status read_string(struct lex *lex)
break;
}
b_string_append_wc(str, c);
fx_string_append_wc(str, c);
line_source_getc(lex->lex_source);
}
char *s = b_string_steal(str);
char *s = fx_string_steal(str);
return push_string_token(lex, TOK_STRING, s);
}
@@ -543,10 +543,10 @@ static enum status read_symbol(struct lex *lex)
{
struct lex_symbol_node *node = lex->lex_sym_tree;
set_token_start(lex);
b_wchar prev = 0;
fx_wchar prev = 0;
while (true) {
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
if (c < 0) {
break;
}
@@ -576,17 +576,17 @@ static enum status read_symbol(struct lex *lex)
static void skip_whitespace(struct lex *lex)
{
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
while (b_wchar_is_space(c)) {
while (fx_wchar_is_space(c)) {
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
}
}
static bool should_skip(b_wchar c, bool skip_linefeeds)
static bool should_skip(fx_wchar c, bool skip_linefeeds)
{
bool skip = b_wchar_is_space(c);
bool skip = fx_wchar_is_space(c);
if (!skip_linefeeds) {
skip = (skip && c != '\n');
@@ -597,7 +597,7 @@ static bool should_skip(b_wchar c, bool skip_linefeeds)
static void skip_ignored_chars(struct lex *lex, bool include_linefeeds)
{
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
while (1) {
while (should_skip(c, include_linefeeds)) {
@@ -624,14 +624,14 @@ static void skip_ignored_chars(struct lex *lex, bool include_linefeeds)
static enum status pump_tokens(struct lex *lex)
{
b_wchar c = line_source_peekc(lex->lex_source);
fx_wchar c = line_source_peekc(lex->lex_source);
if (c < 0) {
return -c;
}
while (1) {
if (c == '#' || (b_wchar_is_space(c) && c != '\n')) {
if (c == '#' || (fx_wchar_is_space(c) && c != '\n')) {
skip_ignored_chars(lex, false);
} else {
break;
@@ -667,7 +667,7 @@ static enum status pump_tokens(struct lex *lex)
return SUCCESS;
}
while (b_wchar_is_space(c) && c != '\n') {
while (fx_wchar_is_space(c) && c != '\n') {
line_source_getc(lex->lex_source);
c = line_source_peekc(lex->lex_source);
}
@@ -695,7 +695,7 @@ struct token *lex_peek(struct lex *lex)
{
enum status status = SUCCESS;
while (b_queue_empty(&lex->lex_queue)) {
while (fx_queue_empty(&lex->lex_queue)) {
status = pump_tokens(lex);
if (status != SUCCESS) {
@@ -706,8 +706,8 @@ struct token *lex_peek(struct lex *lex)
lex->lex_status = status;
b_queue_entry *entry = b_queue_first(&lex->lex_queue);
struct token *tok = b_unbox(struct token, entry, tok_entry);
fx_queue_entry *entry = fx_queue_first(&lex->lex_queue);
struct token *tok = fx_unbox(struct token, entry, tok_entry);
return tok;
}
@@ -715,7 +715,7 @@ void lex_advance(struct lex *lex)
{
enum status status = SUCCESS;
while (b_queue_empty(&lex->lex_queue)) {
while (fx_queue_empty(&lex->lex_queue)) {
status = pump_tokens(lex);
if (status != SUCCESS) {
@@ -724,14 +724,14 @@ void lex_advance(struct lex *lex)
}
}
b_queue_entry *entry = b_queue_pop_front(&lex->lex_queue);
struct token *tok = b_unbox(struct token, entry, tok_entry);
fx_queue_entry *entry = fx_queue_pop_front(&lex->lex_queue);
struct token *tok = fx_unbox(struct token, entry, tok_entry);
token_destroy(tok);
}
bool lex_tokens_available(struct lex *lex)
{
if (!b_queue_empty(&lex->lex_queue)) {
if (!fx_queue_empty(&lex->lex_queue)) {
return true;
}

View File

@@ -4,9 +4,9 @@
#include "status.h"
#include "token.h"
#include <blue/core/queue.h>
#include <blue/ds/dict.h>
#include <blue/ds/string.h>
#include <fx/core/queue.h>
#include <fx/ds/dict.h>
#include <fx/ds/string.h>
#include <stdint.h>
struct lex {
@@ -14,10 +14,10 @@ struct lex {
struct line_source *lex_source;
enum status lex_status;
b_queue lex_queue;
fx_queue lex_queue;
b_string *lex_temp;
b_queue lex_state;
fx_string *lex_temp;
fx_queue lex_state;
unsigned int lex_brace_depth;
struct file_cell lex_token_start, lex_token_end;
@@ -27,8 +27,8 @@ struct lex_symbol_node {
char s_char;
struct lex_token_def *s_def;
b_queue_entry s_entry;
b_queue s_children;
fx_queue_entry s_entry;
fx_queue s_children;
};
struct lex_token_def {

View File

@@ -3,11 +3,11 @@
enum status line_source_init(
struct line_source *src,
const char *path,
b_stream *stream)
fx_stream *stream)
{
memset(src, 0x0, sizeof *src);
src->s_lines = b_array_create();
src->s_lines = fx_array_create();
if (!src->s_lines) {
return ERR_NO_MEMORY;
@@ -24,11 +24,11 @@ enum status line_source_init(
void line_source_cleanup(struct line_source *src)
{
if (src->s_linebuf_ptr) {
b_iterator_unref(src->s_linebuf_ptr);
fx_iterator_unref(src->s_linebuf_ptr);
}
if (src->s_lines) {
b_array_unref(src->s_lines);
fx_array_unref(src->s_lines);
}
memset(src, 0x0, sizeof *src);
@@ -51,31 +51,31 @@ static enum status refill_linebuf(struct line_source *src)
}
if (src->s_linebuf_ptr) {
b_iterator_unref(src->s_linebuf_ptr);
fx_iterator_unref(src->s_linebuf_ptr);
src->s_linebuf_ptr = NULL;
}
b_stringstream *s = b_stringstream_create();
fx_stringstream *s = fx_stringstream_create();
b_status status = b_stream_read_line_s(src->s_stream, s);
fx_status status = fx_stream_read_line_s(src->s_stream, s);
if (status == B_ERR_NO_DATA) {
if (status == FX_ERR_NO_DATA) {
return ERR_EOF;
}
if (!B_OK(status)) {
if (!FX_OK(status)) {
return ERR_INTERNAL_FAILURE;
}
b_string *line = b_string_create();
b_string_replace_all_with_stringstream(line, s);
b_stringstream_unref(s);
fx_string *line = fx_string_create();
fx_string_replace_all_with_stringstream(line, s);
fx_stringstream_unref(s);
b_array_append(src->s_lines, line);
b_string_unref(line);
fx_array_append(src->s_lines, line);
fx_string_unref(line);
src->s_linebuf = line;
src->s_linebuf_ptr = b_iterator_begin(src->s_linebuf);
src->s_linebuf_ptr = fx_iterator_begin(src->s_linebuf);
return SUCCESS;
}
@@ -84,7 +84,7 @@ static int peek(struct line_source *src)
{
enum status status = SUCCESS;
if (!src->s_linebuf_ptr || !b_iterator_is_valid(src->s_linebuf_ptr)) {
if (!src->s_linebuf_ptr || !fx_iterator_is_valid(src->s_linebuf_ptr)) {
status = refill_linebuf(src);
}
@@ -92,11 +92,11 @@ static int peek(struct line_source *src)
return -status;
}
if (b_string_get_size(src->s_linebuf, B_STRLEN_NORMAL) == 0) {
if (fx_string_get_size(src->s_linebuf, FX_STRLEN_NORMAL) == 0) {
return -ERR_EOF;
}
b_wchar c = b_iterator_get_value(src->s_linebuf_ptr).v_int;
fx_wchar c = fx_iterator_get_value(src->s_linebuf_ptr).v_int;
return c;
}
@@ -104,7 +104,7 @@ static int advance(struct line_source *src)
{
enum status status = SUCCESS;
if (!b_iterator_is_valid(src->s_linebuf_ptr)) {
if (!fx_iterator_is_valid(src->s_linebuf_ptr)) {
status = refill_linebuf(src);
}
@@ -112,12 +112,12 @@ static int advance(struct line_source *src)
return -status;
}
if (b_string_get_size(src->s_linebuf, B_STRLEN_NORMAL) == 0) {
if (fx_string_get_size(src->s_linebuf, FX_STRLEN_NORMAL) == 0) {
return -ERR_EOF;
}
b_wchar c = b_iterator_get_value(src->s_linebuf_ptr).v_int;
b_iterator_move_next(src->s_linebuf_ptr);
fx_wchar c = fx_iterator_get_value(src->s_linebuf_ptr).v_int;
fx_iterator_move_next(src->s_linebuf_ptr);
src->s_cursor.c_col++;
if (c == '\n') {
@@ -127,12 +127,12 @@ static int advance(struct line_source *src)
return c;
}
b_wchar line_source_peekc(struct line_source *src)
fx_wchar line_source_peekc(struct line_source *src)
{
return peek(src);
}
b_wchar line_source_getc(struct line_source *src)
fx_wchar line_source_getc(struct line_source *src)
{
return advance(src);
}
@@ -140,7 +140,7 @@ b_wchar line_source_getc(struct line_source *src)
enum status line_source_get_row(
struct line_source *src,
size_t row,
const b_string **out)
const fx_string **out)
{
if (row == 0) {
return ERR_INVALID_ARGUMENT;
@@ -148,11 +148,11 @@ enum status line_source_get_row(
row--;
if (row >= b_array_size(src->s_lines)) {
if (row >= fx_array_size(src->s_lines)) {
return ERR_EOF;
}
b_string *line = b_array_at(src->s_lines, row);
fx_string *line = fx_array_at(src->s_lines, row);
*out = line;
return SUCCESS;
@@ -160,5 +160,5 @@ enum status line_source_get_row(
bool line_source_input_available(struct line_source *src)
{
return src->s_linebuf_ptr && b_iterator_is_valid(src->s_linebuf_ptr);
return src->s_linebuf_ptr && fx_iterator_is_valid(src->s_linebuf_ptr);
}

View File

@@ -4,16 +4,16 @@
#include "file-span.h"
#include "status.h"
#include <blue/core/stream.h>
#include <blue/ds/array.h>
#include <blue/ds/string.h>
#include <fx/core/stream.h>
#include <fx/ds/array.h>
#include <fx/ds/string.h>
struct line_source {
b_stream *s_stream;
fx_stream *s_stream;
const char *s_path;
b_string *s_linebuf;
b_iterator *s_linebuf_ptr;
b_array *s_lines;
fx_string *s_linebuf;
fx_iterator *s_linebuf_ptr;
fx_array *s_lines;
struct file_cell s_cursor;
};
@@ -21,18 +21,18 @@ struct line_source {
extern enum status line_source_init(
struct line_source *src,
const char *path,
b_stream *stream);
fx_stream *stream);
extern void line_source_cleanup(struct line_source *src);
extern const char *line_source_get_path(const struct line_source *src);
extern const struct file_cell *line_source_get_cursor(
const struct line_source *src);
extern b_wchar line_source_peekc(struct line_source *src);
extern b_wchar line_source_getc(struct line_source *src);
extern fx_wchar line_source_peekc(struct line_source *src);
extern fx_wchar line_source_getc(struct line_source *src);
extern enum status line_source_get_row(
struct line_source *src,
size_t row,
const b_string **out);
const fx_string **out);
extern bool line_source_input_available(struct line_source *src);

View File

@@ -6,9 +6,9 @@
#include "msg.h"
#include "parse.h"
#include <blue/cmd.h>
#include <blue/io/file.h>
#include <blue/io/path.h>
#include <fx/cmd.h>
#include <fx/io/file.h>
#include <fx/io/path.h>
#define CMD_ID 0
@@ -20,71 +20,71 @@ enum {
int main(int argc, const char **argv)
{
return b_command_dispatch(CMD_ID, argc, argv);
return fx_command_dispatch(CMD_ID, argc, argv);
}
static void print_msg(struct msg_definition *msg)
{
printf(" msg: %s\n", msg->msg_name);
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
printf(" param:");
type_print(param->p_type);
printf(" %s\n", param->p_name);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
printf(" result:");
type_print(param->p_type);
printf(" %s\n", param->p_name);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
}
static void print_interface(struct interface_definition *iface)
{
printf("interface: %s\n", iface->if_name);
b_queue_entry *entry = b_queue_first(&iface->if_msg);
fx_queue_entry *entry = fx_queue_first(&iface->if_msg);
while (entry) {
struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
= fx_unbox(struct msg_definition, entry, msg_entry);
print_msg(msg);
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
}
static int xpcg(
const b_command *self,
const b_arglist *opt,
const b_array *args)
const fx_command *self,
const fx_arglist *opt,
const fx_array *args)
{
const char *path = NULL;
b_arglist_get_string(opt, B_COMMAND_INVALID_ID, ARG_SRCPATH, 0, &path);
fx_arglist_get_string(opt, FX_COMMAND_INVALID_ID, ARG_SRCPATH, 0, &path);
if (!path) {
b_arglist_report_missing_args(
fx_arglist_report_missing_args(
opt,
B_COMMAND_INVALID_ID,
FX_COMMAND_INVALID_ID,
ARG_SRCPATH,
0);
return -1;
}
b_file *file = NULL;
b_result result
= b_file_open(NULL, B_RV_PATH(path), B_FILE_READ_ONLY, &file);
if (b_result_is_error(result)) {
b_throw(result);
fx_file *file = NULL;
fx_result result
= fx_file_open(NULL, FX_RV_PATH(path), FX_FILE_READ_ONLY, &file);
if (fx_result_is_error(result)) {
fx_throw(result);
return -1;
}
@@ -133,37 +133,37 @@ static int xpcg(
return err;
}
B_COMMAND(CMD_ID, B_COMMAND_INVALID_ID)
FX_COMMAND(CMD_ID, FX_COMMAND_INVALID_ID)
{
B_COMMAND_NAME("xpcg");
B_COMMAND_DESC("xpc interface generator.");
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
B_COMMAND_FUNCTION(xpcg);
B_COMMAND_HELP_OPTION();
FX_COMMAND_NAME("xpcg");
FX_COMMAND_DESC("xpc interface generator.");
FX_COMMAND_FLAGS(FX_COMMAND_SHOW_HELP_BY_DEFAULT);
FX_COMMAND_FUNCTION(xpcg);
FX_COMMAND_HELP_OPTION();
B_COMMAND_ARG(ARG_SRCPATH)
FX_COMMAND_ARG(ARG_SRCPATH)
{
B_ARG_NAME("source-file");
B_ARG_DESC("the interface file to compile.");
B_ARG_NR_VALUES(1);
FX_ARG_NAME("source-file");
FX_ARG_DESC("the interface file to compile.");
FX_ARG_NR_VALUES(1);
}
B_COMMAND_OPTION(OPT_BACKEND)
FX_COMMAND_OPTION(OPT_BACKEND)
{
B_OPTION_LONG_NAME("backend");
B_OPTION_SHORT_NAME('b');
B_OPTION_DESC("which backend to use.");
B_OPTION_ARG(OPT_BACKEND_ARG_NAME)
FX_OPTION_LONG_NAME("backend");
FX_OPTION_SHORT_NAME('b');
FX_OPTION_DESC("which backend to use.");
FX_OPTION_ARG(OPT_BACKEND_ARG_NAME)
{
B_ARG_NAME("backend-name");
B_ARG_NR_VALUES(1);
B_ARG_ALLOWED_VALUES("c-mpc");
FX_ARG_NAME("backend-name");
FX_ARG_NR_VALUES(1);
FX_ARG_ALLOWED_VALUES("c-mpc");
}
}
B_COMMAND_USAGE()
FX_COMMAND_USAGE()
{
B_COMMAND_USAGE_ARG(ARG_SRCPATH);
B_COMMAND_USAGE_OPT(OPT_BACKEND);
FX_COMMAND_USAGE_ARG(ARG_SRCPATH);
FX_COMMAND_USAGE_OPT(OPT_BACKEND);
}
}

View File

@@ -1,6 +1,6 @@
#include "msg.h"
#include <blue/ds/string.h>
#include <fx/ds/string.h>
#include <stdlib.h>
#include <string.h>
@@ -13,7 +13,7 @@ struct msg_definition *msg_definition_create(const char *name, long long id)
memset(out, 0x0, sizeof *out);
out->msg_name = b_strdup(name);
out->msg_name = fx_strdup(name);
out->msg_id = id;
return out;
@@ -21,22 +21,22 @@ struct msg_definition *msg_definition_create(const char *name, long long id)
void msg_definition_destroy(struct msg_definition *msg)
{
b_queue_entry *entry = b_queue_pop_front(&msg->msg_params);
fx_queue_entry *entry = fx_queue_pop_front(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
free(param->p_name);
free(param);
entry = b_queue_pop_front(&msg->msg_params);
entry = fx_queue_pop_front(&msg->msg_params);
}
entry = b_queue_pop_front(&msg->msg_results);
entry = fx_queue_pop_front(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
free(param->p_name);
free(param);
entry = b_queue_pop_front(&msg->msg_results);
entry = fx_queue_pop_front(&msg->msg_results);
}
free(msg->msg_name);
@@ -45,15 +45,15 @@ void msg_definition_destroy(struct msg_definition *msg)
bool msg_definition_has_param(struct msg_definition *msg, const char *name)
{
b_queue_entry *entry = b_queue_first(&msg->msg_params);
fx_queue_entry *entry = fx_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
if (!strcmp(param->p_name, name)) {
return true;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return false;
@@ -61,15 +61,15 @@ bool msg_definition_has_param(struct msg_definition *msg, const char *name)
bool msg_definition_has_result(struct msg_definition *msg, const char *name)
{
b_queue_entry *entry = b_queue_first(&msg->msg_results);
fx_queue_entry *entry = fx_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
= fx_unbox(struct msg_parameter, entry, p_entry);
if (!strcmp(param->p_name, name)) {
return true;
}
entry = b_queue_next(entry);
entry = fx_queue_next(entry);
}
return false;
@@ -88,9 +88,9 @@ int msg_definition_add_param(
memset(param, 0x0, sizeof *param);
param->p_type = type;
param->p_name = b_strdup(name);
param->p_name = fx_strdup(name);
b_queue_push_back(&msg->msg_params, &param->p_entry);
fx_queue_push_back(&msg->msg_params, &param->p_entry);
return 0;
}
@@ -107,8 +107,8 @@ int msg_definition_add_result(
memset(param, 0x0, sizeof *param);
param->p_type = type;
param->p_name = b_strdup(name);
param->p_name = fx_strdup(name);
b_queue_push_back(&msg->msg_results, &param->p_entry);
fx_queue_push_back(&msg->msg_results, &param->p_entry);
return 0;
}

View File

@@ -1,23 +1,23 @@
#ifndef XPCG_MSG_H_
#define XPCG_MSG_H_
#include <blue/core/queue.h>
#include <fx/core/queue.h>
struct type;
struct msg_parameter {
char *p_name;
const struct type *p_type;
b_queue_entry p_entry;
fx_queue_entry p_entry;
};
struct msg_definition {
char *msg_name;
long long msg_id;
b_queue_entry msg_entry;
fx_queue_entry msg_entry;
b_queue msg_params;
b_queue msg_results;
fx_queue msg_params;
fx_queue msg_results;
};
extern struct msg_definition *msg_definition_create(

View File

@@ -3,7 +3,7 @@
#include "file-span.h"
#include <blue/core/queue.h>
#include <fx/core/queue.h>
#define TOKEN_TYPE(tok) ((tok) ? (tok)->tok_type : TOK_NONE)
#define TOKEN_IS(tok, type) ((tok) && ((tok)->tok_type & (type)) != 0)
@@ -55,7 +55,7 @@ struct token {
struct file_span tok_location;
enum token_type tok_type;
enum token_value_type tok_value_type;
b_queue_entry tok_entry;
fx_queue_entry tok_entry;
union {
char *tok_str;

View File

@@ -4,6 +4,7 @@
enum type_id {
TYPE_NONE,
TYPE_INT,
TYPE_OFFSET,
TYPE_SIZE,
TYPE_STRING,
TYPE_BUFFER,