Compare commits

..

28 Commits

Author SHA1 Message Date
bd39cb11aa meta: update kernel 2026-03-15 09:50:38 +00:00
a01b5ddb11 cmake: add a simple does-the-os-boot-successfully test
the test will repeated boot the operating system and use the serial log to determine
if the boot was successful. if a problem is detected, a debugger is automatically
started and attached.
2026-03-15 09:49:51 +00:00
1e9fe24b39 ld: anonymous and file-backed mmap tests 2026-03-15 09:49:18 +00:00
9044281d1b bootstrap: use new libfs interface to handle requests 2026-03-15 09:48:47 +00:00
5dd99bb0a6 bootstrap: tar: fix pointer-alignment tar parsing issue 2026-03-15 09:47:58 +00:00
d03c750e4a cmake: ensure interface headers are regenerated when the corresponding .xpc file is changed 2026-03-15 09:47:03 +00:00
c66c7f3f3f x86_64: cmake: enable RDRAND support when running the kernel under qemu 2026-03-15 09:46:32 +00:00
29acfcee69 toolchain: xpcg: fix output header not being truncated 2026-03-15 09:45:31 +00:00
fea89d675e toolchain: xpcg: fix incorrect variable/type names in output header 2026-03-15 09:45:08 +00:00
eb8d9c3512 interface: fs: add error code result to fs.map() 2026-03-15 09:44:32 +00:00
0c56c645ac lib: fs: implement memory-mapped file i/o 2026-03-15 09:43:49 +00:00
68b7783f32 lib: xpc: implement non-blocking msg receive function 2026-03-15 09:43:22 +00:00
ea2b0d3986 lib: xpc: implement writing to local buffers 2026-03-15 09:43:00 +00:00
c9ccebacfc lib: launch: update to use new address-space api 2026-03-15 09:42:22 +00:00
5ad5f57a76 lib: c: update libheap to use new address-space api 2026-03-15 09:42:03 +00:00
f441d633b2 lib: c: implement mmap() 2026-03-15 09:41:25 +00:00
9ea3441fcc lib: c: move io sys headers to include/sys 2026-03-15 09:40:37 +00:00
86ca343cf0 interface: fs: remove old ifc definition file 2026-03-10 19:20:18 +00:00
b680ffdd5b meta: update kernel 2026-03-10 19:16:51 +00:00
14799e0d58 ld: use unistd i/o functions to open/read library files 2026-03-10 19:16:46 +00:00
b7452a449b bootstrap: update tarfs driver with libfs support 2026-03-10 19:16:22 +00:00
ea6ec785a9 lib: c: re-organise into separate static modules, plus a single shared library 2026-03-10 19:15:59 +00:00
6d88cf4bf3 lib: fs: implement mounting filesystems; reading, writing from files 2026-03-10 19:15:26 +00:00
aef0163017 lib: add libxpc to implement functionality needed by xpc interfaces 2026-03-10 19:14:37 +00:00
b0fda122e0 cmake: define BUILD_STATIC and BUILD_SHARED for library builds 2026-03-10 19:14:00 +00:00
79af171384 interface: fs: replace ifc definition with xpcg 2026-03-10 19:13:24 +00:00
5931642cc2 cmake: update inteface functions to use xpcg 2026-03-10 19:13:01 +00:00
26a49162e6 toolchain: replace ifc interface compiler with xpcg
xpcg is used to generate xpc interfaces
2026-03-10 19:12:14 +00:00
97 changed files with 3289 additions and 1036 deletions

View File

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

View File

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

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

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

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
find_program(IFC find_program(XPCG
NAMES ifc NAMES xpcg
REQUIRED REQUIRED
HINTS ${BUILD_TOOLS_DIR}) HINTS ${BUILD_TOOLS_DIR})
message(STATUS "Found interface compiler: ${IFC}") message(STATUS "Found interface generator: ${XPCG}")
function(add_interface) function(add_interface)
set(options) set(options)
@@ -20,9 +20,10 @@ function(add_interface)
add_custom_command( add_custom_command(
OUTPUT ${header_path} OUTPUT ${header_path}
COMMAND ${IFC} ${arg_PATH} COMMAND ${XPCG} ${arg_PATH}
DEPENDS ${arg_PATH}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${arg_PARENT_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${arg_PARENT_DIR}
COMMENT "Compiling interface: ${arg_NAME}") COMMENT "Generating interface: ${arg_NAME}")
add_custom_target(ifgen-${arg_NAME} ALL add_custom_target(ifgen-${arg_NAME} ALL
DEPENDS ${header_path}) DEPENDS ${header_path})

View File

@@ -64,6 +64,8 @@ function(rosetta_add_library)
${arg_SOURCES} ${arg_SOURCES}
${arg_HEADERS}) ${arg_HEADERS})
set_target_properties(${static_lib_name} PROPERTIES OUTPUT_NAME "${lib_name}") set_target_properties(${static_lib_name} PROPERTIES OUTPUT_NAME "${lib_name}")
target_compile_definitions(${static_lib_name} PRIVATE
BUILD_STATIC=1)
set(targets ${targets} ${static_lib_name}) set(targets ${targets} ${static_lib_name})
if (arg_PUBLIC_INCLUDE_DIRS) if (arg_PUBLIC_INCLUDE_DIRS)
@@ -86,6 +88,8 @@ function(rosetta_add_library)
PATH ${arg_PUBLIC_INCLUDE_DIRS}) PATH ${arg_PUBLIC_INCLUDE_DIRS})
endif () endif ()
target_compile_definitions(${shared_lib_name} PRIVATE
BUILD_SHARED=1)
set_target_properties(${shared_lib_name} PROPERTIES set_target_properties(${shared_lib_name} PROPERTIES
SOVERSION 1) SOVERSION 1)
target_link_options(${shared_lib_name} PRIVATE -Wl,--soname,${soname}) target_link_options(${shared_lib_name} PRIVATE -Wl,--soname,${soname})

View File

@@ -1,4 +1,4 @@
file(GLOB if_files *.if) file(GLOB if_files *.xpc)
foreach (file ${if_files}) foreach (file ${if_files})
get_filename_component(name ${file} NAME_WLE) get_filename_component(name ${file} NAME_WLE)

View File

@@ -1,3 +0,0 @@
interface fs {
msg open(string path, int flags) -> (int err);
}

9
interface/fs.xpc Normal file
View File

@@ -0,0 +1,9 @@
interface fs 6400;
func open[0](path: string, flags: int) -> (err: int);
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) -> (err: int, vmo: handle);

2
kernel

Submodule kernel updated: 1d4cb882a8...0af35c70ef

View File

@@ -1,4 +1,4 @@
set(source_dirs core malloc) set(source_dirs core malloc io)
set(public_include_dirs set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include) ${CMAKE_CURRENT_SOURCE_DIR}/include)
@@ -26,5 +26,5 @@ bsp_add_library(
NAME libc NAME libc
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(libc libmango) target_link_libraries(libc libmango libxpc-static interface::fs)
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1) target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1)

View File

@@ -1,4 +1,4 @@
set(source_dirs stdio string) set(source_dirs stdio string errno)
foreach (dir ${source_dirs}) foreach (dir ${source_dirs})
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c) file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
@@ -21,3 +21,5 @@ sysroot_add_library(
NAME libc-core NAME libc-core
HEADER_DIR /usr/include HEADER_DIR /usr/include
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(libc-core libmango)

View File

@@ -0,0 +1,54 @@
#include <errno.h>
#include <mango/status.h>
#if defined(BUILD_STATIC)
int __set_errno(int err)
{
return -err;
}
#endif
#if defined(BUILD_SHARED)
int __set_errno(int err)
{
/* TODO */
return -1;
}
#endif
int __errno_from_kern_status(unsigned int err)
{
switch (err) {
case KERN_OK:
return SUCCESS;
case KERN_UNIMPLEMENTED:
return ENOSYS;
case KERN_NAME_EXISTS:
return EEXIST;
case KERN_INVALID_ARGUMENT:
return EINVAL;
case KERN_UNSUPPORTED:
return ENOTSUP;
case KERN_NO_MEMORY:
return ENOMEM;
case KERN_NO_ENTRY:
return ENOENT;
case KERN_WOULD_BLOCK:
return EWOULDBLOCK;
case KERN_NO_DEVICE:
return ENODEV;
case KERN_DEVICE_STUCK:
case KERN_IO_ERROR:
return EIO;
case KERN_FATAL_ERROR:
return ENXIO;
case KERN_BAD_STATE:
return EPERM;
case KERN_MEMORY_FAULT:
return EFAULT;
case KERN_ACCESS_DENIED:
return EACCES;
default:
return EINVAL;
}
}

View File

@@ -139,4 +139,7 @@
#define EQFULL 106 /* Interface output queue is full */ #define EQFULL 106 /* Interface output queue is full */
#define ELAST 106 /* Must be equal largest errno */ #define ELAST 106 /* Must be equal largest errno */
extern int __set_errno(int err);
extern int __errno_from_kern_status(unsigned int err);
#endif #endif

View File

@@ -14,4 +14,6 @@ extern int strncmp(const char *s1, const char *s2, unsigned long n);
extern void *memset(void *str, int c, size_t n); extern void *memset(void *str, int c, size_t n);
extern void *memcpy(void *dst, const void *src, size_t len); extern void *memcpy(void *dst, const void *src, size_t len);
extern char *strdup(char *s);
#endif #endif

View File

@@ -0,0 +1,45 @@
#ifndef SYS_MMAN_H_
#define SYS_MMAN_H_
#include <mango/types.h>
#include <stddef.h>
#define PROT_NONE 0x00u
#define PROT_EXEC 0x01u
#define PROT_READ 0x02u
#define PROT_WRITE 0x04u
#define MAP_FAILED ((void *)-1)
#define MAP_SHARED 0x01u
#define MAP_SHARED_VALIDATE 0x02u
#define MAP_PRIVATE 0x04u
#define MAP_32BIT 0x08u
#define MAP_ANON MAP_ANONYMOUS
#define MAP_ANONYMOUS 0x10u
#define MAP_DENYWRITE 0x20u
#define MAP_EXECUTABLE 0x40u
#define MAP_FILE 0x80u
#define MAP_FIXED 0x100u
#define MAP_FIXED_NOREPLACE 0x300u
#define MAP_GROWSDOWN 0x400u
#define MAP_HUGETLB 0x800u
#define MAP_HUGE_2MB 0x1000u
#define MAP_HUGE_1GB 0x2000u
#define MAP_LOCKED 0x4000u
#define MAP_NONBLOCK 0x8000u
#define MAP_NORESERVE 0x10000u
#define MAP_POPULATE 0x20000u
#define MAP_STACK 0x40000u
#define MAP_SYNC 0x80000u
#define MAP_UNINITIALIZED 0x100000u
extern void *mmap(
void *addr,
size_t length,
int prot,
int flags,
int fd,
off_t offset);
#endif

View File

@@ -0,0 +1,18 @@
#ifndef SYS_REMOTE_H_
#define SYS_REMOTE_H_
#include <mango/types.h>
#include <stdbool.h>
enum sys_remote_id {
SYS_REMOTE_NONE,
SYS_REMOTE_NSD,
};
extern bool sys_remote_get(
enum sys_remote_id id,
tid_t *out_tid,
unsigned int *out_chid);
extern void sys_remote_set(enum sys_remote_id id, tid_t tid, unsigned int chid);
#endif

View File

@@ -1,9 +1,12 @@
#ifndef UNISTD_H_ #ifndef UNISTD_H_
#define UNISTD_H_ #define UNISTD_H_
#include <stdint.h> #include <stddef.h>
extern int open(const char *path, int flags); extern int open(const char *path, int flags);
extern int close(int fd); extern int close(int fd);
extern int read(int fd, void *buf, size_t count);
extern int write(int fd, const void *buf, size_t count);
#endif #endif

View File

@@ -0,0 +1,33 @@
set(source_dirs unistd stdio)
file(GLOB sources *.c *.h)
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_RECURSE sub_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
set(headers ${headers} ${sub_headers})
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
rosetta_add_library(STATIC
NAME libc-io
PUBLIC_INCLUDE_DIRS
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc-io
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libc-io libc-core interface::fs libxpc-static libmango)

2
lib/libc/io/fs.c Normal file
View File

@@ -0,0 +1,2 @@
#define MSG_IMPLEMENTATION
#include <rosetta/fs.h>

45
lib/libc/io/remote.c Normal file
View File

@@ -0,0 +1,45 @@
#include <sys/remote.h>
#define TID_INVALID ((tid_t) - 1)
#define CHID_INVALID ((unsigned int)-1)
struct remote {
tid_t tid;
unsigned int chid;
};
static struct remote remotes[] = {
[SYS_REMOTE_NONE] = {.tid = TID_INVALID, .chid = CHID_INVALID},
[SYS_REMOTE_NSD] = {.tid = TID_INVALID, .chid = CHID_INVALID},
};
static const size_t nr_remotes = sizeof remotes / sizeof remotes[0];
bool sys_remote_get(
enum sys_remote_id id,
tid_t *out_tid,
unsigned int *out_chid)
{
if (id < 0 || id >= nr_remotes) {
return false;
}
const struct remote *remote = &remotes[id];
if (remote->tid == TID_INVALID || remote->chid == CHID_INVALID) {
return false;
}
*out_tid = remote->tid;
*out_chid = remote->chid;
return true;
}
void sys_remote_set(enum sys_remote_id id, tid_t tid, unsigned int chid)
{
if (id < 0 || id >= nr_remotes) {
return;
}
struct remote *remote = &remotes[id];
remote->tid = tid;
remote->chid = chid;
}

View File

146
lib/libc/io/unistd/mmap.c Normal file
View File

@@ -0,0 +1,146 @@
#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;
}
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
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;
}
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;
}

