Compare commits

..

18 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
38 changed files with 1041 additions and 75 deletions

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,4 +6,4 @@ func close[1]() -> (err: int);
func read[2](count: size) -> (err: int, nr_read: size, data: buffer);
func write[3](data: buffer) -> (err: int, nr_written: size);
func map[4](prot: int, flags: int) -> (vmo: handle);
func map[4](prot: int, flags: int) -> (err: int, vmo: handle);

2
kernel

Submodule kernel updated: de520cdd2d...0af35c70ef

View File

@@ -9,8 +9,10 @@
#define PROT_READ 0x02u
#define PROT_WRITE 0x04u
#define MAP_FAILED ((void *)-1)
#define MAP_SHARED 0x01u
#define MAP_SHARED_VALIDATE 0x03u
#define MAP_SHARED_VALIDATE 0x02u
#define MAP_PRIVATE 0x04u
#define MAP_32BIT 0x08u
#define MAP_ANON MAP_ANONYMOUS

View File

@@ -1,6 +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)
{
return NULL;
int tmp = 0;
if (flags & MAP_SHARED) {
tmp++;
}
if (flags & MAP_SHARED_VALIDATE) {
tmp++;
}
if (flags & MAP_PRIVATE) {
tmp++;
}
if (tmp != 1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
if ((flags & MAP_ANONYMOUS) && fd != -1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
if (!(flags & MAP_ANONYMOUS) && fd == -1) {
__set_errno(EINVAL);
return MAP_FAILED;
}
kern_status_t status = KERN_OK;
kern_handle_t self = KERN_HANDLE_INVALID,
address_space = KERN_HANDLE_INVALID;
status = task_self(&self);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
status = task_get_address_space(self, &address_space);
kern_handle_close(self);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
kern_handle_t vmo = KERN_HANDLE_INVALID;
int err = get_vmo(fd, prot, flags, length, &vmo);
if (err != SUCCESS) {
kern_handle_close(address_space);
__set_errno(err);
return MAP_FAILED;
}
virt_addr_t map_address = 0;
vm_prot_t vm_prot = vm_prot_from_mmap_prot(prot);
if (addr && (flags & MAP_FIXED)) {
status = address_space_map(
address_space,
(virt_addr_t)addr,
vmo,
offset,
length,
vm_prot,
&map_address);
} else {
status = address_space_map(
address_space,
MAP_ADDRESS_ANY,
vmo,
offset,
length,
vm_prot,
&map_address);
}
kern_handle_close(vmo);
kern_handle_close(address_space);
if (status != KERN_OK) {
__set_errno(__errno_from_kern_status(status));
return MAP_FAILED;
}
return (void *)map_address;
}

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
#include "btree.h"
#include "file.h"
#include "interface.h"
#include "mapping.h"
#include <fs/allocator.h>
#include <fs/context.h>
@@ -8,9 +9,16 @@
#include <fs/inode.h>
#include <fs/status.h>
#include <fs/superblock.h>
#include <mango/handle.h>
#include <mango/log.h>
#include <mango/object.h>
#include <mango/signal.h>
#include <mango/task.h>
#include <mango/vm.h>
#include <stdio.h>
#define TEMP_OBJECT_SIZE 0x10000
BTREE_DEFINE_SIMPLE_GET(struct fs_file, unsigned long, f_node, f_id, get_file);
BTREE_DEFINE_SIMPLE_INSERT(struct fs_file, f_node, f_id, put_file);
@@ -18,12 +26,21 @@ struct fs_context {
struct fs_superblock *ctx_sb;
struct fs_allocator *ctx_alloc;
struct btree ctx_filelist;
kern_handle_t ctx_vm_controller;
kern_handle_t ctx_channel;
kern_handle_t ctx_temp_object;
void *ctx_temp_object_buf;
struct fs_vtable ctx_vtable;
};
struct fs_context *fs_context_create(struct fs_allocator *alloc)
{
kern_handle_t self, address_space;
task_self(&self);
task_get_address_space(self, &address_space);
kern_handle_close(self);
struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx);
if (!ctx) {
return NULL;
@@ -31,10 +48,48 @@ struct fs_context *fs_context_create(struct fs_allocator *alloc)
memset(ctx, 0x0, sizeof *ctx);
kern_status_t status = vm_controller_create(&ctx->ctx_vm_controller);
if (status != KERN_OK) {
fs_free(alloc, ctx);
return NULL;
}
status = vm_object_create(
NULL,
0,
TEMP_OBJECT_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&ctx->ctx_temp_object);
if (status != KERN_OK) {
kern_handle_close(ctx->ctx_vm_controller);
fs_free(alloc, ctx);
return NULL;
}
virt_addr_t temp_buffer;
status = address_space_map(
address_space,
MAP_ADDRESS_ANY,
ctx->ctx_temp_object,
0,
TEMP_OBJECT_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&temp_buffer);
if (status != KERN_OK) {
kern_handle_close(ctx->ctx_temp_object);
kern_handle_close(ctx->ctx_vm_controller);
fs_free(alloc, ctx);
return NULL;
}
ctx->ctx_temp_object_buf = (void *)temp_buffer;
ctx->ctx_alloc = alloc;
ctx->ctx_vtable.open = fs_msg_open;
ctx->ctx_vtable.close = fs_msg_close;
ctx->ctx_vtable.read = fs_msg_read;
ctx->ctx_vtable.write = fs_msg_write;
ctx->ctx_vtable.map = fs_msg_map;
return ctx;
}
@@ -73,6 +128,112 @@ enum fs_status fs_context_unmount_filesystem(struct fs_context *ctx)
return FS_ERR_NOT_IMPLEMENTED;
}
void fs_context_set_channel(struct fs_context *ctx, kern_handle_t channel)
{
ctx->ctx_channel = channel;
}
kern_handle_t fs_context_get_vm_controller(const struct fs_context *ctx)
{
return ctx->ctx_vm_controller;
}
static enum fs_status handle_msg(struct fs_context *ctx)
{
xpc_msg_t msg;
kern_status_t status = xpc_msg_recv_nowait(ctx->ctx_channel, &msg);
if (status == KERN_NO_ENTRY) {
return FS_SUCCESS;
}
if (status != KERN_OK) {
kern_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 *f = get_file(&ctx->ctx_filelist, id);

View File

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

View File

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

View File

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

View File

@@ -27,9 +27,14 @@ extern enum fs_status fs_file_read(
struct fs_file *f,
struct xpc_buffer *buf,
size_t count);
extern enum fs_status fs_file_write(
extern enum fs_status fs_file_read_at(
struct fs_file *f,
struct xpc_buffer *buf,
off_t offset,
size_t count);
extern enum fs_status fs_file_write(
struct fs_file *f,
const struct xpc_buffer *buf,
size_t count);
#endif

View File

@@ -17,9 +17,8 @@ extern kern_status_t fs_msg_open(
int *out_err,
void *arg);
extern kern_status_t fs_msg_close(
const struct msg_endpoint *sender,
const char *path,
int flags,
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
int *out_err,
void *arg);
@@ -31,5 +30,21 @@ extern kern_status_t fs_msg_read(
size_t *out_nr_read,
xpc_buffer_t *out_data,
void *arg);
extern kern_status_t fs_msg_write(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
const xpc_buffer_t *data,
int *out_err,
size_t *out_nr_written,
void *arg);
extern kern_status_t fs_msg_map(
xpc_context_t *ctx,
const xpc_endpoint_t *sender,
int prot,
int flags,
int *out_err,
kern_handle_t *out_vmo,
void *arg);
#endif

View File

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

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

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
#include <mango/status.h>
#include <string.h>
#include <xpc/buffer.h>
#include <xpc/msg.h>
@@ -36,8 +37,7 @@ kern_status_t xpc_buffer_write(
size_t len,
size_t *nr_written)
{
if ((buf->buf_flags & (XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE))
!= (XPC_BUFFER_F_OUT | XPC_BUFFER_F_REMOTE)) {
if (!(buf->buf_flags & XPC_BUFFER_F_OUT)) {
return KERN_BAD_STATE;
}
@@ -46,6 +46,12 @@ kern_status_t xpc_buffer_write(
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) {

View File

@@ -18,6 +18,13 @@
.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;
@@ -49,7 +56,7 @@ typedef struct xpc_buffer {
/* only valid if F_OUT is set.
* if F_FREE_ON_DISCARD is set, must be either NULL or
* allocated via xpc_context_alloc */
const char *buf_ptr;
void *buf_ptr;
};
/* fields that are only valid if F_IN is set */

View File

@@ -29,6 +29,7 @@ extern void xpc_msg_header_init(
unsigned short func);
extern bool xpc_msg_header_validate(const xpc_msg_header_t *msg);
extern kern_status_t xpc_msg_recv(kern_handle_t channel, xpc_msg_t *out);
extern kern_status_t xpc_msg_recv_nowait(kern_handle_t channel, xpc_msg_t *out);
extern kern_status_t xpc_msg_read(
const xpc_msg_t *msg,
size_t offset,

View File

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

View File

@@ -185,6 +185,7 @@ int main(
return -1;
}
fs_context_set_channel(fs, channel);
enum fs_status fs_status = fs_context_mount_filesystem(
fs,
tar_mount,
@@ -196,6 +197,8 @@ int main(
}
while (1) {
fs_context_handle_request(fs);
#if 0
xpc_msg_t msg;
kern_status_t status = xpc_msg_recv(channel, &msg);
if (status != KERN_OK) {
@@ -219,6 +222,7 @@ int main(
kern_logf("message reply error %d", status);
continue;
}
#endif
}
return 0;

View File

@@ -74,8 +74,10 @@ int tar_open(struct tar *tar, const char *path, struct tar_file *out)
}
s += header.size;
if ((uintptr_t)s % (sizeof *bin_header)) {
s += ((sizeof *bin_header)
- ((uintptr_t)s % (sizeof *bin_header)));
}
bin_header = (struct tar_bin_header *)s;
}
@@ -382,8 +384,10 @@ static enum fs_status build_dentry_tree(
}
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;
}

View File

@@ -13,11 +13,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/remote.h>
#include <unistd.h>
int main(const struct rosetta_bootstrap *bs)
{
kern_logf("ld");
kern_handle_t task, address_space;
task_self(&task);
task_get_address_space(task, &address_space);
@@ -29,9 +32,9 @@ int main(const struct rosetta_bootstrap *bs)
sys_remote_set(SYS_REMOTE_NSD, 0, 0);
const char *path = "/usr/lib/libc.so";
int flags = 4;
int fd = open(path, flags);
kern_logf("sending msg: open(%s, %d)", path, flags);
int fd = open(path, flags);
if (fd < 0) {
kern_logf(
@@ -60,5 +63,30 @@ int main(const struct rosetta_bootstrap *bs)
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;
}

View File

@@ -362,7 +362,7 @@ static int emit_interface_msg_function_send_impl(
break;
case TYPE_BUFFER:
emit(ctx,
"msg_data.msg_request.%s_offset = offset;\n",
"msg_data.msg_request.%s_offset = in_offset;\n",
param->p_name);
emit(ctx,
"msg_data.msg_request.%s_len = %s_len;\n",
@@ -693,7 +693,7 @@ static int emit_interface_dispatcher_impl_msg(
break;
case TYPE_BUFFER:
emit(ctx,
"xpc_string_t %s = "
"xpc_buffer_t %s = "
"XPC_BUFFER_IN(msg, " MSG_STRUCT_NAME
".msg_request.%s_offset, " MSG_STRUCT_NAME
".msg_request.%s_len);\n",
@@ -1098,7 +1098,7 @@ static int emit_interface(const struct interface_definition *iface)
b_result result = b_file_open(
NULL,
B_RV_PATH(path),
B_FILE_WRITE_ONLY | B_FILE_CREATE,
B_FILE_WRITE_ONLY | B_FILE_CREATE | B_FILE_TRUNCATE,
&file);
if (b_result_is_error(result)) {
b_throw(result);