40
lib/libc/io/unistd/open.c Normal file
View File

@@ -0,0 +1,40 @@
#include <errno.h>
#include <mango/handle.h>
#include <mango/msg.h>
#include <rosetta/fs.h>
#include <sys/remote.h>
int open(const char *path, int flags)
{
tid_t remote_tid;
unsigned int remote_chid;
if (!sys_remote_get(SYS_REMOTE_NSD, &remote_tid, &remote_chid)) {
return __set_errno(ENXIO);
}
kern_handle_t port;
kern_status_t status = port_create(&port);
if (status != KERN_OK) {
return __set_errno(__errno_from_kern_status(status));
}
status = port_connect(port, remote_tid, remote_chid);
if (status != KERN_OK) {
kern_handle_close(port);
return __set_errno(__errno_from_kern_status(status));
}
int err = SUCCESS;
status = fs_open(port, path, flags, &err);
if (status != KERN_OK) {
kern_handle_close(port);
return __set_errno(__errno_from_kern_status(status));
}
if (err != SUCCESS) {
kern_handle_close(port);
return __set_errno(err);
}
return (int)port;
}

21
lib/libc/io/unistd/read.c Normal file
View File

@@ -0,0 +1,21 @@
#include <errno.h>
#include <mango/handle.h>
#include <mango/msg.h>
#include <rosetta/fs.h>
#include <sys/remote.h>
int read(int fd, void *buf, size_t count)
{
int err;
size_t nr_read;
kern_status_t status = fs_read(fd, count, &err, &nr_read, buf, count);
if (status != KERN_OK) {
return __set_errno(__errno_from_kern_status(status));
}
if (err != SUCCESS) {
return __set_errno(err);
}
return nr_read;
}

View File

View File

@@ -1,4 +1,4 @@
set(source_dirs stdlib) set(source_dirs stdlib string)
file(GLOB sources *.c *.h) file(GLOB sources *.c *.h)

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,14 @@
#include <stdlib.h>
#include <string.h>
char *strdup(char *s)
{
size_t len = strlen(s);
char *out = malloc(len + 1);
if (!out) {
return NULL;
}
memcpy(out, s, len + 1);
return out;
}

View File

@@ -23,7 +23,7 @@ sysroot_add_library(
HEADER_DIR /usr/include HEADER_DIR /usr/include
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(libfs libmango interface::fs libc) target_link_libraries(libfs libmango interface::fs libc libxpc)
target_link_libraries(libfs-static libmango interface::fs libc-core) target_link_libraries(libfs-static libmango interface::fs libc-core libxpc-static)
set_target_properties(libfs-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE) set_target_properties(libfs-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE)

View File

@@ -1,9 +1,23 @@
#include "btree.h" #include "btree.h"
#include "file.h" #include "file.h"
#include "interface.h" #include "interface.h"
#include "mapping.h"
#include <fs/allocator.h> #include <fs/allocator.h>
#include <fs/context.h> #include <fs/context.h>
#include <fs/dentry.h>
#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_GET(struct fs_file, unsigned long, f_node, f_id, get_file);
BTREE_DEFINE_SIMPLE_INSERT(struct fs_file, f_node, f_id, put_file); BTREE_DEFINE_SIMPLE_INSERT(struct fs_file, f_node, f_id, put_file);
@@ -12,14 +26,21 @@ struct fs_context {
struct fs_superblock *ctx_sb; struct fs_superblock *ctx_sb;
struct fs_allocator *ctx_alloc; struct fs_allocator *ctx_alloc;
struct btree ctx_filelist; struct btree ctx_filelist;
kern_handle_t ctx_vm_controller;
kern_handle_t ctx_channel;
kern_handle_t ctx_temp_object;
void *ctx_temp_object_buf;
struct fs_vtable ctx_vtable; struct fs_vtable ctx_vtable;
}; };
struct fs_context *fs_context_create( struct fs_context *fs_context_create(struct fs_allocator *alloc)
struct fs_allocator *alloc,
struct fs_superblock *sb)
{ {
kern_handle_t self, address_space;
task_self(&self);
task_get_address_space(self, &address_space);
kern_handle_close(self);
struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx); struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx);
if (!ctx) { if (!ctx) {
return NULL; return NULL;
@@ -27,10 +48,48 @@ struct fs_context *fs_context_create(
memset(ctx, 0x0, sizeof *ctx); memset(ctx, 0x0, sizeof *ctx);
ctx->ctx_sb = sb; 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);
if (status != KERN_OK) {
kern_handle_close(ctx->ctx_temp_object);
kern_handle_close(ctx->ctx_vm_controller);
fs_free(alloc, ctx);
return NULL;
}
ctx->ctx_temp_object_buf = (void *)temp_buffer;
ctx->ctx_alloc = alloc; ctx->ctx_alloc = alloc;
ctx->ctx_vtable.open = fs_msg_open; ctx->ctx_vtable.open = fs_msg_open;
ctx->ctx_vtable.close = fs_msg_close;
ctx->ctx_vtable.read = fs_msg_read;
ctx->ctx_vtable.write = fs_msg_write;
ctx->ctx_vtable.map = fs_msg_map;
return ctx; return ctx;
} }
@@ -40,6 +99,141 @@ void fs_context_destroy(struct fs_context *ctx)
fs_free(ctx->ctx_alloc, ctx); fs_free(ctx->ctx_alloc, ctx);
} }
enum fs_status fs_context_mount_filesystem(
struct fs_context *ctx,
fs_mount_function_t func,
void *arg,
enum fs_mount_flags flags)
{
if (!func) {
return FS_ERR_INVALID_ARGUMENT;
}
struct fs_superblock *sb = NULL;
enum fs_status status = func(ctx, arg, flags, &sb);
if (status != FS_SUCCESS) {
return status;
}
if (!sb) {
return FS_ERR_INTERNAL_FAILURE;
}
ctx->ctx_sb = sb;
return FS_SUCCESS;
}
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_logf("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_logf(
"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_logf(
"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,
mapping->m_file_offset + packet.req_offset,
length);
if (status != FS_SUCCESS) {
kern_logf("map-read failed with code %d", status);
return status;
}
vm_controller_supply_pages(
ctx->ctx_vm_controller,
mapping->m_vmo,
packet.req_offset,
ctx->ctx_temp_object,
0,
packet.req_length);
return FS_SUCCESS;
}
enum fs_status fs_context_handle_request(struct fs_context *ctx)
{
kern_wait_item_t waiters[] = {
{
.w_handle = ctx->ctx_channel,
.w_waitfor = CHANNEL_SIGNAL_MSG_RECEIVED,
},
{
.w_handle = ctx->ctx_vm_controller,
.w_waitfor = VM_CONTROLLER_SIGNAL_REQUEST_RECEIVED,
},
};
const size_t nr_waiters = sizeof waiters / sizeof waiters[0];
kern_status_t kstatus = kern_object_wait(waiters, nr_waiters);
if (kstatus != KERN_OK) {
return FS_ERR_INTERNAL_FAILURE;
}
if (waiters[0].w_observed & CHANNEL_SIGNAL_MSG_RECEIVED) {
return handle_msg(ctx);
}
if (waiters[1].w_observed & VM_CONTROLLER_SIGNAL_REQUEST_RECEIVED) {
return handle_page_request(ctx);
}
return FS_SUCCESS;
}
struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id) struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id)
{ {
struct fs_file *f = get_file(&ctx->ctx_filelist, id); struct fs_file *f = get_file(&ctx->ctx_filelist, id);
@@ -58,29 +252,104 @@ struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id)
return f; return f;
} }
struct fs_file *fs_context_get_file(struct fs_context *ctx, unsigned long id)
{
return get_file(&ctx->ctx_filelist, id);
}
void fs_context_close_file(struct fs_context *ctx, struct fs_file *f) void fs_context_close_file(struct fs_context *ctx, struct fs_file *f)
{ {
} }
struct fs_dentry *fs_context_resolve_path( static size_t get_first_path_component(const char *in, char *out, size_t max)
struct fs_context *ctx,
const char *path)
{ {
return NULL; size_t i = 0;
while (i < max - 1) {
if (in[i] == '\0' || in[i] == '/') {
break;
}
out[i] = in[i];
i++;
}
out[i] = '\0';
return i;
} }
kern_status_t fs_context_dispatch_msg( extern enum fs_status fs_context_resolve_path(
struct fs_context *ctx, struct fs_context *ctx,
kern_handle_t channel, const char *path,
struct msg_endpoint *sender, struct fs_dentry **out)
struct msg_header *hdr)
{ {
return fs_dispatch( if (!ctx->ctx_sb || !ctx->ctx_sb->s_root) {
channel, return FS_ERR_NO_ENTRY;
&ctx->ctx_vtable, }
sender,
hdr, struct fs_dentry *cur = ctx->ctx_sb->s_root;
NULL,
0, char tok[256];
ctx);
while (*path != '\0') {
while (*path == '/') {
path++;
}
size_t tok_len
= get_first_path_component(path, tok, sizeof tok);
if (!tok_len) {
break;
}
bool is_dir = *(path + tok_len) != '\0';
if (cur->d_inode->i_mode != FS_INODE_DIR) {
return FS_ERR_NOT_DIRECTORY;
}
struct fs_dentry *next = NULL;
enum fs_status status
= fs_inode_lookup(cur->d_inode, tok, &next);
if (status != FS_SUCCESS) {
return status;
}
if (!next) {
return FS_ERR_INTERNAL_FAILURE;
}
cur = next;
path += tok_len;
}
*out = cur;
return FS_SUCCESS;
}
kern_status_t fs_context_dispatch_msg(struct fs_context *ctx, xpc_msg_t *msg)
{
return fs_dispatch(NULL, msg, &ctx->ctx_vtable, ctx);
}
void *fs_context_alloc(struct fs_context *ctx, size_t count)
{
return fs_alloc(ctx->ctx_alloc, count);
}
void *fs_context_calloc(struct fs_context *ctx, size_t count, size_t sz)
{
return fs_calloc(ctx->ctx_alloc, count, sz);
}
void *fs_context_realloc(struct fs_context *ctx, void *p, size_t count)
{
return fs_realloc(ctx->ctx_alloc, p, count);
}
void fs_context_free(struct fs_context *ctx, void *p)
{
fs_free(ctx->ctx_alloc, p);
} }

54
lib/libfs/file.c Normal file
View File

@@ -0,0 +1,54 @@
#include "file.h"
struct fs_inode *fs_file_get_inode(const struct fs_file *f)
{
return f->f_inode;
}
size_t fs_file_get_cursor(const struct fs_file *f)
{
return f->f_seek;
}
enum fs_status fs_file_read(
struct fs_file *f,
struct xpc_buffer *buf,
size_t count)
{
if (!f->f_ops || !f->f_ops->f_read) {
return FS_ERR_NOT_IMPLEMENTED;
}
off_t seek = f->f_seek;
enum fs_status status = f->f_ops->f_read(f, buf, count, &seek);
f->f_seek = seek;
return status;
}
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) {
return FS_ERR_NOT_IMPLEMENTED;
}
off_t seek = f->f_seek;
enum fs_status status = f->f_ops->f_write(f, buf, count, &seek);
f->f_seek = seek;
return status;
}

View File

@@ -2,8 +2,11 @@
#define _FS_FILE_H_ #define _FS_FILE_H_
#include "btree.h" #include "btree.h"
#include "queue.h"
#include <fs/dentry.h>
#include <fs/file.h> #include <fs/file.h>
#include <fs/inode.h>
struct fs_file { struct fs_file {
/* id of the open file, equal to the koid of the port being used to /* id of the open file, equal to the koid of the port being used to
@@ -12,6 +15,12 @@ struct fs_file {
struct btree_node f_node; struct btree_node f_node;
const struct fs_file_ops *f_ops; const struct fs_file_ops *f_ops;
off_t f_seek;
struct fs_inode *f_inode;
struct fs_dentry *f_dent;
struct queue f_mappings;
}; };
#endif #endif

View File

@@ -2,30 +2,60 @@
#define FS_CONTEXT_H_ #define FS_CONTEXT_H_
#include <rosetta/fs.h> #include <rosetta/fs.h>
#include <xpc/msg.h>
struct fs_file; struct fs_file;
struct fs_dentry;
struct fs_context; struct fs_context;
struct fs_allocator; struct fs_allocator;
struct fs_superblock; struct fs_superblock;
extern struct fs_context *fs_context_create( enum fs_mount_flags {
struct fs_allocator *alloc, FS_MOUNT_READONLY = 0x01u,
struct fs_superblock *sb); };
typedef enum fs_status (*fs_mount_function_t)(
struct fs_context *,
void *arg,
enum fs_mount_flags,
struct fs_superblock **);
extern struct fs_context *fs_context_create(struct fs_allocator *alloc);
extern void fs_context_destroy(struct fs_context *ctx); extern void fs_context_destroy(struct fs_context *ctx);
extern enum fs_status fs_context_mount_filesystem(
struct fs_context *ctx,
fs_mount_function_t func,
void *arg,
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( extern struct fs_file *fs_context_open_file(
struct fs_context *ctx, struct fs_context *ctx,
unsigned long id); unsigned long id);
extern struct fs_file *fs_context_get_file(
struct fs_context *ctx,
unsigned long id);
extern void fs_context_close_file(struct fs_context *ctx, struct fs_file *f); extern void fs_context_close_file(struct fs_context *ctx, struct fs_file *f);
extern struct fs_dentry *fs_context_resolve_path( extern enum fs_status fs_context_resolve_path(
struct fs_context *ctx, struct fs_context *ctx,
const char *path); const char *path,
struct fs_dentry **out);
extern kern_status_t fs_context_dispatch_msg( extern kern_status_t fs_context_dispatch_msg(
struct fs_context *ctx, struct fs_context *ctx,
kern_handle_t channel, xpc_msg_t *msg);
struct msg_endpoint *sender,
struct msg_header *hdr); extern void *fs_context_alloc(struct fs_context *ctx, size_t count);
extern void *fs_context_calloc(struct fs_context *ctx, size_t count, size_t sz);
extern void *fs_context_realloc(struct fs_context *ctx, void *p, size_t count);
extern void fs_context_free(struct fs_context *ctx, void *p);
#endif #endif

View File

@@ -13,6 +13,7 @@ struct fs_dentry {
struct fs_superblock *d_sb; struct fs_superblock *d_sb;
const struct fs_dentry_ops *d_ops; const struct fs_dentry_ops *d_ops;
void *d_fsdata; void *d_fsdata;
char *d_name;
}; };
#endif #endif

View File

@@ -5,11 +5,36 @@
#include <stddef.h> #include <stddef.h>
struct fs_file; struct fs_file;
struct xpc_buffer;
struct fs_file_ops { struct fs_file_ops {
ssize_t (*f_read)(struct fs_file *, void *, size_t); enum fs_status (*f_read)(
ssize_t (*f_write)(struct fs_file *, const void *, size_t); struct fs_file *,
off_t (*f_seek)(struct fs_file *, off_t, int); struct xpc_buffer *,
size_t,
off_t *);
enum fs_status (*f_write)(
struct fs_file *,
const struct xpc_buffer *,
size_t,
off_t *);
enum fs_status (*f_seek)(struct fs_file *, off_t, int);
}; };
extern struct fs_inode *fs_file_get_inode(const struct fs_file *f);
extern size_t fs_file_get_cursor(const struct fs_file *f);
extern enum fs_status fs_file_read(
struct fs_file *f,
struct xpc_buffer *buf,
size_t count);
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 #endif

View File

@@ -1,17 +1,37 @@
#ifndef FS_INODE_H_ #ifndef FS_INODE_H_
#define FS_INODE_H_ #define FS_INODE_H_
#include <fs/status.h>
#include <stddef.h>
struct fs_inode; struct fs_inode;
struct fs_dentry; struct fs_dentry;
struct fs_superblock; struct fs_superblock;
struct fs_file_ops;
enum fs_inode_mode {
FS_INODE_REG = 0x01u,
FS_INODE_DIR = 0x02u,
};
struct fs_inode_ops { struct fs_inode_ops {
int (*i_lookup)(struct fs_inode *, struct fs_dentry *); enum fs_status (*i_lookup)(
struct fs_inode *,
const char *,
struct fs_dentry **);
}; };
struct fs_inode { struct fs_inode {
enum fs_inode_mode i_mode;
struct fs_superblock *i_sb; struct fs_superblock *i_sb;
const struct fs_inode_ops *i_ops; const struct fs_inode_ops *i_ops;
const struct fs_file_ops *i_fops;
size_t i_size;
}; };
extern enum fs_status fs_inode_lookup(
struct fs_inode *inode,
const char *name,
struct fs_dentry **out);
#endif #endif

View File

@@ -0,0 +1,18 @@
#ifndef FS_STATUS_H_
#define FS_STATUS_H_
enum fs_status {
FS_SUCCESS = 0,
FS_ERR_NO_ENTRY,
FS_ERR_NO_MEMORY,
FS_ERR_INVALID_ARGUMENT,
FS_ERR_NOT_IMPLEMENTED,
FS_ERR_IS_DIRECTORY,
FS_ERR_NOT_DIRECTORY,
FS_ERR_BAD_STATE,
FS_ERR_INTERNAL_FAILURE,
};
extern int fs_status_to_errno(enum fs_status status);
#endif

13
lib/libfs/inode.c Normal file
View File

@@ -0,0 +1,13 @@
#include <fs/inode.h>
enum fs_status fs_inode_lookup(
struct fs_inode *inode,
const char *name,
struct fs_dentry **out)
{
if (!inode->i_ops || !inode->i_ops->i_lookup) {
return FS_ERR_NOT_IMPLEMENTED;
}
return inode->i_ops->i_lookup(inode, name, out);
}

View File

@@ -2,20 +2,49 @@
#define _FS_INTERFACE_H_ #define _FS_INTERFACE_H_
#include <mango/types.h> #include <mango/types.h>
#include <xpc/buffer.h>
#include <xpc/context.h>
#include <xpc/endpoint.h>
#include <xpc/string.h>
struct msg_endpoint; struct msg_endpoint;
extern kern_status_t fs_msg_open( extern kern_status_t fs_msg_open(
const struct msg_endpoint *sender, xpc_context_t *ctx,
const char *path, const xpc_endpoint_t *sender,
const xpc_string_t *path,
int flags, int flags,
int *out_err, int *out_err,
void *arg); void *arg);
extern kern_status_t fs_msg_close( extern kern_status_t fs_msg_close(
const struct msg_endpoint *sender, xpc_context_t *ctx,
const char *path, const xpc_endpoint_t *sender,
int flags,
int *out_err, int *out_err,
void *arg); void *arg);
extern kern_status_t fs_msg_read(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
size_t count,
int *out_err,
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_map(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
int prot,
int flags,
int *out_err,
kern_handle_t *out_vmo,
void *arg);
#endif #endif

View File

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

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

@@ -0,0 +1,74 @@
#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>
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 = fs_context_alloc(ctx, sizeof *mapping);
if (!mapping) {
*out_err = ENOMEM;
return KERN_OK;
}
kern_logf("mapping file %s", f->f_dent->d_name);
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);
*out_err = __errno_from_kern_status(status);
return KERN_OK;
}
mapping->m_file = f;
mapping->m_file_offset = 0;
kern_handle_duplicate(vmo, &mapping->m_vmo);
queue_push_back(&f->f_mappings, &mapping->m_entry);
*out_err = SUCCESS;
*out_vmo = vmo;
return KERN_OK;
}

View File

@@ -1,21 +1,53 @@
#include "../file.h"
#include <errno.h> #include <errno.h>
#include <fs/context.h> #include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
extern kern_status_t fs_msg_open( extern kern_status_t fs_msg_open(
const struct msg_endpoint *sender, xpc_context_t *xpc,
const char *path, xpc_endpoint_t *sender,
const xpc_string_t *path,
int flags, int flags,
int *out_err, int *out_err,
void *arg) void *arg)
{ {
char path_buf[4096];
size_t path_len = 0;
kern_status_t status
= xpc_string_read(path, path_buf, sizeof path_buf, &path_len);
if (status != KERN_OK) {
return status;
}
struct fs_context *ctx = arg; struct fs_context *ctx = arg;
struct fs_dentry *dent = fs_context_resolve_path(ctx, path); struct fs_file *f = fs_context_open_file(ctx, sender->e_port);
if (!dent) { if (!f) {
*out_err = ENOENT; *out_err = ENOMEM;
return KERN_OK; return KERN_OK;
} }
if (f->f_inode) {
*out_err = EBUSY;
return KERN_OK;
}
struct fs_dentry *dent = NULL;
enum fs_status fs_status
= fs_context_resolve_path(ctx, path_buf, &dent);
if (fs_status != FS_SUCCESS) {
fs_context_close_file(ctx, f);
*out_err = fs_status_to_errno(status);
return KERN_OK;
}
f->f_seek = 0;
f->f_dent = dent;
f->f_inode = dent->d_inode;
f->f_ops = dent->d_inode->i_fops;
*out_err = SUCCESS; *out_err = SUCCESS;
return KERN_OK; return KERN_OK;
} }

View File

@@ -0,0 +1,30 @@
#include <errno.h>
#include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
extern kern_status_t fs_msg_read(
xpc_context_t *xpc,
xpc_endpoint_t *sender,
size_t count,
int *out_err,
size_t *out_nr_read,
xpc_buffer_t *out_data,
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_read(f, out_data, count);
size_t end = fs_file_get_cursor(f);
*out_err = fs_status_to_errno(status);
*out_nr_read = end - start;
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;
}

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

@@ -0,0 +1,17 @@
#ifndef MAPPING_H_
#define MAPPING_H_
#include "queue.h"
#include <mango/types.h>
struct fs_file;
struct file_mapping {
struct fs_file *m_file;
kern_handle_t m_vmo;
off_t m_file_offset;
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

25
lib/libfs/status.c Normal file
View File

@@ -0,0 +1,25 @@
#include <errno.h>
#include <fs/status.h>
int fs_status_to_errno(enum fs_status status)
{
switch (status) {
case FS_SUCCESS:
return SUCCESS;
case FS_ERR_NO_ENTRY:
return ENOENT;
case FS_ERR_NO_MEMORY:
return ENOMEM;
case FS_ERR_INVALID_ARGUMENT:
return EINVAL;
case FS_ERR_NOT_IMPLEMENTED:
return ENOSYS;
case FS_ERR_IS_DIRECTORY:
return EISDIR;
case FS_ERR_NOT_DIRECTORY:
return ENOTDIR;
default:
return EINVAL;
}
}

View File

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

View File

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

View File

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

28
lib/libxpc/CMakeLists.txt Normal file
View File

@@ -0,0 +1,28 @@
file(GLOB sources
${CMAKE_CURRENT_SOURCE_DIR}/*.c)
file(GLOB headers
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/include/xpc/*.h)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
rosetta_add_library(
NAME libxpc SHARED STATIC
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libxpc
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
sysroot_add_library(
NAME libxpc-static
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libxpc libmango libc)
target_link_libraries(libxpc-static libmango libc-core)
#set_target_properties(libxpc-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE)

65
lib/libxpc/buffer.c Normal file
View File

@@ -0,0 +1,65 @@
#include <mango/status.h>
#include <string.h>
#include <xpc/buffer.h>
#include <xpc/msg.h>
kern_status_t xpc_buffer_read(
const xpc_buffer_t *buf,
void *out,
size_t max,
size_t *nr_read)
{
if ((buf->buf_flags & (XPC_BUFFER_F_IN | XPC_BUFFER_F_REMOTE))
!= (XPC_BUFFER_F_IN | XPC_BUFFER_F_REMOTE)) {
return KERN_BAD_STATE;
}
size_t to_read = max;
if (to_read > buf->buf_len) {
to_read = buf->buf_len;
}
kern_status_t status
= xpc_msg_read(buf->buf_origin, buf->buf_offset, out, to_read);
if (status != KERN_OK) {
return status;
}
/* TODO */
*nr_read = to_read;
return KERN_OK;
}
kern_status_t xpc_buffer_write(
xpc_buffer_t *buf,
const void *in,
size_t len,
size_t *nr_written)
{
if (!(buf->buf_flags & XPC_BUFFER_F_OUT)) {
return KERN_BAD_STATE;
}
size_t to_write = len;
if (to_write > buf->buf_max) {
to_write = buf->buf_max;
}
if (!(buf->buf_flags & XPC_BUFFER_F_REMOTE)) {
memcpy(buf->buf_ptr, in, to_write);
*nr_written = to_write;
return KERN_OK;
}
kern_status_t status
= xpc_msg_write(buf->buf_origin, buf->buf_offset, in, to_write);
if (status != KERN_OK) {
return status;
}
/* TODO */
*nr_written = to_write;
return KERN_OK;
}

View File

@@ -0,0 +1,93 @@
#ifndef XPC_BUFFER_H_
#define XPC_BUFFER_H_
#include <stddef.h>
#include <xpc/status.h>
#define XPC_BUFFER_IN(msg, offset, size) \
{ \
.buf_flags = XPC_BUFFER_F_IN | XPC_BUFFER_F_REMOTE, \
.buf_origin = (msg), \
.buf_offset = (offset), \
.buf_len = (size), \
}
#define XPC_BUFFER_OUT(msg, offset, size) \
{ \
.buf_flags = XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE, \
.buf_origin = (msg), \
.buf_offset = (offset), \
.buf_len = (size), \
}
#define XPC_LOCAL_BUFFER_OUT(ptr, size) \
{ \
.buf_flags = XPC_BUFFER_F_OUT, \
.buf_ptr = (ptr), \
.buf_max = (size), \
.buf_len = (size), \
}
struct xpc_msg;
typedef enum xpc_buffer_flags {
/* the buffer can be read from */
XPC_BUFFER_F_IN = 0x01u,
/* the buffer can be written to */
XPC_BUFFER_F_OUT = 0x02u,
/* the buffer is backed by a buffer located in another address space.
* the buffer can only be accessed via xpc_buffer_read and/or
* xpc_buffer_write */
XPC_BUFFER_F_REMOTE = 0x04u,
/* free the buffer backing this buffer when the buffer is discarded.
* this is only used for out-buffers. the buffer must have been
* allocated using xpc_context_alloc, as it will be freed via a call
* to xpc_context_free */
XPC_BUFFER_F_FREE_ON_DISCARD = 0x08u,
} xpc_buffer_flags_t;
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 */
void *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_REMOTE is set.
* used to read/write buffer data from/to the sender's address
* space. */
const struct xpc_msg *buf_origin;
/* valid for both F_IN and F_OUT buffers.
* F_IN: specifies the length of the incoming buffer data.
* F_OUT: specifies how many bytes from buf_ptr to send. */
size_t buf_len;
} xpc_buffer_t;
extern xpc_status_t xpc_buffer_read(
const xpc_buffer_t *s,
void *out,
size_t max,
size_t *nr_read);
extern xpc_status_t xpc_buffer_write(
xpc_buffer_t *s,
const void *in,
size_t len,
size_t *nr_written);
#endif

View File

@@ -0,0 +1,8 @@
#ifndef XPC_CONTEXT_H_
#define XPC_CONTEXT_H_
typedef struct xpc_context {
} xpc_context_t;
#endif

View File

@@ -0,0 +1,13 @@
#ifndef XPC_ENDPOINT_H_
#define XPC_ENDPOINT_H_
#include <mango/types.h>
typedef struct xpc_endpoint {
kern_handle_t e_channel;
tid_t e_task;
koid_t e_port;
msgid_t e_msg;
} xpc_endpoint_t;
#endif

View File

@@ -0,0 +1,54 @@
#ifndef XPC_MSG_H_
#define XPC_MSG_H_
#include <mango/types.h>
#include <stdbool.h>
#include <stdint.h>
#include <xpc/endpoint.h>
#define XPC_MSG_MAGIC 0x5850434D
typedef struct xpc_msg_header {
uint32_t hdr_magic;
uint32_t hdr_interface;
uint16_t hdr_func;
uint16_t hdr_status;
} xpc_msg_header_t;
typedef struct xpc_msg {
xpc_endpoint_t msg_sender;
xpc_msg_header_t msg_header;
size_t msg_handles_count;
kern_msg_handle_t msg_handles[KERN_MSG_MAX_HANDLES];
} xpc_msg_t;
extern void xpc_msg_header_init(
xpc_msg_header_t *msg,
unsigned long interface,
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,
void *p,
size_t count);
extern kern_status_t xpc_msg_write(
const xpc_msg_t *msg,
size_t offset,
const void *p,
size_t count);
extern kern_status_t xpc_msg_reply(
const xpc_msg_t *msg,
kern_iovec_t *iov,
size_t iov_count,
kern_msg_handle_t *handles,
size_t handle_count);
extern kern_status_t xpc_msg_reply_error(
const xpc_msg_t *msg,
unsigned short code);
#endif

View File

@@ -0,0 +1,12 @@
#ifndef XPC_STATUS_H_
#define XPC_STATUS_H_
typedef enum xpc_status {
XPC_SUCCESS = 0,
XPC_ERR_BAD_STATE,
XPC_ERR_INVALID_ARGUMENT,
XPC_ERR_NO_MEMORY,
XPC_ERR_MEMORY_FAULT,
} xpc_status_t;
#endif

View File

@@ -0,0 +1,85 @@
#ifndef XPC_STRING_H_
#define XPC_STRING_H_
#include <stddef.h>
#include <xpc/status.h>
#define XPC_STRING_NPOS ((size_t)-1)
#define XPC_STRING_IN(msg, offset, size) \
{ \
.s_flags = XPC_STRING_F_IN | XPC_STRING_F_REMOTE, \
.s_origin = (msg), \
.s_offset = (offset), \
.s_len = (size), \
}
#define XPC_STRING_OUT(msg, offset, size) \
{ \
.s_flags = XPC_STRING_F_OUT | XPC_STRING_F_REMOTE, \
.s_origin = (msg), \
.s_offset = (offset), \
.s_len = (size), \
}
struct xpc_msg;
typedef enum xpc_string_flags {
/* the string can be read from */
XPC_STRING_F_IN = 0x01u,
/* the string can be written to */
XPC_STRING_F_OUT = 0x02u,
/* the string is backed by a buffer located in another address space.
* the string can only be accessed via xpc_string_read and/or
* xpc_string_write */
XPC_STRING_F_REMOTE = 0x04u,
/* free the buffer backing this string when the string is discarded.
* this is only used for out-strings. the buffer must have been
* allocated using xpc_context_alloc, as it will be freed via a call
* to xpc_context_free */
XPC_STRING_F_FREE_ON_DISCARD = 0x08u,
} xpc_string_flags_t;
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;
};
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;
};
};
/* only valid if F_REMOTE is set.
* used to read/write string data from/to the sender's address space. */
const struct xpc_msg *s_origin;
/* valid for both F_IN and F_OUT strings.
* F_IN: specifies the length of the incoming string data.
* F_OUT: specifies how many characters from s_buf to send. */
size_t s_len;
} xpc_string_t;
extern xpc_status_t xpc_string_read(
const xpc_string_t *s,
char *out,
size_t max,
size_t *nr_read);
extern xpc_status_t xpc_string_write(
xpc_string_t *s,
const char *in,
size_t len,
size_t *nr_written);
#endif

151
lib/libxpc/msg.c Normal file
View File

@@ -0,0 +1,151 @@
#include <mango/msg.h>
#include <mango/object.h>
#include <mango/signal.h>
#include <string.h>
#include <xpc/msg.h>
void xpc_msg_header_init(
xpc_msg_header_t *msg,
unsigned long interface,
unsigned short func)
{
memset(msg, 0x0, sizeof *msg);
msg->hdr_magic = XPC_MSG_MAGIC;
msg->hdr_interface = interface;
msg->hdr_func = func;
msg->hdr_status = 0;
}
bool xpc_msg_header_validate(const xpc_msg_header_t *msg)
{
return msg->hdr_magic == XPC_MSG_MAGIC;
}
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,
.msg_data_count = 1,
.msg_handles = out->msg_handles,
.msg_handles_count = KERN_MSG_MAX_HANDLES,
};
status = msg_recv(channel, &msg);
if (status != KERN_OK) {
return status;
}
if (!xpc_msg_header_validate(&out->msg_header)) {
return KERN_INVALID_ARGUMENT;
}
out->msg_sender.e_channel = channel;
out->msg_sender.e_task = msg.msg_sender;
out->msg_sender.e_port = msg.msg_endpoint;
out->msg_sender.e_msg = msg.msg_id;
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,
void *p,
size_t count)
{
kern_iovec_t iov = IOVEC(p, count);
size_t r = 0;
return msg_read(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
offset,
&iov,
1,
&r);
}
kern_status_t xpc_msg_write(
const xpc_msg_t *msg,
size_t offset,
const void *p,
size_t count)
{
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);
}
kern_status_t xpc_msg_reply(
const xpc_msg_t *msg,
kern_iovec_t *iov,
size_t iov_count,
kern_msg_handle_t *handles,
size_t handle_count)
{
kern_msg_t reply = MSG(iov, iov_count, handles, handle_count);
return msg_reply(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
&reply);
}
kern_status_t xpc_msg_reply_error(const xpc_msg_t *msg, unsigned short code)
{
xpc_msg_header_t reply_data = {
.hdr_magic = XPC_MSG_MAGIC,
.hdr_interface = msg->msg_header.hdr_interface,
.hdr_func = msg->msg_header.hdr_func,
.hdr_status = code,
};
kern_iovec_t iov = IOVEC(&reply_data, sizeof reply_data);
kern_msg_t reply = MSG(&iov, 1, NULL, 0);
return msg_reply(
msg->msg_sender.e_channel,
msg->msg_sender.e_msg,
&reply);
}

60
lib/libxpc/string.c Normal file
View File

@@ -0,0 +1,60 @@
#include <mango/status.h>
#include <xpc/msg.h>
#include <xpc/string.h>
xpc_status_t xpc_string_read(
const xpc_string_t *s,
char *out,
size_t max,
size_t *nr_read)
{
if ((s->s_flags & (XPC_STRING_F_IN | XPC_STRING_F_REMOTE))
!= (XPC_STRING_F_IN | XPC_STRING_F_REMOTE)) {
return KERN_BAD_STATE;
}
size_t to_read = max - 1;
if (to_read > s->s_len) {
to_read = s->s_len;
}
kern_status_t status
= xpc_msg_read(s->s_origin, s->s_offset, out, to_read);
if (status != KERN_OK) {
return status;
}
out[to_read] = '\0';
/* TODO */
*nr_read = to_read;
return KERN_OK;
}
xpc_status_t xpc_string_write(
xpc_string_t *s,
const char *in,
size_t len,
size_t *nr_written)
{
if ((s->s_flags & (XPC_STRING_F_OUT | XPC_STRING_F_REMOTE))
!= (XPC_STRING_F_IN | XPC_STRING_F_REMOTE)) {
return KERN_BAD_STATE;
}
size_t to_write = len;
if (to_write > s->s_max - 1) {
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;
}

View File

@@ -6,7 +6,7 @@ set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C)
add_executable(bootstrap ${c_sources} ${arch_sources}) add_executable(bootstrap ${c_sources} ${arch_sources})
target_link_libraries(bootstrap target_link_libraries(bootstrap
libmango libc-core libc-malloc libfs-static liblaunch libmango libc-core libc-malloc libfs-static liblaunch libxpc-static
interface::fs) interface::fs)
target_compile_options(bootstrap PRIVATE target_compile_options(bootstrap PRIVATE

View File

@@ -53,7 +53,8 @@ static enum launch_status resolve_dependency(
} }
static kern_status_t open( static kern_status_t open(
const struct msg_endpoint *sender, xpc_context_t *ctx,
const xpc_endpoint_t *sender,
const char *path, const char *path,
int flags, int flags,
int *out_err, int *out_err,
@@ -178,51 +179,50 @@ int main(
.fs_arg = &heap, .fs_arg = &heap,
}; };
struct fs_context *fs = fs_context_create(&fs_allocator, NULL); struct fs_context *fs = fs_context_create(&fs_allocator);
if (!fs) { if (!fs) {
kern_logf("cannot initialise fs"); kern_logf("cannot initialise fs");
return -1; 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);
return -1;
}
while (1) { while (1) {
struct msg_endpoint sender; fs_context_handle_request(fs);
struct msg_header hdr; #if 0
kern_msg_handle_t handles[KERN_MSG_MAX_HANDLES] = {0}; xpc_msg_t msg;
kern_status_t status = msg_recv_generic( kern_status_t status = xpc_msg_recv(channel, &msg);
channel,
&sender,
&hdr,
handles,
KERN_MSG_MAX_HANDLES);
if (status != KERN_OK) { if (status != KERN_OK) {
kern_logf("message recv error %d", status); kern_logf("message recv error %d", status);
msg_reply_generic(
channel,
&sender,
&hdr,
KERN_UNSUPPORTED);
continue; continue;
} }
switch (hdr.hdr_protocol) { switch (msg.msg_header.hdr_interface) {
case PROTOCOL_FS: case INTERFACE_FS:
status = fs_context_dispatch_msg( status = fs_context_dispatch_msg(fs, &msg);
fs,
channel,
&sender,
&hdr);
break; break;
default: default:
kern_logf( kern_logf(
"unknown message protocol %u", "unknown message protocol %u",
hdr.hdr_protocol); msg.msg_header.hdr_interface);
msg_reply_generic( xpc_msg_reply_error(&msg, KERN_UNSUPPORTED);
channel,
&sender,
&hdr,
KERN_UNSUPPORTED);
break; break;
} }
if (status != KERN_OK) {
kern_logf("message reply error %d", status);
continue;
}
#endif
} }
return 0; return 0;

138
sys/bootstrap/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/bootstrap/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

@@ -1,8 +1,30 @@
#include "tar.h" #include "tar.h"
#include "queue.h"
#include <fs/dentry.h>
#include <fs/file.h>
#include <fs/inode.h>
#include <fs/superblock.h>
#include <mango/handle.h> #include <mango/handle.h>
#include <mango/log.h>
#include <mango/vm.h> #include <mango/vm.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <xpc/buffer.h>
struct tar_superblock {
struct fs_superblock sb_base;
struct tar_bin_header *sb_data;
};
struct tar_entry {
struct fs_dentry e_dentry;
struct fs_inode e_inode;
void *e_data;
struct queue_entry e_entry;
struct queue e_children;
};
size_t getsize(const char *in) size_t getsize(const char *in)
{ {
@@ -52,8 +74,10 @@ int tar_open(struct tar *tar, const char *path, struct tar_file *out)
} }
s += header.size; s += header.size;
s += ((sizeof *bin_header) if ((uintptr_t)s % (sizeof *bin_header)) {
- ((uintptr_t)s % (sizeof *bin_header))); s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header)));
}
bin_header = (struct tar_bin_header *)s; bin_header = (struct tar_bin_header *)s;
} }
@@ -94,3 +118,302 @@ int tar_header_decode(const struct tar_bin_header *in, struct tar_header *out)
out->size = getsize(in->size); out->size = getsize(in->size);
return 0; return 0;
} }
static struct tar_entry *entry_from_dentry(struct fs_dentry *dent)
{
return QUEUE_CONTAINER(struct tar_entry, e_dentry, dent);
}
static struct tar_entry *entry_from_inode(struct fs_inode *inode)
{
return QUEUE_CONTAINER(struct tar_entry, e_inode, inode);
}
static struct tar_entry *entry_get_child(
struct tar_entry *entry,
const char *name)
{
struct queue_entry *cur = queue_first(&entry->e_children);
while (cur) {
struct tar_entry *child
= QUEUE_CONTAINER(struct tar_entry, e_entry, cur);
if (!strcmp(child->e_dentry.d_name, name)) {
return child;
}
cur = queue_next(cur);
}
return NULL;
}
static const struct fs_dentry_ops dentry_ops = {};
static enum fs_status dir_lookup(
struct fs_inode *inode,
const char *name,
struct fs_dentry **out)
{
struct tar_entry *entry = entry_from_inode(inode);
struct tar_entry *child = entry_get_child(entry, name);
if (!child) {
return FS_ERR_NO_ENTRY;
}
*out = &child->e_dentry;
return FS_SUCCESS;
}
static enum fs_status file_read(
struct fs_file *f,
xpc_buffer_t *buf,
size_t count,
off_t *seek)
{
off_t offset = *seek;
struct tar_entry *entry = entry_from_inode(fs_file_get_inode(f));
if (!entry) {
return FS_ERR_BAD_STATE;
}
if (offset >= entry->e_inode.i_size) {
count = 0;
} else if (offset + count > entry->e_inode.i_size) {
count = entry->e_inode.i_size - offset;
}
if (count == 0) {
return FS_SUCCESS;
}
char *src = (char *)entry->e_data + offset;
size_t w;
xpc_buffer_write(buf, src, count, &w);
offset += count;
*seek = offset;
return FS_SUCCESS;
}
static const struct fs_file_ops file_ops = {
.f_read = file_read,
};
static const struct fs_inode_ops file_inode_ops = {
.i_lookup = NULL,
};
static const struct fs_inode_ops dir_inode_ops = {
.i_lookup = dir_lookup,
};
static struct tar_entry *create_dir_entry(
struct fs_context *ctx,
struct tar_superblock *sb,
const char *name)
{
struct tar_entry *entry = fs_context_alloc(ctx, sizeof *entry);
if (!entry) {
return NULL;
}
memset(entry, 0x0, sizeof *entry);
entry->e_inode.i_sb = &sb->sb_base;
entry->e_inode.i_mode = FS_INODE_DIR;
entry->e_inode.i_ops = &dir_inode_ops;
entry->e_dentry.d_sb = &sb->sb_base;
entry->e_dentry.d_ops = &dentry_ops;
entry->e_dentry.d_inode = &entry->e_inode;
size_t name_len = strlen(name);
entry->e_dentry.d_name = fs_context_alloc(ctx, name_len + 1);
if (!entry->e_dentry.d_name) {
fs_context_free(ctx, entry);
return NULL;
}
memcpy(entry->e_dentry.d_name, name, name_len + 1);
return entry;
}
static struct tar_entry *create_file_entry(
struct fs_context *ctx,
struct tar_superblock *sb,
struct tar_header *header,
void *data,
const char *name)
{
struct tar_entry *entry = fs_context_alloc(ctx, sizeof *entry);
if (!entry) {
return NULL;
}
memset(entry, 0x0, sizeof *entry);
entry->e_inode.i_sb = &sb->sb_base;
entry->e_inode.i_mode = FS_INODE_REG;
entry->e_inode.i_ops = &file_inode_ops;
entry->e_inode.i_fops = &file_ops;
entry->e_inode.i_size = header->size;
entry->e_dentry.d_sb = &sb->sb_base;
entry->e_dentry.d_ops = &dentry_ops;
entry->e_dentry.d_inode = &entry->e_inode;
entry->e_data = data;
size_t name_len = strlen(name);
entry->e_dentry.d_name = fs_context_alloc(ctx, name_len + 1);
if (!entry->e_dentry.d_name) {
fs_context_free(ctx, entry);
return NULL;
}
memcpy(entry->e_dentry.d_name, name, name_len + 1);
return entry;
}
static size_t get_first_path_component(const char *in, char *out, size_t max)
{
size_t i = 0;
while (i < max - 1) {
if (in[i] == '\0' || in[i] == '/') {
break;
}
out[i] = in[i];
i++;
}
out[i] = '\0';
return i;
}
static enum fs_status add_entry_to_tree(
struct fs_context *ctx,
struct tar_superblock *sb,
struct tar_header *entry,
void *data)
{
struct tar_entry *cur = entry_from_dentry(sb->sb_base.s_root);
const char *path = entry->filename;
char tok[256];
while (*path != '\0') {
while (*path == '/') {
path++;
}
size_t tok_len
= get_first_path_component(path, tok, sizeof tok);
if (!tok_len) {
break;
}
struct tar_entry *next = entry_get_child(cur, tok);
bool is_file = *(path + tok_len) == '\0';
if (next) {
goto next;
}
if (is_file) {
next = create_file_entry(ctx, sb, entry, data, tok);
} else {
next = create_dir_entry(ctx, sb, tok);
}
if (!next) {
return FS_ERR_NO_MEMORY;
}
queue_push_back(&cur->e_children, &next->e_entry);
next->e_dentry.d_parent = &cur->e_dentry;
next:
cur = next;
path += tok_len;
}
return FS_SUCCESS;
}
static enum fs_status build_dentry_tree(
struct fs_context *ctx,
struct tar_superblock *sb)
{
struct tar_entry *root = create_dir_entry(ctx, sb, "/");
if (!root) {
return FS_ERR_NO_MEMORY;
}
sb->sb_base.s_root = &root->e_dentry;
struct tar_bin_header *bin_header = sb->sb_data;
struct tar_header header;
enum fs_status status = FS_SUCCESS;
for (size_t i = 0;; i++) {
tar_header_decode(bin_header, &header);
if (bin_header->filename[0] == 0) {
break;
}
char *s = (char *)bin_header;
s += sizeof *bin_header;
bool add = true;
if (!strcmp(header.filename, "././@PaxHeader")) {
add = false;
}
if (add) {
status = add_entry_to_tree(ctx, sb, &header, s);
}
if (status != FS_SUCCESS) {
break;
}
s += header.size;
if ((uintptr_t)s % (sizeof *bin_header)) {
s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header)));
}
bin_header = (struct tar_bin_header *)s;
}
return FS_SUCCESS;
}
enum fs_status tar_mount(
struct fs_context *ctx,
void *arg,
enum fs_mount_flags flags,
struct fs_superblock **out)
{
struct tar_superblock *sb = fs_context_alloc(ctx, sizeof *sb);
if (!sb) {
return FS_ERR_NO_MEMORY;
}
sb->sb_data = arg;
enum fs_status status = build_dentry_tree(ctx, sb);
if (status != FS_SUCCESS) {
fs_context_free(ctx, sb);
return status;
}
*out = (struct fs_superblock *)sb;
return FS_SUCCESS;
}

View File

@@ -1,6 +1,8 @@
#ifndef TAR_H_ #ifndef TAR_H_
#define TAR_H_ #define TAR_H_
#include <fs/context.h>
#include <fs/status.h>
#include <mango/types.h> #include <mango/types.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -42,4 +44,10 @@ extern int tar_header_decode(
const struct tar_bin_header *in, const struct tar_bin_header *in,
struct tar_header *out); struct tar_header *out);
extern enum fs_status tar_mount(
struct fs_context *ctx,
void *arg,
enum fs_mount_flags flags,
struct fs_superblock **out);
#endif #endif

View File

@@ -10,7 +10,7 @@ set_target_properties(ld PROPERTIES
SUFFIX ".so") SUFFIX ".so")
target_link_libraries(ld target_link_libraries(ld
libc-core libc-malloc libmango librosetta libc-core libc-malloc libc-io libmango librosetta libxpc-static
interface::fs) interface::fs)
target_compile_options(ld PRIVATE target_compile_options(ld PRIVATE

View File

@@ -1,6 +1,7 @@
#define MSG_IMPLEMENTATION #define MSG_IMPLEMENTATION
#define MSG_NO_MALLOC #define MSG_NO_MALLOC
#include <errno.h>
#include <heap/heap.h> #include <heap/heap.h>
#include <mango/log.h> #include <mango/log.h>
#include <mango/msg.h> #include <mango/msg.h>
@@ -12,10 +13,14 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mman.h>
#include <sys/remote.h>
#include <unistd.h> #include <unistd.h>
int main(const struct rosetta_bootstrap *bs) int main(const struct rosetta_bootstrap *bs)
{ {
kern_logf("ld");
kern_handle_t task, address_space; kern_handle_t task, address_space;
task_self(&task); task_self(&task);
task_get_address_space(task, &address_space); task_get_address_space(task, &address_space);
@@ -24,32 +29,64 @@ int main(const struct rosetta_bootstrap *bs)
kern_logf("argv[%zu]: %s", i, bs->bs_argv[i]); kern_logf("argv[%zu]: %s", i, bs->bs_argv[i]);
} }
kern_handle_t port; sys_remote_set(SYS_REMOTE_NSD, 0, 0);
kern_status_t status = port_create(&port);
if (status != KERN_OK) {
kern_logf("port creation failed %d", status);
return -1;
}
port_connect(port, 0, 0);
const char *path = "/usr/lib/libc.so"; const char *path = "/usr/lib/libc.so";
int flags = 4; int flags = 4;
int err = 0;
kern_logf("sending msg: open(%s, %d)", path, flags); kern_logf("sending msg: open(%s, %d)", path, flags);
status = fs_open(port, path, flags, &err); int fd = open(path, flags);
if (status != KERN_OK) { if (fd < 0) {
kern_logf("open call failed (status %d)", status);
} else {
kern_logf( kern_logf(
"open(%s, %d) = %s (%s)", "open(%s, %d) = %s (%s)",
path, path,
flags, flags,
strerror_code(err), strerror_code(fd),
strerror(err)); strerror(fd));
return -1;
} }
kern_logf(
"open(%s, %d) = %s (%s)",
path,
flags,
strerror_code(SUCCESS),
strerror(SUCCESS));
unsigned char buf[32] = {0};
int nr = read(fd, buf, sizeof buf);
if (nr < 0) {
kern_logf("read call failed (%s)", strerror(nr));
return -1;
}
kern_logf("data: %x %c %c %c", buf[0], buf[1], buf[2], buf[3]);
void *p
= mmap(NULL,
0x1000,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE,
-1,
0);
if (p != MAP_FAILED) {
memset(p, 0x0, 0x1000);
kern_logf("mmap'd buffer at %p", p);
} else {
kern_logf("mmap buffer failed");
}
void *lib
= mmap(NULL, 0x1000, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
if (lib != MAP_FAILED) {
kern_logf("mmap'd %s at %p", path, lib);
unsigned char *tmp = lib;
kern_logf("data: %x %c %c %c", tmp[0], tmp[1], tmp[2], tmp[3]);
} else {
kern_logf("mmap lib failed");
}
kern_logf("ld finished");
return 0; return 0;
} }

View File

@@ -14,4 +14,4 @@ add_subdirectory(
../kernel/tools ../kernel/tools
${CMAKE_CURRENT_BINARY_DIR}/kernel-tools) ${CMAKE_CURRENT_BINARY_DIR}/kernel-tools)
add_subdirectory(ifc) add_subdirectory(xpcg)

View File

@@ -1,7 +0,0 @@
file(GLOB sources
*.c *.h
backend/c-mpc/*.c backend/c-mpc/*.h)
add_executable(ifc ${sources})
target_link_libraries(ifc Bluelib::Core Bluelib::Ds Bluelib::Cmd Bluelib::Io)

View File

@@ -0,0 +1,7 @@
file(GLOB sources
*.c *.h
backend/c-mpc/*.c backend/c-mpc/*.h)
add_executable(xpcg ${sources})
target_link_libraries(xpcg Bluelib::Core Bluelib::Ds Bluelib::Cmd Bluelib::Io)

View File

@@ -1,5 +1,5 @@
#ifndef IFC_BACKEND_H_ #ifndef XPCG_BACKEND_H_
#define IFC_BACKEND_H_ #define XPCG_BACKEND_H_
struct interface_definition; struct interface_definition;

View File

@@ -43,6 +43,14 @@ const struct type *ctx_get_type(struct ctx *ctx, const char *name)
return ctx_get_builtin_type(ctx, TYPE_HANDLE); return ctx_get_builtin_type(ctx, TYPE_HANDLE);
} }
if (!strcmp(name, "size")) {
return ctx_get_builtin_type(ctx, TYPE_SIZE);
}
if (!strcmp(name, "buffer")) {
return ctx_get_builtin_type(ctx, TYPE_BUFFER);
}
return NULL; return NULL;
} }

View File

@@ -1,5 +1,5 @@
#ifndef IFC_CTX_H_ #ifndef XPCG_CTX_H_
#define IFC_CTX_H_ #define XPCG_CTX_H_
#include "type.h" #include "type.h"

View File

@@ -1,5 +1,5 @@
#ifndef IFC_FILE_SPAN_H_ #ifndef XPCG_FILE_SPAN_H_
#define IFC_FILE_SPAN_H_ #define XPCG_FILE_SPAN_H_
struct file_cell { struct file_cell {
unsigned int c_row, c_col; unsigned int c_row, c_col;

View File

@@ -6,7 +6,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct interface_definition *interface_definition_create(const char *name) struct interface_definition *interface_definition_create(
const char *name,
long long id)
{ {
struct interface_definition *out = malloc(sizeof *out); struct interface_definition *out = malloc(sizeof *out);
if (!out) { if (!out) {
@@ -16,6 +18,7 @@ struct interface_definition *interface_definition_create(const char *name)
memset(out, 0x0, sizeof *out); memset(out, 0x0, sizeof *out);
out->if_name = b_strdup(name); out->if_name = b_strdup(name);
out->if_id = id;
return out; return out;
} }

View File

@@ -1,5 +1,5 @@
#ifndef IFC_INTERFACE_H_ #ifndef XPCG_INTERFACE_H_
#define IFC_INTERFACE_H_ #define XPCG_INTERFACE_H_
#include <blue/core/queue.h> #include <blue/core/queue.h>
@@ -7,11 +7,13 @@ struct msg_definition;
struct interface_definition { struct interface_definition {
char *if_name; char *if_name;
long long if_id;
b_queue if_msg; b_queue if_msg;
}; };
extern struct interface_definition *interface_definition_create( extern struct interface_definition *interface_definition_create(
const char *name); const char *name,
long long id);
extern void interface_definition_destroy(struct interface_definition *iface); extern void interface_definition_destroy(struct interface_definition *iface);
extern bool interface_definition_has_msg( extern bool interface_definition_has_msg(

View File

@@ -29,18 +29,21 @@
static struct lex_token_def symbols[] = { static struct lex_token_def symbols[] = {
LEX_TOKEN_DEF(SYM_COMMA, ","), LEX_TOKEN_DEF(SYM_COMMA, ","),
LEX_TOKEN_DEF(SYM_HYPHEN, "-"), LEX_TOKEN_DEF(SYM_HYPHEN, "-"),
LEX_TOKEN_DEF(SYM_LEFT_BRACKET, "["),
LEX_TOKEN_DEF(SYM_RIGHT_BRACKET, "]"),
LEX_TOKEN_DEF(SYM_LEFT_BRACE, "{"), LEX_TOKEN_DEF(SYM_LEFT_BRACE, "{"),
LEX_TOKEN_DEF(SYM_RIGHT_BRACE, "}"), LEX_TOKEN_DEF(SYM_RIGHT_BRACE, "}"),
LEX_TOKEN_DEF(SYM_LEFT_PAREN, "("), LEX_TOKEN_DEF(SYM_LEFT_PAREN, "("),
LEX_TOKEN_DEF(SYM_RIGHT_PAREN, ")"), LEX_TOKEN_DEF(SYM_RIGHT_PAREN, ")"),
LEX_TOKEN_DEF(SYM_SEMICOLON, ";"), LEX_TOKEN_DEF(SYM_SEMICOLON, ";"),
LEX_TOKEN_DEF(SYM_COLON, ":"),
LEX_TOKEN_DEF(SYM_HYPHEN_RIGHT_ANGLE, "->"), LEX_TOKEN_DEF(SYM_HYPHEN_RIGHT_ANGLE, "->"),
}; };
static const size_t nr_symbols = sizeof symbols / sizeof symbols[0]; static const size_t nr_symbols = sizeof symbols / sizeof symbols[0];
static struct lex_token_def keywords[] = { static struct lex_token_def keywords[] = {
LEX_TOKEN_DEF(KW_INTERFACE, "interface"), LEX_TOKEN_DEF(KW_INTERFACE, "interface"),
LEX_TOKEN_DEF(KW_MSG, "msg"), LEX_TOKEN_DEF(KW_FUNC, "func"),
}; };
static const size_t nr_keywords = sizeof keywords / sizeof keywords[0]; static const size_t nr_keywords = sizeof keywords / sizeof keywords[0];

View File

@@ -1,5 +1,5 @@
#ifndef IFC_LEX_H_ #ifndef XPCG_LEX_H_
#define IFC_LEX_H_ #define XPCG_LEX_H_
#include "status.h" #include "status.h"
#include "token.h" #include "token.h"

View File

@@ -64,7 +64,10 @@ static void print_interface(struct interface_definition *iface)
} }
} }
static int ifc(const b_command *self, const b_arglist *opt, const b_array *args) static int xpcg(
const b_command *self,
const b_arglist *opt,
const b_array *args)
{ {
const char *path = NULL; const char *path = NULL;
b_arglist_get_string(opt, B_COMMAND_INVALID_ID, ARG_SRCPATH, 0, &path); b_arglist_get_string(opt, B_COMMAND_INVALID_ID, ARG_SRCPATH, 0, &path);
@@ -132,10 +135,10 @@ static int ifc(const b_command *self, const b_arglist *opt, const b_array *args)
B_COMMAND(CMD_ID, B_COMMAND_INVALID_ID) B_COMMAND(CMD_ID, B_COMMAND_INVALID_ID)
{ {
B_COMMAND_NAME("ifc"); B_COMMAND_NAME("xpcg");
B_COMMAND_DESC("interface definition compiler."); B_COMMAND_DESC("xpc interface generator.");
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
B_COMMAND_FUNCTION(ifc); B_COMMAND_FUNCTION(xpcg);
B_COMMAND_HELP_OPTION(); B_COMMAND_HELP_OPTION();
B_COMMAND_ARG(ARG_SRCPATH) B_COMMAND_ARG(ARG_SRCPATH)

View File

@@ -4,7 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct msg_definition *msg_definition_create(const char *name) struct msg_definition *msg_definition_create(const char *name, long long id)
{ {
struct msg_definition *out = malloc(sizeof *out); struct msg_definition *out = malloc(sizeof *out);
if (!out) { if (!out) {
@@ -14,6 +14,7 @@ struct msg_definition *msg_definition_create(const char *name)
memset(out, 0x0, sizeof *out); memset(out, 0x0, sizeof *out);
out->msg_name = b_strdup(name); out->msg_name = b_strdup(name);
out->msg_id = id;
return out; return out;
} }

View File

@@ -1,5 +1,5 @@
#ifndef IFC_MSG_H_ #ifndef XPCG_MSG_H_
#define IFC_MSG_H_ #define XPCG_MSG_H_
#include <blue/core/queue.h> #include <blue/core/queue.h>
@@ -13,13 +13,16 @@ struct msg_parameter {
struct msg_definition { struct msg_definition {
char *msg_name; char *msg_name;
long long msg_id;
b_queue_entry msg_entry; b_queue_entry msg_entry;
b_queue msg_params; b_queue msg_params;
b_queue msg_results; b_queue msg_results;
}; };
extern struct msg_definition *msg_definition_create(const char *name); extern struct msg_definition *msg_definition_create(
const char *name,
long long id);
extern void msg_definition_destroy(struct msg_definition *msg); extern void msg_definition_destroy(struct msg_definition *msg);
extern bool msg_definition_has_param( extern bool msg_definition_has_param(

View File

@@ -48,26 +48,55 @@ static bool parse_word(struct lex *lex, char **out)
return true; return true;
} }
static bool parse_int(struct lex *lex, long long *out)
{
struct token *tok = lex_peek(lex);
if (!tok || tok->tok_type != TOK_INT) {
return false;
}
*out = tok->tok_int;
lex_advance(lex);
return true;
}
struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex) struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
{ {
struct msg_definition *msg = NULL; struct msg_definition *msg = NULL;
if (!parse_keyword(lex, KW_MSG)) { if (!parse_keyword(lex, KW_FUNC)) {
report_error("expected `msg` keyword\n"); report_error("expected `func` keyword\n");
goto fail; goto fail;
} }
char *msg_name = NULL; char *msg_name = NULL;
if (!parse_word(lex, &msg_name)) { if (!parse_word(lex, &msg_name)) {
report_error("expected message identifier\n"); report_error("expected function identifier\n");
goto fail; goto fail;
} }
msg = msg_definition_create(msg_name); long long msg_id = 0;
if (!parse_symbol(lex, SYM_LEFT_BRACKET)) {
report_error("expected `[` after function identifier\n");
goto fail;
}
if (!parse_int(lex, &msg_id)) {
report_error("expected function id number after `[`\n");
goto fail;
}
if (!parse_symbol(lex, SYM_RIGHT_BRACKET)) {
report_error("expected `]` after function id number\n");
goto fail;
}
msg = msg_definition_create(msg_name, msg_id);
free(msg_name); free(msg_name);
if (!parse_symbol(lex, SYM_LEFT_PAREN)) { if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
report_error("expected `(` after message identifier\n"); report_error(
"expected `(` after function id number specifier\n");
goto fail; goto fail;
} }
@@ -79,14 +108,31 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
} }
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) { if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
report_error("expected `,` after message parameter\n"); report_error(
"expected `,` after function "
"parameter\n");
ok = false;
break;
}
char *param_name;
if (!parse_word(lex, &param_name)) {
report_error("expected function parameter name\n");
ok = false;
break;
}
if (!parse_symbol(lex, SYM_COLON)) {
report_error(
"expected `:` after function parameter "
"name\n");
ok = false; ok = false;
break; break;
} }
char *type_name; char *type_name;
if (!parse_word(lex, &type_name)) { if (!parse_word(lex, &type_name)) {
report_error("expected message parameter type\n"); report_error("expected function parameter type\n");
ok = false; ok = false;
break; break;
} }
@@ -94,7 +140,7 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
const struct type *type = ctx_get_type(ctx, type_name); const struct type *type = ctx_get_type(ctx, type_name);
if (!type) { if (!type) {
report_error( report_error(
"message parameter has unknown type " "function parameter has unknown type "
"'%s'\n", "'%s'\n",
type_name); type_name);
free(type_name); free(type_name);
@@ -104,19 +150,13 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
free(type_name); free(type_name);
char *param_name;
if (!parse_word(lex, &param_name)) {
report_error("expected message parameter name\n");
ok = false;
break;
}
bool duplicate = msg_definition_has_param(msg, param_name) bool duplicate = msg_definition_has_param(msg, param_name)
|| msg_definition_has_result(msg, param_name); || msg_definition_has_result(msg, param_name);
if (duplicate) { if (duplicate) {
free(param_name); free(param_name);
report_error( report_error(
"message has multiple parameters/results with " "function has multiple "
"parameters/results with "
"name '%s'\n", "name '%s'\n",
param_name); param_name);
ok = false; ok = false;
@@ -133,12 +173,14 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
} }
if (!parse_symbol(lex, SYM_HYPHEN_RIGHT_ANGLE)) { if (!parse_symbol(lex, SYM_HYPHEN_RIGHT_ANGLE)) {
report_error("expected `->` after message parameter list\n"); report_error(
"expected `->` after function parameter "
"list\n");
goto fail; goto fail;
} }
if (!parse_symbol(lex, SYM_LEFT_PAREN)) { if (!parse_symbol(lex, SYM_LEFT_PAREN)) {
report_error("expected `(` for message results list\n"); report_error("expected `(` for function results list\n");
goto fail; goto fail;
} }
@@ -150,14 +192,30 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
if (i > 0 && !parse_symbol(lex, SYM_COMMA)) { if (i > 0 && !parse_symbol(lex, SYM_COMMA)) {
report_error( report_error(
"expected `,` or `)` after message result\n"); "expected `,` or `)` after function "
"result\n");
ok = false;
break;
}
char *result_name;
if (!parse_word(lex, &result_name)) {
report_error("expected function parameter name\n");
ok = false;
break;
}
if (!parse_symbol(lex, SYM_COLON)) {
report_error(
"expected `:` after function result "
"name\n");
ok = false; ok = false;
break; break;
} }
char *type_name; char *type_name;
if (!parse_word(lex, &type_name)) { if (!parse_word(lex, &type_name)) {
report_error("expected message result type\n"); report_error("expected function result type\n");
ok = false; ok = false;
break; break;
} }
@@ -165,7 +223,7 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
const struct type *type = ctx_get_type(ctx, type_name); const struct type *type = ctx_get_type(ctx, type_name);
if (!type) { if (!type) {
report_error( report_error(
"message result has unknown type " "function result has unknown type "
"'%s'\n", "'%s'\n",
type_name); type_name);
free(type_name); free(type_name);
@@ -174,18 +232,12 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
} }
free(type_name); free(type_name);
char *result_name;
if (!parse_word(lex, &result_name)) {
report_error("expected message parameter name\n");
ok = false;
break;
}
bool duplicate = msg_definition_has_param(msg, result_name) bool duplicate = msg_definition_has_param(msg, result_name)
|| msg_definition_has_result(msg, result_name); || msg_definition_has_result(msg, result_name);
if (duplicate) { if (duplicate) {
report_error( report_error(
"message has multiple parameters/results with " "function has multiple "
"parameters/results with "
"name '%s'\n", "name '%s'\n",
result_name); result_name);
free(result_name); free(result_name);
@@ -199,7 +251,7 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
} }
if (!parse_symbol(lex, SYM_SEMICOLON)) { if (!parse_symbol(lex, SYM_SEMICOLON)) {
report_error("expected `;` after message definition\n"); report_error("expected `;` after function definition\n");
goto fail; goto fail;
} }
@@ -226,29 +278,35 @@ struct interface_definition *parse_interface_definition(
char *if_name = NULL; char *if_name = NULL;
if (!parse_word(lex, &if_name)) { if (!parse_word(lex, &if_name)) {
report_error("expected interface identifier"); report_error("expected interface name");
goto fail; goto fail;
} }
iface = interface_definition_create(if_name); long long if_id = 0;
if (!parse_int(lex, &if_id)) {
report_error("expected interface id number");
goto fail;
}
if (!parse_symbol(lex, SYM_SEMICOLON)) {
report_error("expected `;` after interface definition");
goto fail;
}
iface = interface_definition_create(if_name, if_id);
free(if_name); free(if_name);
if (!iface) { if (!iface) {
goto fail; goto fail;
} }
if (!parse_symbol(lex, SYM_LEFT_BRACE)) {
report_error("expected `{` after interface identifier");
goto fail;
}
bool ok = true; bool ok = true;
while (ok) { while (ok) {
if (parse_symbol(lex, SYM_RIGHT_BRACE)) { if (!lex_peek(lex) && lex_get_status(lex) == ERR_EOF) {
break; break;
} }
if (peek_keyword(lex, KW_MSG)) { if (peek_keyword(lex, KW_FUNC)) {
struct msg_definition *msg struct msg_definition *msg
= parse_msg_definition(ctx, lex); = parse_msg_definition(ctx, lex);
if (!msg) { if (!msg) {
@@ -268,7 +326,7 @@ struct interface_definition *parse_interface_definition(
continue; continue;
} }
report_error("expected `}` or message definition\n"); report_error("expected eof or function definition\n");
ok = false; ok = false;
break; break;
} }

View File

@@ -1,5 +1,5 @@
#ifndef IFC_PARSE_H_ #ifndef XPCG_PARSE_H_
#define IFC_PARSE_H_ #define XPCG_PARSE_H_
struct ctx; struct ctx;
struct lex; struct lex;

View File

@@ -1,5 +1,5 @@
#ifndef IFC_STATUS_H_ #ifndef XPCG_STATUS_H_
#define IFC_STATUS_H_ #define XPCG_STATUS_H_
enum status { enum status {
SUCCESS = 0, SUCCESS = 0,

View File

@@ -40,6 +40,7 @@ const char *token_symbol_to_string(enum token_symbol sym)
ENUM_STR(SYM_NONE); ENUM_STR(SYM_NONE);
ENUM_STR(SYM_COMMA); ENUM_STR(SYM_COMMA);
ENUM_STR(SYM_SEMICOLON); ENUM_STR(SYM_SEMICOLON);
ENUM_STR(SYM_COLON);
ENUM_STR(SYM_HYPHEN); ENUM_STR(SYM_HYPHEN);
ENUM_STR(SYM_LEFT_BRACE); ENUM_STR(SYM_LEFT_BRACE);
ENUM_STR(SYM_RIGHT_BRACE); ENUM_STR(SYM_RIGHT_BRACE);
@@ -56,7 +57,7 @@ const char *token_keyword_to_string(enum token_keyword kw)
switch (kw) { switch (kw) {
ENUM_STR(KW_NONE); ENUM_STR(KW_NONE);
ENUM_STR(KW_INTERFACE); ENUM_STR(KW_INTERFACE);
ENUM_STR(KW_MSG); ENUM_STR(KW_FUNC);
default: default:
return ""; return "";
} }

View File

@@ -1,5 +1,5 @@
#ifndef IFC_TOKEN_H_ #ifndef XPCG_TOKEN_H_
#define IFC_TOKEN_H_ #define XPCG_TOKEN_H_
#include "file-span.h" #include "file-span.h"
@@ -34,6 +34,9 @@ enum token_symbol {
SYM_COMMA = __TOK_UBOUND, SYM_COMMA = __TOK_UBOUND,
SYM_HYPHEN, SYM_HYPHEN,
SYM_SEMICOLON, SYM_SEMICOLON,
SYM_COLON,
SYM_LEFT_BRACKET,
SYM_RIGHT_BRACKET,
SYM_LEFT_BRACE, SYM_LEFT_BRACE,
SYM_RIGHT_BRACE, SYM_RIGHT_BRACE,
SYM_LEFT_PAREN, SYM_LEFT_PAREN,
@@ -45,7 +48,7 @@ enum token_symbol {
enum token_keyword { enum token_keyword {
KW_NONE = 0, KW_NONE = 0,
KW_INTERFACE = __SYM_UBOUND, KW_INTERFACE = __SYM_UBOUND,
KW_MSG, KW_FUNC,
}; };
struct token { struct token {

View File

@@ -11,6 +11,12 @@ void type_print(const struct type *ty)
case TYPE_STRING: case TYPE_STRING:
printf("string"); printf("string");
break; break;
case TYPE_SIZE:
printf("size");
break;
case TYPE_BUFFER:
printf("buffer");
break;
case TYPE_HANDLE: case TYPE_HANDLE:
printf("handle"); printf("handle");
break; break;

View File

@@ -1,10 +1,12 @@
#ifndef IFC_TYPE_H_ #ifndef XPCG_TYPE_H_
#define IFC_TYPE_H_ #define XPCG_TYPE_H_
enum type_id { enum type_id {
TYPE_NONE, TYPE_NONE,
TYPE_INT, TYPE_INT,
TYPE_SIZE,
TYPE_STRING, TYPE_STRING,
TYPE_BUFFER,
TYPE_HANDLE, TYPE_HANDLE,
TYPE_OTHER, TYPE_OTHER,
}; };