meta: move photon/libc to root

This commit is contained in:
2026-02-08 20:45:25 +00:00
parent f00e74260d
commit 345a37962e
140 changed files with 0 additions and 0 deletions

323
libc/sys/horizon/__elf.h Normal file
View File

@@ -0,0 +1,323 @@
#ifndef SYS_HORIZON_SYS___ELF_H_
#define SYS_HORIZON_SYS___ELF_H_
#include <magenta/types.h>
#include <stdint.h>
#define ELF_LOAD_ERR -1
#define ELF_LOADED_EXEC 0
#define ELF_LOADED_INTERP 1
#define ELF_MAG0 0x7f
#define ELF_MAG1 'E'
#define ELF_MAG2 'L'
#define ELF_MAG3 'F'
#define ELF_NIDENT 16
#define SHT_NONE 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_DYNAMIC 6
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_DYNSYM 11
/** Little endian. */
#define ELFDATA2LSB (1)
/** 64-bit. */
#define ELFCLASS64 (2)
/** x86_64 machine type. */
#define EM_X86_64 (62)
/** ELF current version. */
#define EV_CURRENT (1)
/** Dynamic section tags. */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_JMPREL 23
#define DT_GNU_HASH 0x6ffffef5
#define DT_AUXILIARY 0x7ffffffd
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GOT32 3
#define R_386_PLT32 4
#define R_386_GOTOFF 9
#define R_386_GOTPC 10
#define R_386_GOT32X 43
#define R_X86_64_64 1
#define R_X86_64_PC32 2
#define R_X86_64_GOT32 3
#define R_X86_64_PLT32 4
#define R_X86_64_COPY 5
#define R_X86_64_GLOB_DAT 6
#define R_X86_64_JUMP_SLOT 7
#define R_X86_64_RELATIVE 8
#define R_X86_64_GOTPCREL 9
#define R_X86_64_32 10
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
/* Section flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHN_UNDEF 0
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((elf_word_t)(i))
#define ELF64_ST_BIND(i) ((i) >> 4)
#define ELF64_ST_TYPE(i) ((i)&0xf)
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_NUM 3
typedef uint64_t elf_addr_t;
typedef uint64_t elf_off_t;
typedef uint16_t elf_half_t;
typedef uint32_t elf_word_t;
typedef int32_t elf_sword_t;
typedef uint64_t elf_xword_t;
typedef int64_t elf_sxword_t;
/**
* ELF file header.
*/
typedef struct {
uint8_t e_ident[ELF_NIDENT];
elf_half_t e_type;
elf_half_t e_machine;
elf_word_t e_version;
elf_addr_t e_entry;
elf_off_t e_phoff;
elf_off_t e_shoff;
elf_word_t e_flags;
elf_half_t e_ehsize;
elf_half_t e_phentsize;
elf_half_t e_phnum;
elf_half_t e_shentsize;
elf_half_t e_shnum;
elf_half_t e_shstrndx;
} elf_ehdr_t;
/**
* ELF section header.
*/
typedef struct {
elf_word_t sh_name;
elf_word_t sh_type;
elf_xword_t sh_flags;
elf_addr_t sh_addr;
elf_off_t sh_offset;
elf_xword_t sh_size;
elf_word_t sh_link;
elf_word_t sh_info;
elf_xword_t sh_addralign;
elf_xword_t sh_entsize;
} elf_shdr_t;
/**
* ELF symbol.
*/
typedef struct {
elf_word_t st_name;
unsigned char st_info;
unsigned char st_other;
elf_half_t st_shndx;
elf_addr_t st_value;
elf_xword_t st_size;
} elf_sym_t;
/**
* ELF program header.
*/
typedef struct {
elf_word_t p_type;
elf_word_t p_flags;
elf_off_t p_offset;
elf_addr_t p_vaddr;
elf_addr_t p_paddr;
elf_xword_t p_filesz;
elf_xword_t p_memsz;
elf_xword_t p_align;
} elf_phdr_t;
/**
* Extended ELF relocation information.
*/
typedef struct {
elf_addr_t r_offset;
elf_xword_t r_info;
elf_sxword_t r_addend;
} elf_rela_t;
/**
* Dynamic section entries
*/
typedef struct {
elf_sxword_t d_tag;
union {
elf_xword_t d_val;
elf_addr_t d_ptr;
} d_un;
} elf_dyn_t;
/**
* Section header types.
*/
enum elf_stype {
ST_NONE = 0,
ST_PROGBITS = 1,
ST_SYMTAB = 2,
ST_STRTAB = 3,
ST_NOBITS = 8,
ST_REL = 9
};
/**
* Program header types.
*/
enum elf_ptype {
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6
};
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
/**
* ELF identification byte locations.
*/
enum elf_ident {
EI_MAG0 = 0,
EI_MAG1 = 1,
EI_MAG2 = 2,
EI_MAG3 = 3,
EI_CLASS = 4,
EI_DATA = 5,
EI_VERSION = 6,
EI_OSABI = 7,
EI_ABIVERSION = 8,
EI_PAD = 9
};
enum elf_type {
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
};
#define AT_NULL 0
#define AT_IGNORE 1
#define AT_EXECFD 2
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_ENTRY 9
#define AT_NOTELF 10
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_CLKTCK 17
#define AT_PLATFORM 15
#define AT_HWCAP 16
#define AT_FPUCW 18
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
#define AT_IGNOREPPC 22
#define AT_SECURE 23
#define AT_BASE_PLATFORM 24
#define AT_RANDOM 25
#define AT_HWCAP2 26
#define AT_EXECFN 31
#define AT_SYSINFO 32
#define AT_SYSINFO_EHDR 33
#define AT_L1I_CACHESHAPE 34
#define AT_L1D_CACHESHAPE 35
#define AT_L2_CACHESHAPE 36
#define AT_L3_CACHESHAPE 37
#define AT_ENTRY_COUNT 38
struct bootdata;
struct bootfs_file;
struct elf_image {
mx_handle_t image_vmo, rw_vmo;
mx_vaddr_t local_base_addr, remote_base_addr;
mx_handle_t local_root_vmar, local_exec_vmar;
mx_handle_t remote_root_vmar, remote_exec_vmar;
size_t exec_vmar_size;
elf_ehdr_t hdr;
uintptr_t dynstr_offset;
size_t dynstr_len;
uintptr_t dynsym_offset;
size_t dynsym_len, dynsym_entsz;
elf_phdr_t dynamic;
enum { NO_HASH, REG_HASH, GNU_HASH } hash_type;
uintptr_t hash_offset;
};
extern void __elf_image_init(mx_handle_t local_vmar, mx_handle_t remote_vmar, struct elf_image *out);
extern int __elf_image_load_image(struct elf_image *image, mx_handle_t image_vmo);
extern int __elf_get_interp_path(mx_handle_t exec_vmo, char *out, size_t max);
extern int __elf_check_dependencies(struct elf_image *image);
extern mx_vaddr_t __elf_image_get_symbol(struct elf_image *image, const char *name);
extern int __elf_image_link(struct elf_image *exec, struct elf_image *vdso);
extern mx_vaddr_t __elf_image_entry_point(struct elf_image *image);
extern void __elf_image_cleanup(struct elf_image *image);
#endif

36
libc/sys/horizon/__fio.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef SYS_HORIZON___FIO_H_
#define SYS_HORIZON___FIO_H_
#define __FIO_BUFSZ 512
#if defined(__cplusplus)
extern "C" {
#endif
struct __io_file {
char in_buf[__FIO_BUFSZ];
char out_buf[__FIO_BUFSZ];
unsigned long in_buf_ptr, in_buf_len;
unsigned long out_buf_len;
int fd, unget;
char err, eof;
};
extern int __fileno(struct __io_file *f);
extern void __fio_init(int in, int out, int err);
extern unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz);
extern unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz);
extern unsigned int __fio_flush(struct __io_file *f);
extern int __fio_error(struct __io_file *f);
extern int __fio_eof(struct __io_file *f);
extern int __fio_ungetc(struct __io_file *f, char c);
extern int __fio_fopen(const char *path, const char *mode, struct __io_file *out);
extern int __fio_fclose(struct __io_file *in);
extern int __fio_fdopen(int fd, const char *mode, struct __io_file *out);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,8 @@
#ifndef SYS_HORIZON_HEAP_H_
#define SYS_HORIZON_HEAP_H_
#include "__init.h"
extern int __heap_init();
#endif

View File

@@ -0,0 +1,4 @@
#ifndef SYS_HORIZON_INIT_H_
#define SYS_HORIZON_INIT_H_
#endif

View File

@@ -0,0 +1,14 @@
#ifndef SYS_LINUX___SYSTEM_H_
#define SYS_LINUX___SYSTEM_H_
#if defined(__cplusplus)
extern "C" {
#endif
extern _Noreturn void __exit(int code);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,6 @@
#ifndef SYS_HORIZON___TIME_H_
#define SYS_HORIZON___TIME_H_
#include <time.h>
#endif

View File

157
libc/sys/horizon/dirent.c Normal file
View File

@@ -0,0 +1,157 @@
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <mio/fs.h>
#include <mio/dirent.h>
DIR *opendir(const char *path)
{
int fd = open(path, O_DIRECTORY);
if (fd < 0) {
return NULL;
}
DIR *out = malloc(sizeof(*out));
if (!out) {
__set_errno(ENOMEM);
return NULL;
}
memset(out, 0x0, sizeof(*out));
out->fd = fd;
return out;
}
int closedir(DIR *d)
{
close(d->fd);
for (int i = 0; i < d->cache_size; i++) {
if (d->dent_cache[i].d_namep) {
free(d->dent_cache[i].d_namep);
}
}
free(d);
return 0;
}
static void clear_cache(DIR *d)
{
for (int i = 0; i < d->cache_size; i++) {
if (d->dent_cache[i].d_namep) {
free(d->dent_cache[i].d_namep);
}
d->dent_cache[i].d_namep = NULL;
}
d->cache_size = d->cache_idx = 0;
}
static int refill(DIR *d)
{
clear_cache(d);
for (int i = 0; i < d->cache_size; i++) {
free(d->dent_cache[i].d_namep);
d->dent_cache[i].d_namep = NULL;
}
d->cache_size = d->cache_idx = 0;
mio_dirent dent[__SYS_DENT_CACHE_SZ];
int r = mio_getdents(d->fd, dent, __SYS_DENT_CACHE_SZ);
if (r < 0) {
__set_errno(-r);
return -1;
}
for (int i = 0; i < r; i++) {
struct __dentcache *cache_ent = &d->dent_cache[i];
cache_ent->d_ino = dent[i].d_ino;
cache_ent->d_type = dent[i].d_type;
cache_ent->d_namep = strdup(dent[i].d_name);
}
d->cache_idx = 0;
d->cache_size = r;
return 0;
}
static void fill_dirent(DIR *d, struct dirent *out)
{
if (d->cache_idx >= d->cache_size) {
return;
}
struct __dentcache *cache_ent = &d->dent_cache[d->cache_idx];
out->d_ino = cache_ent->d_ino;
out->d_type = cache_ent->d_type;
if (cache_ent->d_namep) {
strncpy(out->d_name, cache_ent->d_namep, sizeof out->d_name - 1);
out->d_name[sizeof out->d_name - 1] = '\0';
}
}
struct dirent *readdir(DIR *d)
{
if (d->cache_idx == d->cache_size) {
if (refill(d) != 0 || !d->cache_size) {
return NULL;
}
}
fill_dirent(d, &d->cdent);
d->cache_idx++;
d->seek++;
return &d->cdent;
}
int readdir_r(DIR *d, struct dirent *entry, struct dirent **result)
{
if (d->cache_idx == d->cache_size) {
if (refill(d) != 0) {
return 1;
}
if (d->cache_size == 0) {
if (result) {
*result = NULL;
}
return 0;
}
}
fill_dirent(d, entry);
d->seek++;
if (result) {
*result = entry;
}
return 0;
}
void rewinddir(DIR *d)
{
d->seek = mio_seek(d->fd, 0, SEEK_SET);
clear_cache(d);
}
void seekdir(DIR *d, long int off)
{
d->seek = mio_seek(d->fd, off, SEEK_SET);
clear_cache(d);
}
long int telldir(DIR *d)
{
return d->seek;
}

56
libc/sys/horizon/dlfcn.c Normal file
View File

@@ -0,0 +1,56 @@
#include <magenta/types.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <mio/fs.h>
__attribute__((weak)) void *dyld_load_object(const char *path, mx_handle_t handle, int mode) { return NULL; }
__attribute__((weak)) void *dyld_get_symbol(void *handle, const char *name) { return NULL; }
__attribute__((weak)) int dyld_close_object(void *handle) { return 0; }
__attribute__((weak)) char *dyld_get_error(void) { return NULL; }
static char dl_error[512] = {};
void *dlopen(const char *path, int mode)
{
/* TODO include error message from errno */
int fd = open(path, O_RDONLY);
if (fd == -1) {
snprintf(dl_error, sizeof dl_error, "cannot open '%s'", path);
return NULL;
}
mx_handle_t image_vmo = MX_NULL_HANDLE;
int err = mio_map_file(fd, &image_vmo);
close(fd);
if (err != 0) {
snprintf(dl_error, sizeof dl_error, "cannot load '%s'", path);
return NULL;
}
dl_error[0] = '\0';
return dyld_load_object(path, image_vmo, mode);
}
void *dlsym(void *handle, const char *name)
{
return dyld_get_symbol(handle, name);
}
int dlclose(void *handle)
{
return dyld_close_object(handle);
}
char *dlerror(void)
{
if (dl_error[0] != '\0') {
return dl_error;
}
return dyld_get_error();
}

673
libc/sys/horizon/elf.c Normal file
View File

@@ -0,0 +1,673 @@
#include <magenta/misc.h>
#include <magenta/errors.h>
#include <magenta/handle.h>
#include <magenta/vmo.h>
#include <magenta/vmar.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "__elf.h"
#define HIDDEN __attribute__((visibility("hidden")))
#define VDSO_SONAME "mx.dylib"
#define NEEDS_NOTHING 0
#define NEEDS_VDSO 1
#define NEEDS_MORE 2
#define ACL (PF_R | PF_W | PF_X)
#define ACCESS(x) ((x) & ACL)
/* TODO in case we ever support ELF32 images */
#define elf_class_bits(x) (64)
#define PAGE_OFFSET(v) ((v) & (MX_PAGE_SIZE - 1))
#define PAGE_ALIGN_DOWN(v) (v) &= ~(MX_PAGE_SIZE - 1)
#define PAGE_ALIGN_UP(v) \
do { \
if ((v) & (MX_PAGE_SIZE - 1)) { \
v &= ~(MX_PAGE_SIZE - 1); \
v += MX_PAGE_SIZE; \
} \
} while (0)
#undef DEBUG_LOG
HIDDEN void __elf_image_init(mx_handle_t local_vmar, mx_handle_t remote_vmar, struct elf_image *out)
{
memset(out, 0x0, sizeof(*out));
out->local_root_vmar = local_vmar;
out->remote_root_vmar = remote_vmar;
}
static int elf_validate_ehdr(elf_ehdr_t *hdr)
{
if (hdr->e_ident[EI_MAG0] != ELF_MAG0) {
return -1;
}
if (hdr->e_ident[EI_MAG1] != ELF_MAG1) {
return -1;
}
if (hdr->e_ident[EI_MAG2] != ELF_MAG2) {
return -1;
}
if (hdr->e_ident[EI_MAG3] != ELF_MAG3) {
return -1;
}
if (hdr->e_ident[EI_CLASS] != ELFCLASS64) {
return -1;
}
if (hdr->e_machine != EM_X86_64) {
return -1;
}
if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
return -1;
}
if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
return -1;
}
return 0;
}
static int read_header(struct elf_image *image)
{
mx_status_t err = mx_vmo_read(image->image_vmo, (uint8_t *)&image->hdr, sizeof(image->hdr), 0);
if (err != MX_OK) {
printf("vmo_read %x error %s\n", image->image_vmo, mx_status_to_string(err));
return -1;
}
return elf_validate_ehdr(&image->hdr);
}
static mx_status_t allocate_vmar(struct elf_image *image, size_t size)
{
mx_status_t err = mx_vmar_allocate(image->local_root_vmar,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE |
MX_VM_CAN_MAP_EXEC | MX_VM_CAN_MAP_SPECIFIC,
0, size, &image->local_exec_vmar, &image->local_base_addr);
if (err != MX_OK) {
return err;
}
err = mx_vmar_allocate(image->remote_root_vmar,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE |
MX_VM_CAN_MAP_EXEC | MX_VM_CAN_MAP_SPECIFIC,
0, size, &image->remote_exec_vmar, &image->remote_base_addr);
image->exec_vmar_size = size;
return err;
}
static void deduce_dynsym_count(struct elf_image *image)
{
if (image->hash_type == REG_HASH) {
image->dynsym_len = *(((uint32_t *)image->hash_offset) + 1);
} else {
/* We don't need to know the symbol count to use DT_GNU_HASH
* (which is good because calculating it is a pain) */
image->dynsym_len = 0;
}
}
static void read_dynamic_segment(struct elf_image *image)
{
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
for (int i = 0;; i++) {
elf_dyn_t *dyn = &dyn_array[i];
if (dyn->d_tag == DT_NULL) {
break;
}
switch (dyn->d_tag) {
case DT_STRTAB:
image->dynstr_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
case DT_STRSZ:
image->dynstr_len = dyn->d_un.d_val;
break;
case DT_SYMTAB:
image->dynsym_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
case DT_SYMENT:
image->dynsym_entsz = dyn->d_un.d_val;
break;
case DT_HASH:
/* prefer the GNU hash table */
if (image->hash_type == GNU_HASH) {
continue;
}
image->hash_type = REG_HASH;
image->hash_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
case DT_GNU_HASH:
image->hash_type = GNU_HASH;
image->hash_offset = dyn->d_un.d_ptr;
dyn->d_un.d_ptr += image->remote_base_addr;
break;
default:
break;
}
}
}
static void get_memory_requirements(void *phdr_buf, int entsize, int nr_phdr,
size_t *out_vmem, size_t *out_rw)
{
size_t vmem_max = 0;
size_t rw_max = 0;
for (int i = 0; i < nr_phdr; i++) {
elf_phdr_t *phdr = (elf_phdr_t *)((char *)phdr_buf + (i * entsize));
if (phdr->p_type != PT_LOAD) {
continue;
}
size_t foffset = phdr->p_offset;
size_t voffset = phdr->p_vaddr;
PAGE_ALIGN_DOWN(foffset);
PAGE_ALIGN_DOWN(voffset);
size_t vend = phdr->p_vaddr + phdr->p_memsz;
PAGE_ALIGN_UP(vend);
size_t fsize = phdr->p_filesz;
size_t vsize = vend - voffset;
PAGE_ALIGN_UP(fsize);
if (phdr->p_flags & PF_W) {
rw_max += vsize;
}
if (vend > vmem_max) {
vmem_max = vend;
}
}
*out_rw = rw_max;
*out_vmem = vmem_max;
}
static mx_status_t map_memory(struct elf_image *image,
mx_off_t voffset, mx_off_t foffset, size_t sz, int flags, void **out_buf)
{
mx_status_t err = MX_OK;
mx_flags_t options = MX_VM_SPECIFIC;
mx_handle_t vmo = image->image_vmo;
if (flags & PF_R) {
options |= MX_VM_PERM_READ;
}
if (flags & PF_W) {
options |= MX_VM_PERM_WRITE;
vmo = image->rw_vmo;
}
if (flags & PF_X) {
options |= MX_VM_PERM_EXEC;
}
mx_vaddr_t local_addr = 0, remote_addr = 0;
*out_buf = NULL;
err = mx_vmar_map(image->local_exec_vmar, options, voffset, vmo, foffset, sz, &local_addr);
if (err != MX_OK) {
return err;
}
err = mx_vmar_map(image->remote_exec_vmar, options, voffset, vmo, foffset, sz, &remote_addr);
if (err != MX_OK) {
return err;
}
*out_buf = (void *)local_addr;
return MX_OK;
}
static mx_status_t map_image(struct elf_image *image,
void *phdr_buf, int phdr_entsize, int phdr_num)
{
size_t rw_offset = 0;
mx_status_t err = MX_OK;
for (int i = 0; i < phdr_num; i++) {
elf_phdr_t *phdr = (elf_phdr_t *)((char *)phdr_buf + (i * phdr_entsize));
if (phdr->p_type == PT_DYNAMIC) {
image->dynamic = *phdr;
}
if (phdr->p_type != PT_LOAD) {
continue;
}
size_t foffset = phdr->p_offset;
size_t voffset = phdr->p_vaddr;
PAGE_ALIGN_DOWN(foffset);
PAGE_ALIGN_DOWN(voffset);
size_t vend = phdr->p_vaddr + phdr->p_memsz;
PAGE_ALIGN_UP(vend);
size_t fsize = phdr->p_filesz;
size_t vsize = vend - voffset;
PAGE_ALIGN_UP(fsize);
if (phdr->p_flags & PF_W) {
size_t rw_vmo_offset = rw_offset;
size_t rw_vmo_size = vsize;
size_t bss_offset = phdr->p_vaddr + phdr->p_filesz;
size_t bss_size = phdr->p_memsz - phdr->p_filesz;
void *segment_buf = NULL;
err = map_memory(image, voffset, rw_vmo_offset, vsize, phdr->p_flags, &segment_buf);
if (err != MX_OK) {
return err;
}
void *file_dest = (char *)image->local_base_addr + phdr->p_vaddr;
void *bss_dest = (char *)image->local_base_addr + bss_offset;
mx_vmo_read(image->image_vmo, file_dest, phdr->p_filesz, phdr->p_offset);
if (bss_size) {
memset(bss_dest, 0x0, bss_size);
}
rw_offset += rw_vmo_size;
} else {
void *segment_buf = NULL;
err = map_memory(image, voffset, foffset, vsize, phdr->p_flags, &segment_buf);
if (err != MX_OK) {
return err;
}
}
}
return MX_OK;
}
HIDDEN int __elf_image_load_image(struct elf_image *image, mx_handle_t image_vmo)
{
image->image_vmo = image_vmo;
int status = read_header(image);
if (status != 0) {
printf("read_header error\n");
return status;
}
size_t phdr_bufsz = image->hdr.e_phentsize * image->hdr.e_phnum;
unsigned char phdr_buf[phdr_bufsz];
mx_vmo_read(image_vmo, phdr_buf, phdr_bufsz, image->hdr.e_phoff);
size_t rw_size, vmem_size;
get_memory_requirements(phdr_buf, image->hdr.e_phentsize, image->hdr.e_phnum, &vmem_size, &rw_size);
if (allocate_vmar(image, vmem_size) != MX_OK) {
printf("allocate_vmar error\n");
return -1;
}
if (rw_size) {
mx_vmo_create(rw_size, MX_VM_PERM_READ | MX_VM_PERM_WRITE, &image->rw_vmo);
}
mx_status_t err = map_image(image, phdr_buf, image->hdr.e_phentsize, image->hdr.e_phnum);
if (err != MX_OK) {
printf("map_image error\n");
return -1;
}
read_dynamic_segment(image);
return 0;
}
HIDDEN int __elf_get_interp_path(mx_handle_t image_vmo, char *out, size_t max)
{
elf_ehdr_t hdr;
mx_vmo_read(image_vmo, (uint8_t *)&hdr, sizeof(hdr), 0);
if (elf_validate_ehdr(&hdr) != 0) {
return -1;
}
unsigned char phdr_buf[hdr.e_phentsize * hdr.e_phnum];
mx_vmo_read(image_vmo, phdr_buf, hdr.e_phentsize * hdr.e_phnum, hdr.e_phoff);
uintptr_t dynamic_offset = 0, interp_offset = 0;
size_t dynamic_sz = 0, interp_sz = 0;
for (size_t i = 0; i < hdr.e_phnum; i++) {
elf_phdr_t *phdr = (elf_phdr_t *)(phdr_buf + i * hdr.e_phentsize);
switch (phdr->p_type) {
case PT_DYNAMIC:
dynamic_offset = phdr->p_offset;
dynamic_sz = phdr->p_filesz;
break;
case PT_INTERP:
interp_offset = phdr->p_offset;
interp_sz = phdr->p_filesz;
break;
default:
break;
}
}
if (!dynamic_sz || !interp_offset) {
return 0;
}
if (max > interp_sz) {
max = interp_sz;
}
mx_vmo_read(image_vmo, (uint8_t *)out, max, interp_offset);
return 1;
}
HIDDEN int __elf_check_dependencies(struct elf_image *image)
{
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
for (int i = 0;; i++) {
elf_dyn_t *dyn = &dyn_array[i];
if (dyn->d_tag == DT_NULL) {
break;
}
if (dyn->d_tag != DT_NEEDED) {
continue;
}
const char *lib_name = (const char *)(image->local_base_addr + image->dynstr_offset + dyn->d_un.d_ptr);
if (strcmp(lib_name, VDSO_SONAME) != 0) {
/* We can't load executables that link to libraries other than
* libmx */
return -1;
}
}
return 0;
}
static elf_sym_t *get_dynsym_entry(struct elf_image *image, unsigned int idx)
{
return (elf_sym_t *)(image->local_base_addr + image->dynsym_offset + idx * image->dynsym_entsz);
}
static const char *get_dynstr(struct elf_image *image, unsigned int idx)
{
return (const char *)(image->local_base_addr + image->dynstr_offset + idx);
}
static int do_rela(struct elf_image *image, struct elf_image *lib, uintptr_t ptr, size_t sz, size_t entsz)
{
size_t entries = sz / entsz;
for (size_t i = 0; i < entries; i++) {
elf_rela_t *rela = (elf_rela_t *)(image->local_base_addr + ptr + i * entsz);
int sym_idx = ELF64_R_SYM(rela->r_info);
int type = ELF64_R_TYPE(rela->r_info);
mx_vaddr_t sym_val = 0;
if (type != R_X86_64_RELATIVE) {
elf_sym_t *dynsym = get_dynsym_entry(image, sym_idx);
const char *name = get_dynstr(image, dynsym->st_name);
sym_val = __elf_image_get_symbol(image, name);
if (!sym_val && lib) {
sym_val = __elf_image_get_symbol(lib, name);
}
if (!sym_val) {
return -1;
}
}
int ok = 1;
mx_status_t status = MX_OK;
switch (type) {
case R_X86_64_GLOB_DAT: {
elf_xword_t val = sym_val;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} case R_X86_64_64: {
elf_xword_t val = sym_val + rela->r_addend;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} case R_X86_64_JUMP_SLOT: {
elf_xword_t val = sym_val;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} case R_X86_64_RELATIVE: {
elf_xword_t val = image->remote_base_addr + rela->r_addend;
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
*dest = val;
break;
} default:
ok = 0;
break;
}
if (!ok || status != MX_OK) {
return -1;
}
}
return 0;
}
static int relocate(struct elf_image *image, struct elf_image *lib)
{
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
int result = 0;
uintptr_t rel_addr = 0, rela_addr = 0, plt_addr = 0;
size_t rel_sz = 0, rel_entsz = 0;
size_t rela_sz = 0, rela_entsz = 0;
size_t plt_sz = 0, plt_entsz = 0;
int plt_enttype;
for (int i = 0;; i++) {
elf_dyn_t *dyn = &dyn_array[i];
if (dyn->d_tag == DT_NULL) {
break;
}
switch (dyn->d_tag) {
case DT_REL:
rel_addr = dyn->d_un.d_ptr;
break;
case DT_RELSZ:
rel_sz = dyn->d_un.d_val;
break;
case DT_RELENT:
rel_entsz = dyn->d_un.d_val;
break;
case DT_RELA:
rela_addr = dyn->d_un.d_ptr;
break;
case DT_RELASZ:
rela_sz = dyn->d_un.d_val;
break;
case DT_RELAENT:
rela_entsz = dyn->d_un.d_val;
break;
case DT_PLTRELSZ:
plt_sz = dyn->d_un.d_val;
break;
case DT_JMPREL:
plt_addr = dyn->d_un.d_ptr;
break;
case DT_PLTREL:
plt_enttype = dyn->d_un.d_ptr;
break;
default:
break;
}
if (dyn->d_tag != DT_NEEDED) {
continue;
}
}
if (rel_sz) {
/* DT_REL is not supported */
return -1;
}
if (plt_enttype == DT_RELA) {
plt_entsz = rela_entsz ? rela_entsz : sizeof(elf_rela_t);
} else if (plt_enttype == DT_REL) {
return -1;
}
int r;
if (rela_sz) {
r = do_rela(image, lib, rela_addr, rela_sz, rela_entsz);
if (r != 0) {
return r;
}
}
if (plt_sz) {
r = do_rela(image, lib, plt_addr, plt_sz, plt_entsz);
if (r != 0) {
return r;
}
}
return 0;
}
HIDDEN int __elf_image_link(struct elf_image *exec, struct elf_image *vdso)
{
int status = relocate(vdso, NULL);
if (status != 0) {
return status;
}
return relocate(exec, vdso);
}
HIDDEN mx_vaddr_t __elf_image_entry_point(struct elf_image *image)
{
return image->remote_base_addr + image->hdr.e_entry;
}
static uint32_t gnu_hash(const char *name)
{
uint32_t h = 5381;
for (; *name; name++) {
h = (h << 5) + h + *name;
}
return h;
}
static mx_vaddr_t sym_gnu_hash_search(struct elf_image *image, const char *name)
{
uint32_t hash = gnu_hash(name);
uint32_t *hashtab = (uint32_t *)(image->local_base_addr + image->hash_offset);
uint32_t nbuckets = hashtab[0];
uint32_t symoffset = hashtab[1];
uint32_t bloom_size = hashtab[2];
uint32_t bloom_shift = hashtab[3];
uint64_t *bloom = (uint64_t *)&hashtab[4];
uint32_t *buckets = (uint32_t *)&bloom[bloom_size];
uint32_t *chain = &buckets[nbuckets];
uint64_t bloom_word =
bloom[(hash / elf_class_bits(image)) % bloom_size];
uint64_t bloom_mask =
((uint64_t)1 << (hash % elf_class_bits(image))) |
((uint64_t)1 << ((hash >> bloom_shift) % elf_class_bits(image)));
if ((bloom_word & bloom_mask) != bloom_mask) {
return 0;
}
uint32_t symix = buckets[hash % nbuckets];
if (symix < symoffset) {
return 0;
}
const char *strtab = (const char *)(image->local_base_addr + image->dynstr_offset);
elf_sym_t *symtab = (elf_sym_t *)(image->local_base_addr + image->dynsym_offset);
while (1) {
const char *symname = strtab + symtab[symix].st_name;
uint32_t symhash = chain[symix - symoffset];
if ((symhash | 1) == (hash | 1) && !strcmp(symname, name)) {
return image->remote_base_addr + symtab[symix].st_value;
}
if (symhash & 1) {
break;
}
symix++;
}
return 0;
}
HIDDEN mx_vaddr_t __elf_image_get_symbol(struct elf_image *image, const char *name)
{
switch (image->hash_type) {
case GNU_HASH:
return sym_gnu_hash_search(image, name);
default:
return 0;
}
}
HIDDEN void __elf_image_cleanup(struct elf_image *image)
{
if (image->local_exec_vmar) {
mx_vmar_unmap(image->local_exec_vmar, 0, image->exec_vmar_size);
mx_vmar_destroy(image->local_exec_vmar);
mx_handle_close(image->local_exec_vmar);
image->local_exec_vmar = MX_NULL_HANDLE;
}
if (image->remote_exec_vmar) {
mx_handle_close(image->remote_exec_vmar);
image->remote_exec_vmar = MX_NULL_HANDLE;
}
if (image->rw_vmo) {
mx_handle_close(image->rw_vmo);
image->rw_vmo = MX_NULL_HANDLE;
}
}

View File

@@ -0,0 +1,35 @@
#include <stddef.h>
#include <string.h>
extern const char **__crt_environ();
char *__crt_sys_getenv(const char *name)
{
const char **envp = __crt_environ();
for (int i = 0; envp[i] != NULL; i++) {
int equal = -1;
const char *env = envp[i];
for (int ii = 0; env[ii] != '\0'; ii++) {
if (env[ii] == '=') {
equal = ii;
break;
}
}
if (equal == -1) {
continue;
}
char env_name[equal + 1];
memcpy(env_name, env, equal);
env_name[equal] = '\0';
if (!strcmp(env_name, name)) {
return (char *)(env + equal + 1);
}
}
return NULL;
}

31
libc/sys/horizon/fcntl.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef SYS_HORIZON_FCNTL_H_
#define SYS_HORIZON_FCNTL_H_
#include <sys/types.h>
#define O_ACCMODE 0003
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_CREAT 0100
#define O_EXCL 0200
#define O_NOCTTY 0400
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NONBLOCK 04000
#define O_NDELAY O_NONBLOCK
#define O_SYNC 04010000
#define O_FSYNC O_SYNC
#define O_ASYNC 020000
#define O_LARGEFILE 0100000
#define O_DIRECTORY 0200000
#define O_NOFOLLOW 0400000
#define O_CLOEXEC 02000000
#define O_DIRECT 040000
#define O_NOATIME 01000000
#define O_PATH 010000000
#define O_DSYNC 010000
#define O_TMPFILE (020000000 | __O_DIRECTORY)
#endif

202
libc/sys/horizon/fio.c Normal file
View File

@@ -0,0 +1,202 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "sys/types.h"
#include "__fio.h"
static struct __io_file __stdin = {};
static struct __io_file __stdout = {};
static struct __io_file __stderr = {};
static int flags_from_mode(const char *r)
{
return 0;
}
static int refill(struct __io_file *fp)
{
ssize_t err = read(fp->fd, fp->in_buf, sizeof fp->in_buf);
if (err < 0) {
fp->err = 1;
return 0;
}
fp->in_buf_ptr = 0;
fp->in_buf_len = err;
return err;
}
FILE *__get_stdio_file(int i)
{
switch (i) {
case 0:
return &__stdin;
case 1:
return &__stdout;
case 2:
return &__stderr;
default:
return NULL;
}
}
void __fio_init(int in, int out, int err)
{
__stdin.fd = in;
__stdout.fd = out;
__stderr.fd = err;
}
int __fio_fopen(const char *path, const char *mode, struct __io_file *fp)
{
/* TODO */
int fd = open(path, 0);
if (fd == -1) {
return -1;
}
fp->fd = fd;
return 0;
}
int __fio_fclose(struct __io_file *fp)
{
if (fp->fd == -1) {
return -1;
}
close(fp->fd);
fp->fd = -1;
return 0;
}
int __fio_fdopen(int fd, const char *mode, struct __io_file *fp)
{
if (fd == -1) {
return -1;
}
fp->fd = fd;
return 0;
}
int __fileno(struct __io_file *f)
{
return (int)f->fd;
}
unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz)
{
if (sz == 0) {
return 0;
}
size_t r = 0;
char *out = buf;
if (f->unget) {
*out++ = f->unget;
f->unget = 0;
r++;
sz--;
}
size_t available = f->in_buf_len - f->in_buf_ptr;
size_t bufread = sz;
if (bufread > available) {
bufread = available;
}
memcpy(out, f->in_buf + f->in_buf_ptr, bufread);
f->in_buf_ptr += bufread;
out += bufread;
sz -= bufread;
r += bufread;
if (sz == 0) {
return r;
}
while (1) {
refill(f);
available = f->in_buf_len - f->in_buf_ptr;
if (available == 0) {
f->eof = 1;
break;
}
bufread = sz;
if (bufread > available) {
bufread = available;
}
memcpy(out, f->in_buf + f->in_buf_ptr, bufread);
f->in_buf_ptr += bufread;
out += bufread;
sz -= bufread;
r += bufread;
if (sz == 0 || f->err || f->eof) {
break;
}
}
if (sz > 0) {
f->eof = 1;
}
return r;
}
unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz)
{
for (unsigned int i = 0; i < sz; i++) {
if (f->out_buf_len >= __FIO_BUFSZ) {
__fio_flush(f);
}
f->out_buf[f->out_buf_len++] = buf[i];
if (buf[i] == '\n') {
__fio_flush(f);
}
}
return sz;
}
int __fio_ungetc(struct __io_file *f, char c)
{
if (f->unget) {
return -1;
}
f->unget = c;
return 0;
}
unsigned int __fio_flush(struct __io_file *f)
{
ssize_t res = write(f->fd, f->out_buf, f->out_buf_len);
if (res != f->out_buf_len) {
f->err = 1;
}
size_t flushed = f->out_buf_len;
f->out_buf_len = 0;
return flushed;
}
int __fio_error(struct __io_file *f)
{
return f->err != 0;
}
int __fio_eof(struct __io_file *f)
{
return f->eof != 0;
}

101
libc/sys/horizon/heap.c Normal file
View File

@@ -0,0 +1,101 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <magenta/vmo.h>
#include <magenta/bootstrap.h>
#include <magenta/errors.h>
#include <magenta/misc.h>
#include <magenta/vmar.h>
/* 1 GiB */
#define HEAP_REGION_SZ 0x40000000
#define ROUND_UP(x, b) x += (b) - ((x) % (b))
static uintptr_t heap_start = 0;
static uintptr_t heap_end = 0;
static uintptr_t heap_alloc_point = 0;
static size_t heap_sz = 0;
static mx_handle_t heap_vmo = MX_NULL_HANDLE;
static mx_handle_t heap_vmar = MX_NULL_HANDLE;
void __crt_heap_init(size_t sz)
{
mx_handle_t root_vmar = mx_bootstrap_handle_get(MX_B_VMAR_ROOT);
mx_vaddr_t heap = 0;
mx_status_t status = mx_vmar_allocate(root_vmar,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE | MX_VM_CAN_MAP_SPECIFIC,
0, HEAP_REGION_SZ, &heap_vmar, &heap);
if (status != MX_OK) {
fprintf(stderr, "fatal: cannot allocate heap virtual region (%s)\n", mx_status_to_string(status));
abort();
}
status = mx_vmo_create(
sz,
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE | MX_VM_CAN_MAP_SPECIFIC,
&heap_vmo);
if (status != MX_OK) {
fprintf(stderr, "fatal: cannot allocate heap (%s)\n", mx_status_to_string(status));
abort();
}
status = mx_vmar_map(heap_vmar,
MX_VM_PERM_READ | MX_VM_PERM_WRITE | MX_VM_SPECIFIC,
0, heap_vmo, 0, sz,
&heap);
if (status != MX_OK) {
fprintf(stderr, "fatal: cannot map heap (%s)\n", mx_status_to_string(status));
abort();
}
heap_sz = sz;
heap_start = heap;
heap_end = heap + heap_sz;
heap_alloc_point = heap_start;
memset((void *)heap, 0x0, heap_sz);
}
void *__crt_heap_extend(size_t sz)
{
if (sz % MX_PAGE_SIZE) {
sz &= (MX_PAGE_SIZE - 1);
sz += MX_PAGE_SIZE;
}
if (!sz) {
return (void *)heap_end;
}
if (!heap_start) {
__crt_heap_init(sz);
return (void *)heap_start;
}
mx_vmo_set_size(heap_vmo, heap_sz + sz);
mx_vaddr_t vmar_base, alloc_base;
mx_vmar_bounds(heap_vmar, &vmar_base, NULL);
size_t offset = heap_end - vmar_base;
mx_status_t err = mx_vmar_map(heap_vmar,
MX_VM_PERM_READ | MX_VM_PERM_WRITE | MX_VM_SPECIFIC,
offset, heap_vmo, heap_sz, sz, &alloc_base);
if (err != MX_OK) {
fprintf(stderr, "fatal: cannot map extended heap (%s)\n", mx_status_to_string(err));
abort();
}
heap_sz += sz;
void *out = (void *)heap_end;
memset(out, 0x0, sz);
heap_end += sz;
return out;
}

378
libc/sys/horizon/init.c Normal file
View File

@@ -0,0 +1,378 @@
#include <magenta/task.h>
#include <magenta/tunnel.h>
#include <magenta/bootstrap.h>
#include <magenta/signals.h>
#include <magenta/errors.h>
#include <magenta/handle.h>
#include <magenta/misc.h>
#include <magenta/object.h>
#include <mio/object.h>
#include <mio/fd.h>
#include <mio/fs.h>
#include <mio/namespace.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "__init.h"
#include "__heap.h"
#include "__fio.h"
/* maximum of 32 handles can be received sent as arguments */
#define MAX_HANDLE_ARGS 32
/* maximum size of bootstrap message that can be received */
#define MAX_MSG_SIZE 0x2000
#if 1
#define dbg_log(...)
#else
static void dbg_log(const char *format, ...)
{
char buf[1024];
va_list arg;
va_start(arg, format);
int r = vsnprintf(buf, sizeof buf, format, arg);
va_end(arg);
mx_console_write(buf, r);
}
#endif
#ifdef DYLD_PARENT_IMAGE
extern mx_vaddr_t dyld_load_exec(int argc, const char **argv);
#endif
static const char **environ = NULL;
static char arg_msg_buf[MAX_MSG_SIZE];
static mx_bootstrap_handle_t arg_handles[MAX_HANDLE_ARGS];
const char **__crt_environ()
{
return environ;
}
extern int main(int, const char **);
extern void __crt_run_atexit();
static void extract_arg_handles(mx_bootstrap_msg_t *args,
mx_handle_t *handles, int hndc, mx_bootstrap_handle_t *out)
{
uint32_t *hent = (uint32_t *)((char *)args + args->handle_info_off);
for (int i = 0; i < hndc; i++) {
out[i].info = hent[i];
out[i].handle = handles[i];
}
}
static void parse_args(mx_bootstrap_msg_t *args,
const char **argv, const char **envp, const char **namep)
{
if (args->args_num > 0) {
char *arg_buf = (char *)args + args->args_off;
int arg_i = 0;
int arg_off = 0;
for (int i = 0; ; i++) {
if (arg_buf[i] == '\0') {
argv[arg_i++] = arg_buf + arg_off;
arg_off = i + 1;
}
if (arg_i == (int)args->args_num) {
break;
}
}
}
if (args->environ_num > 0) {
char *env_buf = (char *)args + args->environ_off;
int env_i = 0;
int env_off = 0;
for (int i = 0; ; i++) {
if (env_buf[i] == '\0') {
envp[env_i++] = env_buf + env_off;
env_off = i + 1;
}
if (env_i == (int)args->environ_num) {
break;
}
}
}
if (args->names_num) {
char *name_buf = (char *)args + args->names_off;
int name_i = 0;
int name_off = 0;
for (int i = 0; ; i++) {
if (name_buf[i] == '\0') {
namep[name_i++] = name_buf + name_off;
name_off = i + 1;
}
if (name_i == (int)args->names_num) {
break;
}
}
}
}
static void hang()
{
while (1) {
mx_nanosleep(mx_deadline_after(MX_SEC(1)));
}
}
static void init_stdio_fd(int fd, mx_handle_t *handles, size_t nhandles)
{
if (handles[0] == MX_NULL_HANDLE) {
dbg_log("** photon: FD %d is closed\n", fd);
return;
}
mx_info_basic_t handle0_info;
mx_status_t err = mx_object_get_info(handles[0], MX_INFO_HANDLE_BASIC, &handle0_info, sizeof(handle0_info));
if (err != MX_OK) {
/* bad handle. TODO report error somehow */
return;
}
mio_object *obj = NULL;
if (handle0_info.type == MX_OBJECT_PIPE) {
obj = mio_pipe_create(handles[0]);
dbg_log("** photon: FD %d is a pipe\n", fd);
} else {
/* just assume all other stdio handles implement the file protocol over a tunnel */
obj = mio_file_create(handles[0]);
dbg_log("** photon: FD %d is a file\n", fd);
}
mio_fd_list_alloc_at(mio_global_fd_list(), obj, fd);
}
static void init_stdio(mx_bootstrap_handle_t *handles, size_t nhandles)
{
dbg_log("** photon: initialising stdio\n");
bool no_fds = true;
int max_fd = 0;
for (size_t i = 0; i < nhandles; i++) {
uint32_t info = handles[i].info;
if (MX_B_HND_TYPE(info) != MX_B_FD) {
continue;
}
no_fds = false;
int fd = MX_B_HND_ARG(info);
if (fd > max_fd) {
max_fd = fd;
}
}
if (no_fds) {
dbg_log("** photon: we've been given no FDs\n");
return;
}
int nfds = max_fd + 1;
dbg_log("** photon: we've been given up to %d FDs\n", nfds);
/* Supports up to two handles per FD */
mx_handle_t fd_handles[nfds][2];
memset(fd_handles, 0x0, sizeof(mx_handle_t) * 2 * nfds);
for (size_t i = 0; i < nhandles; i++) {
uint32_t info = handles[i].info;
if (MX_B_HND_TYPE(info) != MX_B_FD) {
continue;
}
int fd = MX_B_HND_ARG(info);
mx_handle_t *this_fd_handles = fd_handles[fd];
if (this_fd_handles[0] != MX_NULL_HANDLE) {
this_fd_handles[1] = handles[i].handle;
} else {
this_fd_handles[0] = handles[i].handle;
}
}
for (int i = 0; i < nfds; i++) {
size_t n = 1;
if (fd_handles[i][1] != MX_NULL_HANDLE) {
n++;
}
//dbg_log("** photon: handles for FD %d = { %x, %x }\n", i, fd_handles[i][0], fd_handles[i][1]);
init_stdio_fd(i, fd_handles[i], n);
}
__fio_init(0, 1, 2);
dbg_log("** photon: stdio init finished\n");
}
static int do_init(mx_handle_t bootstrap, bool enable_fs, bool enable_stdio, int *out_argc, const char ***out_argv)
{
dbg_log("reading bootstrap message from %x\n", bootstrap);
mx_signals_t sig = 0;
mx_object_wait(bootstrap, MX_TUNNEL_READABLE, 0, &sig);
if (!(sig & MX_TUNNEL_READABLE)) {
dbg_log("no bootstrap message!\n");
return -1;
}
size_t msg_size = 0;
size_t nr_handles = 0;
mx_handle_t handles[MAX_HANDLE_ARGS + 1];
dbg_log("receiving message from handle %lx\n", bootstrap);
mx_status_t err = mx_tunnel_read(bootstrap,
arg_msg_buf, MAX_MSG_SIZE,
handles, MAX_HANDLE_ARGS,
&msg_size, &nr_handles);
if (err != MX_OK) {
dbg_log("error: cannot read bootstrap message from handle %lx (error %d)\n",
bootstrap, err);
return -1;
}
mx_bootstrap_msg_t *msg = (mx_bootstrap_msg_t *)arg_msg_buf;
dbg_log("extracting handles\n");
extract_arg_handles(msg, handles, nr_handles, arg_handles);
#if 0
arg_handles[nr_handles].handle = bootstrap;
arg_handles[nr_handles].info = MX_B_HND(MX_B_TUNNEL_BTSTP, 0);
nr_handles++;
#endif
dbg_log("extracted %zu handles\n", nr_handles);
mx_bootstrap_handle_init(arg_handles, nr_handles);
const char **argv = NULL, **envp = NULL, **namep = NULL;
dbg_log("allocating buffers (%u, %u, %u)\n", msg->args_num, msg->environ_num, msg->names_num);
argv = calloc(sizeof *argv, msg->args_num + 1);
envp = calloc(sizeof *envp, msg->environ_num + 1);
namep = calloc(sizeof *namep, msg->names_num + 1);
environ = envp;
parse_args(msg, argv, envp, namep);
*out_argc = msg->args_num;
*out_argv = argv;
if (enable_stdio) {
init_stdio(arg_handles, nr_handles);
} else {
__fio_init(-1, -1, -1);
}
if (!enable_fs) {
return 0;
}
mio_namespace *ns = mio_namespace_create();
dbg_log("received %u names/%zu handles\n", msg->names_num, nr_handles);
if (msg->names_num > 0) {
for (size_t i = 0; i < nr_handles; i++) {
int type = MX_B_HND_TYPE(arg_handles[i].info);
int arg = MX_B_HND_ARG(arg_handles[i].info);
if (type != MX_B_NS_DIR && type != MX_B_TUNNEL_CWD) {
dbg_log(" * wrong type %x\n", type);
continue;
}
const char *path = namep[arg];
dbg_log(" * %s = %x\n", path, arg_handles[i].handle);
if (type == MX_B_TUNNEL_CWD) {
mio_set_cwd(arg_handles[i].handle, path);
} else {
mio_namespace_add_entry(ns, path, arg_handles[i].handle);
}
}
}
mio_set_global_namespace(ns);
return 0;
}
static int do_run(mx_handle_t bootstrap)
{
int argc;
const char **argv;
int err = do_init(bootstrap, true, true, &argc, &argv);
if (err != 0) {
return err;
}
return main(argc, argv);
}
#ifdef DYLD_PARENT_IMAGE
static int do_load_and_run(mx_handle_t bootstrap)
{
int argc;
const char **argv;
int err = do_init(bootstrap, false, true, &argc, &argv);
if (err != 0) {
return err;
}
mx_vaddr_t main_ptr = dyld_load_exec(argc, argv);
if (!main_ptr) {
return -1;
}
mx_bootstrap_handle_cleanup();
err = do_init(bootstrap, true, true, &argc, &argv);
if (err != 0) {
return err;
}
int(*main_func)(int, const char **) = (int(*)(int, const char **))main_ptr;
if (!main_func) {
return -1;
}
return main_func(argc, argv);
}
#endif
int __crt_init(mx_handle_t bootstrap, mx_vaddr_t arg2)
{
#ifndef DYLD_PARENT_IMAGE
int ret = do_run(bootstrap);
#else
int ret = do_load_and_run(bootstrap);
#endif
fflush(stdout);
fflush(stderr);
__crt_run_atexit();
mio_fd_cleanup();
mio_fs_cleanup();
mx_task_kill(mx_bootstrap_handle_get(MX_B_TASK_SELF), ret);
/* unreachable */
hang();
return 0;
}

1225
libc/sys/horizon/launch.c Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,18 @@
.global _start
.type _start, @function
.extern __crt_init
.type __crt_init, @function
.extern main
.type main, @function
_start:
# Magenta aligns the stack to a page boundry and subtracts 8.
# Add 8 to restore 16-byte alignment
add $8, %rsp
call __crt_init
# unreachable; __crt_init() will call mx_task_kill()
.loop:
jmp .loop

View File

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

View File

@@ -0,0 +1,29 @@
#ifndef SYS_HORIZON_SYS__DIRENT_H_
#define SYS_HORIZON_SYS__DIRENT_H_
#include <sys/types.h>
#include <limits.h>
#define __SYS_DENT_CACHE_SZ 4
struct __dentcache {
ino_t d_ino;
unsigned char d_type;
char *d_namep;
};
struct dirent {
ino_t d_ino;
unsigned char d_type;
char d_name[NAME_MAX + 1];
};
typedef struct {
int fd;
long seek;
unsigned char cache_idx, cache_size;
struct __dentcache dent_cache[__SYS_DENT_CACHE_SZ];
struct dirent cdent;
} DIR;
#endif

View File

@@ -0,0 +1,136 @@
#ifndef SYS_HORIZON_SYS__ERRNO_H_
#define SYS_HORIZON_SYS__ERRNO_H_
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* Input/output error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file descriptor */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Resource temporarily unavailable */
#define ENOMEM 12 /* Cannot allocate memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Invalid cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* Too many open files in system */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Inappropriate ioctl for device */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Numerical argument out of domain */
#define ERANGE 34 /* Numerical result out of range */
#define EDEADLK 35 /* Resource deadlock avoided */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many levels of symbolic links */
#define ENOMSG 41 /* No message of desired type */
#define EIDRM 42 /* Identifier removed */
#define ECHRNG 43 /* Channel number out of range */
#define EL2NSYNC 44 /* Level 2 not synchronized */
#define EL3HLT 45 /* Level 3 halted */
#define EL3RST 46 /* Level 3 reset */
#define ELNRNG 47 /* Link number out of range */
#define EUNATCH 48 /* Protocol driver not attached */
#define ENOCSI 49 /* No CSI structure available */
#define EL2HLT 50 /* Level 2 halted */
#define EBADE 51 /* Invalid exchange */
#define EBADR 52 /* Invalid request descriptor */
#define EXFULL 53 /* Exchange full */
#define ENOANO 54 /* No anode */
#define EBADRQC 55 /* Invalid request code */
#define EBADSLT 56 /* Invalid slot */
#define EBFONT 57 /* Bad font file format */
#define ENOSTR 58 /* Device not a stream */
#define ENODATA 59 /* No data available */
#define ETIME 60 /* Timer expired */
#define ENOSR 61 /* Out of streams resources */
#define ENONET 62 /* Machine is not on the network */
#define ENOPKG 63 /* Package not installed */
#define EREMOTE 64 /* Object is remote */
#define ENOLINK 65 /* Link has been severed */
#define EADV 66 /* Advertise error */
#define ESRMNT 67 /* Srmount error */
#define ECOMM 68 /* Communication error on send */
#define EPROTO 69 /* Protocol error */
#define EMULTIHOP 70 /* Multihop attempted */
#define EDOTDOT 71 /* RFS specific error */
#define EBADMSG 72 /* Bad message */
#define EOVERFLOW 73 /* Value too large for defined data type */
#define ENOTUNIQ 74 /* Name not unique on network */
#define EBADFD 75 /* File descriptor in bad state */
#define EREMCHG 76 /* Remote address changed */
#define ELIBACC 77 /* Can not access a needed shared library */
#define ELIBBAD 78 /* Accessing a corrupted shared library */
#define ELIBSCN 79 /* .lib section in a.out corrupted */
#define ELIBMAX 80 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 81 /* Cannot exec a shared library directly */
#define EILSEQ 82 /* Invalid or incomplete multibyte or wide character */
#define ERESTART 83 /* Interrupted system call should be restarted */
#define ESTRPIPE 84 /* Streams pipe error */
#define EUSERS 85 /* Too many users */
#define ENOTSOCK 86 /* Socket operation on non-socket */
#define EDESTADDRREQ 87 /* Destination address required */
#define EMSGSIZE 88 /* Message too long */
#define EPROTOTYPE 89 /* Protocol wrong type for socket */
#define ENOPROTOOPT 90 /* Protocol not available */
#define EPROTONOSUPPORT 91 /* Protocol not supported */
#define ESOCKTNOSUPPORT 92 /* Socket type not supported */
#define ENOTSUP 93 /* Operation not supported */
#define EPFNOSUPPORT 94 /* Protocol family not supported */
#define EAFNOSUPPORT 95 /* Address family not supported by protocol */
#define EADDRINUSE 96 /* Address already in use */
#define EADDRNOTAVAIL 97 /* Cannot assign requested address */
#define ENETDOWN 98 /* Network is down */
#define ENETUNREACH 99 /* Network is unreachable */
#define ENETRESET 100 /* Network dropped connection on reset */
#define ECONNABORTED 101 /* Software caused connection abort */
#define ECONNRESET 102 /* Connection reset by peer */
#define ENOBUFS 103 /* No buffer space available */
#define EISCONN 104 /* Transport endpoint is already connected */
#define ENOTCONN 105 /* Transport endpoint is not connected */
#define ESHUTDOWN 106 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 107 /* Too many references: cannot splice */
#define ETIMEDOUT 108 /* Connection timed out */
#define ECONNREFUSED 109 /* Connection refused */
#define EHOSTDOWN 110 /* Host is down */
#define EHOSTUNREACH 111 /* No route to host */
#define EALREADY 112 /* Operation already in progress */
#define EINPROGRESS 113 /* Operation now in progress */
#define ESTALE 114 /* Stale file handle */
#define EUCLEAN 115 /* Structure needs cleaning */
#define ENOTNAM 116 /* Not a XENIX named type file */
#define ENAVAIL 117 /* No XENIX semaphores available */
#define EISNAM 118 /* Is a named type file */
#define EREMOTEIO 119 /* Remote I/O error */
#define EDQUOT 120 /* Disk quota exceeded */
#define ENOMEDIUM 121 /* No medium found */
#define EMEDIUMTYPE 122 /* Wrong medium type */
#define ECANCELED 123 /* Operation canceled */
#define ENOKEY 124 /* Required key not available */
#define EKEYEXPIRED 125 /* Key has expired */
#define EKEYREVOKED 126 /* Key has been revoked */
#define EKEYREJECTED 127 /* Key was rejected by service */
#define EOWNERDEAD 128 /* Owner died */
#define ENOTRECOVERABLE 129 /* State not recoverable */
#define ERFKILL 130 /* Operation not possible due to RF-kill */
#define EHWPOISON 131 /* Memory page has hardware error */
#endif

View File

@@ -0,0 +1,12 @@
#ifndef SYS_HORIZON_SYS__FCONST_H_
#define SYS_HORIZON_SYS__FCONST_H_
/* Must use the value of horizon.io.NAME_MAX */
#define __FILENAME_MAX 255
/* Must use the values from horizon.io.Whence */
#define __SEEK_SET 0
#define __SEEK_CUR 1
#define __SEEK_END 2
#endif

View File

@@ -0,0 +1,20 @@
#ifndef SYS_HORIZON___TIME_H_
#define SYS_HORIZON___TIME_H_
#include <sys/types.h>
#include <magenta/clock.h>
#define __SYS_CLOCKS_PER_SEC 1000000000
#define __SYS_CLOCK_REALTIME MX_CLOCK_REALTIME
#define __SYS_CLOCK_MONOTONIC MX_CLOCK_MONOTONIC
struct timespec;
extern clock_t __sys_clock(void);
extern time_t __sys_time(void);
extern int __sys_clock_getres(clockid_t clk_id, struct timespec *res);
extern int __sys_clock_gettime(clockid_t clk_id, struct timespec *tp);
extern int __sys_clock_settime(clockid_t clk_id, const struct timespec *tp);
#endif

View File

@@ -0,0 +1,51 @@
#ifndef SYS_HORIZON_SYS_LAUNCH_H_
#define SYS_HORIZON_SYS_LAUNCH_H_
#include <magenta/bootstrap.h>
#define FD_NONE -1
#define FD_INHERIT -2
#define LAUNCH_MAX_FDS 3
#define NS_ENTRY_FD(p, f) { .path = (p), .src = NULL, .fd = (f), .handle = MX_NULL_HANDLE }
#define NS_ENTRY_HANDLE(p, h) { .path = (p), .src = NULL, .fd = -1, .handle = (h) }
#define NS_ENTRY_PATH(p, s) { .path = (p), .src = (s), .fd = -1, .handle = MX_NULL_HANDLE }
enum launch_flags {
/* don't inherit parent task's namespace. */
LAUNCH_SET_NS = 0x01u,
/* use launch_info.fd as the new task's stdio file descriptors */
LAUNCH_SET_FD = 0x02u,
};
struct namespace_entry {
const char *path, *src;
/* if this is not -1, handle must be MX_NULL_HANDLE */
int fd;
/* if this is not MX_NULL_HANDLE, fd must be -1 */
mx_handle_t handle;
};
struct launch_info {
enum launch_flags flags;
const char *path;
int argc;
const char **argv;
int fd[LAUNCH_MAX_FDS];
struct namespace_entry cwd;
const struct namespace_entry *ns;
size_t ns_count;
const mx_bootstrap_handle_t *handles;
size_t handle_count;
};
extern int launch(const struct launch_info *info, mx_handle_t *out_task);
extern const char *launch_error(void);
#endif

View File

@@ -0,0 +1,16 @@
#ifndef SYS_HORIZON_TIME_H_
#define SYS_HORIZON_TIME_H_
#include <time.h>
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
#endif

View File

@@ -0,0 +1,27 @@
#ifndef SYS_LINUX_SYS_TYPES_H_
#define SYS_LINUX_SYS_TYPES_H_
#include <machine/_stdint.h>
#include <mio/types.h>
typedef signed long long blkcnt_t;
typedef signed long long blksize_t;
typedef unsigned long long clock_t;
typedef unsigned int clockid_t;
typedef unsigned long long fsblkcnt_t;
typedef unsigned long long fsfilcnt_t;
typedef unsigned int gid_t;
typedef unsigned int id_t;
typedef unsigned int key_t;
typedef unsigned int mode_t;
typedef unsigned long long nlink_t;
typedef __int64_t off64_t;
typedef signed int pid_t;
typedef unsigned long long time_t;
typedef unsigned int timer_t;
typedef unsigned int uid_t;
typedef unsigned long useconds_t;
typedef long suseconds_t;
typedef unsigned long long dev_t;
#endif

View File

@@ -0,0 +1,5 @@
_Noreturn void __exit(int code)
{
/* TODO Exit syscall */
while (1) {}
}

78
libc/sys/horizon/time.c Normal file
View File

@@ -0,0 +1,78 @@
#include <magenta/types.h>
#include <magenta/misc.h>
#include <magenta/errors.h>
#include <magenta/clock.h>
#include <time.h>
#include <errno.h>
clock_t __sys_clock(void)
{
mx_time_val_t v;
mx_clock_get_time(MX_CLOCK_MONOTONIC, &v);
return (v.sec * CLOCKS_PER_SEC) + v.nsec;
}
time_t __sys_time(void)
{
mx_time_val_t v;
mx_clock_get_time(MX_CLOCK_REALTIME, &v);
return v.sec;
}
int nanosleep(const struct timespec *req, struct timespec *rem)
{
if (!req) {
__set_errno(EFAULT);
return -1;
}
mx_nanosleep(mx_deadline_after(MX_SEC(req->tv_sec) + MX_NSEC(req->tv_nsec)));
return 0;
}
int __sys_clock_getres(clockid_t clk_id, struct timespec *res)
{
mx_time_val_t v;
mx_status_t s = mx_clock_get_resolution(clk_id, &v);
if (s != MX_OK) {
/* TODO set errno */
return -1;
}
res->tv_sec = v.sec;
res->tv_nsec = v.nsec;
return 0;
}
int __sys_clock_gettime(clockid_t clk_id, struct timespec *tp)
{
mx_time_val_t v;
mx_status_t s = mx_clock_get_time(clk_id, &v);
if (s != MX_OK) {
/* TODO set errno */
return -1;
}
tp->tv_sec = v.sec;
tp->tv_nsec = v.nsec;
return 0;
}
int __sys_clock_settime(clockid_t clk_id, const struct timespec *tp)
{
mx_time_val_t v = { .sec = tp->tv_sec, .nsec = tp->tv_nsec };
mx_status_t s = mx_clock_set_time(clk_id, &v);
if (s != MX_OK) {
/* TODO set errno */
return -1;
}
return 0;
}

86
libc/sys/horizon/unistd.c Normal file
View File

@@ -0,0 +1,86 @@
#include <magenta/object.h>
#include <magenta/bootstrap.h>
#include <magenta/errors.h>
#include <unistd.h>
#include <errno.h>
#include <mio/fs.h>
int open(const char *pathname, int flags, ...)
{
int ret = mio_open(pathname, flags);
if (ret < 0) {
__set_errno(-ret);
return -1;
}
__set_errno(0);
return ret;
}
int openat(int dirfd, const char *pathname, int flags, ...)
{
int ret = mio_openat(dirfd, pathname, flags);
if (ret < 0) {
__set_errno(-ret);
return -1;
}
__set_errno(0);
return ret;
}
ssize_t read(int fd, void *buf, size_t count)
{
ssize_t ret = mio_read(fd, buf, count);
if (ret < 0) {
__set_errno(-(int)ret);
return -1;
}
__set_errno(0);
return ret;
}
ssize_t write(int fd, const void *buf, size_t count)
{
ssize_t ret = mio_write(fd, buf, count);
if (ret < 0) {
__set_errno(-(int)ret);
return -1;
}
__set_errno(0);
return ret;
}
int close(int fd)
{
int ret = mio_close(fd);
if (ret < 0) {
__set_errno(-ret);
return -1;
}
__set_errno(0);
return ret;
}
pid_t getpid(void)
{
mx_info_task_t task_info;
mx_status_t status = mx_object_get_info(
mx_bootstrap_handle_get(MX_B_TASK_SELF),
MX_INFO_TASK,
&task_info, sizeof task_info);
return status == MX_OK ? task_info.leader_id : (pid_t)-1;
}
pid_t gettid(void)
{
mx_info_task_t task_info;
mx_status_t status = mx_object_get_info(
mx_bootstrap_handle_get(MX_B_TASK_SELF),
MX_INFO_TASK,
&task_info, sizeof task_info);
return status == MX_OK ? task_info.id : (pid_t)-1;
}

24
libc/sys/horizon/unistd.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef SYS_LINUX_UNISTD_H_
#define SYS_LINUX_UNISTD_H_
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <mio/types.h>
struct stat;
struct pollfd;
extern int open(const char *pathname, int flags, ...);
extern int openat(int dirfd, const char *pathname, int flags, ...);
extern ssize_t read(int fd, void *buf, size_t count);
extern ssize_t write(int fd, const void *buf, size_t count);
extern int close(int fd);
extern off_t lseek(int fd, off_t off, int whence);
extern pid_t getpid(void);
extern pid_t gettid(void);
#endif

33
libc/sys/linux/__fio.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef SYS_LINUX___FIO_H_
#define SYS_LINUX___FIO_H_
#define __FIO_BUFSZ 512
#if defined(__cplusplus)
extern "C" {
#endif
struct __io_file {
char buf[__FIO_BUFSZ];
unsigned int buf_idx;
unsigned int fd;
char err;
};
extern int __fileno(struct __io_file *f);
extern void __fio_init();
extern unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz);
extern unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz);
extern unsigned int __fio_flush(struct __io_file *f);
extern int __fio_error(struct __io_file *f);
extern int __fio_ungetc(struct __io_file *f, char c);
extern int __fio_fopen(const char *path, const char *mode, struct __io_file *out);
extern int __fio_fclose(struct __io_file *in);
extern int __fio_fdopen(int fd, const char *mode, struct __io_file *out);
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -0,0 +1,17 @@
#ifndef SYS_LINUX___SYSCALL_H_
#define SYS_LINUX___SYSCALL_H_
#include <stdint.h>
extern intptr_t __syscall0(uintptr_t id);
extern intptr_t __syscall1(uintptr_t id, uintptr_t p0);
extern intptr_t __syscall2(uintptr_t id, uintptr_t p0, uintptr_t p1);
extern intptr_t __syscall3(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2);
extern intptr_t __syscall4(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2,
uintptr_t p3);
extern intptr_t __syscall5(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2,
uintptr_t p3, uintptr_t p4);
extern intptr_t __syscall6(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2,
uintptr_t p3, uintptr_t p4, uintptr_t p5);
#endif

14
libc/sys/linux/__system.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef SYS_LINUX___SYSTEM_H_
#define SYS_LINUX___SYSTEM_H_
#if defined(__cplusplus)
extern "C" {
#endif
extern _Noreturn void __exit(int code);
#if defined(__cplusplus)
}
#endif
#endif

View File

56
libc/sys/linux/fcntl.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef SYS_LINUX_FCNTL_H_
#define SYS_LINUX_FCNTL_H_
#include <sys/types.h>
struct flock
{
short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
short int l_whence; /* Where `l_start' is relative to (like `lseek'). */
off_t l_start; /* Offset where the lock begins. */
off_t l_len; /* Size of the locked area; zero means until EOF. */
pid_t l_pid; /* Process holding the lock. */
};
struct flock64
{
short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
short int l_whence; /* Where `l_start' is relative to (like `lseek'). */
off64_t l_start; /* Offset where the lock begins. */
off64_t l_len; /* Size of the locked area; zero means until EOF. */
pid_t l_pid; /* Process holding the lock. */
};
#define O_ACCMODE 0003
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_CREAT 0100 /* Not fcntl. */
#define O_EXCL 0200 /* Not fcntl. */
#define O_NOCTTY 0400 /* Not fcntl. */
#define O_TRUNC 01000 /* Not fcntl. */
#define O_APPEND 02000
#define O_NONBLOCK 04000
#define O_NDELAY O_NONBLOCK
#define O_SYNC 04010000
#define O_FSYNC O_SYNC
#define O_ASYNC 020000
#define O_LARGEFILE 0100000
#define O_DIRECTORY 0200000
#define O_NOFOLLOW 0400000
#define O_CLOEXEC 02000000
#define O_DIRECT 040000
#define O_NOATIME 01000000
#define O_PATH 010000000
#define O_DSYNC 010000
#define O_TMPFILE (020000000 | __O_DIRECTORY)
#define F_GETLK 5 /* Get record locking info. */
#define F_SETLK 6 /* Set record locking info (non-blocking). */
#define F_SETLKW 7 /* Set record locking info (blocking). */
#define F_GETLK64 12 /* Get record locking info. */
#define F_SETLK64 13 /* Set record locking info (non-blocking). */
#define F_SETLKW64 14 /* Set record locking info (blocking). */
#endif

49
libc/sys/linux/fio.c Normal file
View File

@@ -0,0 +1,49 @@
#include "__fio.h"
#include "__syscall.h"
#include "unistd.h"
struct __io_file __stdin = { .fd = 0 };
struct __io_file __stdout = { .fd = 1 };
struct __io_file __stderr = { .fd = 2 };
struct __io_file *stdin = &__stdin;
struct __io_file *stdout = &__stdout;
struct __io_file *stderr = &__stderr;
int __fileno(struct __io_file *f)
{
return f->fd;
}
unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz)
{
for (unsigned int i = 0; i < sz; i++) {
if (f->buf_idx >= __FIO_BUFSZ) {
__fio_flush(f);
}
f->buf[f->buf_idx++] = buf[i];
if (buf[i] == '\n') {
__fio_flush(f);
}
}
return sz;
}
unsigned int __fio_flush(struct __io_file *f)
{
ssize_t res = write(f->fd, f->buf, f->buf_idx);
if (res != f->buf_idx) {
f->err = 1;
}
size_t flushed = f->buf_idx;
f->buf_idx = 0;
return flushed;
}
int __fio_error(struct __io_file *f)
{
return f->err != 0;
}

View File

@@ -0,0 +1,20 @@
.global _start
.type _start, @function
.extern __fio_init
.type __fio_init, @function
.extern main
.type main, @function
_start:
xor %ebp, %ebp
mov (%rsp), %edi
lea 8(%rsp), %rsi
lea 16(%rsp, %rdi, 8), %rdx
xor %eax, %eax
call main
movq %rax, %rdi
movq $60, %rax
syscall

View File

@@ -0,0 +1,108 @@
#include <stdint.h>
intptr_t __syscall0(uintptr_t id)
{
intptr_t ret = 0;
asm volatile("mov %1, %%rax; syscall; mov %%rax, %0"
: "=m" (ret)
: "m" (id));
return ret;
}
intptr_t __syscall1(uintptr_t id, uintptr_t p0)
{
intptr_t ret = 0;
asm volatile(
"mov %1, %%rax;"
"mov %2, %%rdi;"
"syscall;"
"mov %%rax, %0"
: "=m" (ret)
: "m" (id), "m" (p0));
return ret;
}
intptr_t __syscall2(uintptr_t id, uintptr_t p0, uintptr_t p1)
{
intptr_t ret = 0;
asm volatile(
"mov %1, %%rax;"
"mov %2, %%rdi;"
"mov %3, %%rsi;"
"syscall;"
"mov %%rax, %0"
: "=m" (ret)
: "m" (id), "m" (p0), "m" (p1));
return ret;
}
intptr_t __syscall3(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2)
{
intptr_t ret = 0;
asm volatile(
"movq %1, %%rax;"
"mov %2, %%rdi;"
"mov %3, %%rsi;"
"mov %4, %%rdx;"
"syscall;"
"mov %%rax, %0"
: "=m" (ret)
: "m" (id), "m" (p0), "m" (p1), "m" (p2));
return ret;
}
intptr_t __syscall4(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2,
uintptr_t p3)
{
intptr_t ret = 0;
asm volatile(
"mov %1, %%rax;"
"mov %2, %%rdi;"
"mov %3, %%rsi;"
"mov %4, %%rdx;"
"mov %5, %%r10;"
"syscall;"
"mov %%rax, %0"
: "=m" (ret)
: "m" (id), "m" (p0), "m" (p1), "m" (p2), "m" (p3));
return ret;
}
intptr_t __syscall5(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2,
uintptr_t p3, uintptr_t p4)
{
intptr_t ret = 0;
asm volatile(
"mov %1, %%rax;"
"mov %2, %%rdi;"
"mov %3, %%rsi;"
"mov %4, %%rdx;"
"mov %5, %%r10;"
"mov %6, %%r8;"
"syscall;"
"mov %%rax, %0"
: "=m" (ret)
: "m" (id), "m" (p0), "m" (p1), "m" (p2), "m" (p3), "m" (p4));
return ret;
}
intptr_t __syscall6(uintptr_t id, uintptr_t p0, uintptr_t p1, uintptr_t p2,
uintptr_t p3, uintptr_t p4, uintptr_t p5)
{
intptr_t ret = 0;
asm volatile(
"mov %1, %%rax;"
"mov %2, %%rdi;"
"mov %3, %%rsi;"
"mov %4, %%rdx;"
"mov %5, %%r10;"
"mov %6, %%r8;"
"mov %7, %%r9;"
"syscall;"
"mov %%rax, %0"
: "=m" (ret)
: "m" (id), "m" (p0), "m" (p1), "m" (p2), "m" (p3), "m" (p4),
"m" (p5));
return ret;
}

33
libc/sys/linux/poll.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef SYS_LINUX_POLL_H_
#define SYS_LINUX_POLL_H_
#define POLLIN 0x1
#define POLLPRI 0x2
#define POLLOUT 0x4
#define POLLERR 0x8
#define POLLHUP 0x10
#define POLLNVAL 0x20
#define POLLRDNORM 0x40
#define POLLRDBAND 0x80
#define POLLWRNORM 0x100
#define POLLWRBAND 0x200
#if defined(__cplusplus)
extern "C" {
#endif
typedef unsigned long long nfds_t;
struct pollfd {
int fd;
short events;
short revents;
};
extern int poll(struct pollfd *fds, nfds_t nfds, int timeout);
#if defined(__cplusplus)
}
#endif
#endif

22
libc/sys/linux/sbrk.c Normal file
View File

@@ -0,0 +1,22 @@
#include "unistd.h"
#include <stddef.h>
#include <stdint.h>
void *__curr_brk = NULL;
void *sbrk(intptr_t increment)
{
if (!__curr_brk) {
brk(NULL);
}
uintptr_t end = (uintptr_t)__curr_brk + increment;
void *start = __curr_brk;
int res = brk((void *)end);
if (res == -1) {
return NULL;
}
return start;
}

View File

@@ -0,0 +1,39 @@
#ifndef SYS_MAGENTA_SYS__ERRNO_H_
#define SYS_MAGENTA_SYS__ERRNO_H_
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#endif

View File

@@ -0,0 +1,10 @@
#ifndef SYS_LINUX_SYS__FCONST_H_
#define SYS_LINUX_SYS__FCONST_H_
#define __FILENAME_MAX 1024
#define __SEEK_SET 0
#define __SEEK_CUR 1
#define __SEEK_END 2
#endif

131
libc/sys/linux/sys/mman.h Normal file
View File

@@ -0,0 +1,131 @@
#ifndef SYS_LINUX_SYS_MMAN_H_
#define SYS_LINUX_SYS_MMAN_H_
#include <sys/types.h>
#include <stddef.h>
#define MAP_GROWSDOWN 0x00100
#define MAP_DENYWRITE 0x00800
#define MAP_EXECUTABLE 0x01000
#define MAP_LOCKED 0x02000
#define MAP_NORESERVE 0x04000
#define MAP_POPULATE 0x08000
#define MAP_NONBLOCK 0x10000
#define MAP_STACK 0x20000
#define MAP_HUGETLB 0x40000
#define MAP_SYNC 0x80000
#define MAP_FIXED_NOREPLACE 0x100000
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define PROT_NONE 0x0
#define PROT_GROWSDOWN 0x01000000
#define PROT_GROWSUP 0x02000000
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_SHARED_VALIDATE 0x03
#define MAP_TYPE 0x0f
#define MAP_FIXED 0x10
#define MAP_FILE 0
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
#define MS_ASYNC 1
#define MS_SYNC 4
#define MS_INVALIDATE 2
#define MADV_NORMAL 0
#define MADV_RANDOM 1
#define MADV_SEQUENTIAL 2
#define MADV_WILLNEED 3
#define MADV_DONTNEED 4
#define MADV_FREE 8
#define MADV_REMOVE 9
#define MADV_DONTFORK 10
#define MADV_DOFORK 11
#define MADV_MERGEABLE 12
#define MADV_UNMERGEABLE 13
#define MADV_HUGEPAGE 14
#define MADV_NOHUGEPAGE 15
#define MADV_DONTDUMP 16
#define MADV_DODUMP 17
#define MADV_WIPEONFORK 18
#define MADV_KEEPONFORK 19
#define MADV_COLD 20
#define MADV_PAGEOUT 21
#define MADV_HWPOISON 100
#define MCL_CURRENT 1
#define MCL_FUTURE 2
#define MCL_ONFAULT 4
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define PROT_NONE 0x0
#define PROT_GROWSDOWN 0x01000000
#define PROT_GROWSUP 0x02000000
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_SHARED_VALIDATE 0x03
#define MAP_TYPE 0x0f
#define MAP_FIXED 0x10
#define MAP_FILE 0
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_HUGE_SHIFT 26
#define MAP_HUGE_MASK 0x3f
#define MS_ASYNC 1
#define MS_SYNC 4
#define MS_INVALIDATE 2
#define MADV_NORMAL 0
#define MADV_RANDOM 1
#define MADV_SEQUENTIAL 2
#define MADV_WILLNEED 3
#define MADV_DONTNEED 4
#define MADV_FREE 8
#define MADV_REMOVE 9
#define MADV_DONTFORK 10
#define MADV_DOFORK 11
#define MADV_MERGEABLE 12
#define MADV_UNMERGEABLE 13
#define MADV_HUGEPAGE 14
#define MADV_NOHUGEPAGE 15
#define MADV_DONTDUMP 16
#define MADV_DODUMP 17
#define MADV_WIPEONFORK 18
#define MADV_KEEPONFORK 19
#define MADV_COLD 20
#define MADV_PAGEOUT 21
#define MADV_HWPOISON 100
#define MCL_CURRENT 1
#define MCL_FUTURE 2
#define MCL_ONFAULT 4
#define MAP_FAILED ((void *) -1)
extern void *mmap (void *addr, size_t len, int prot,
int flags, int fd, off_t offset);
extern int munmap (void *addr, size_t len);
extern int mprotect (void *addr, size_t len, int prot) ;
extern int msync (void *addr, size_t len, int flags);
extern int madvise (void *addr, size_t len, int advice) ;
extern int mlock (const void *addr, size_t len) ;
extern int munlock (const void *addr, size_t len) ;
extern int mlockall (int flags) ;
extern int munlockall (void) ;
extern int mincore (void *start, size_t len, unsigned char *vec);
#endif

View File

@@ -0,0 +1,85 @@
#ifndef SYS_LINUX_SYS_PARAM_H_
#define SYS_LINUX_SYS_PARAM_H_
#include <stddef.h>
#include <sys/types.h>
#ifndef ARG_MAX
# define __undef_ARG_MAX
#endif
#include <linux/limits.h>
#include <linux/param.h>
#ifdef __undef_ARG_MAX
#undef ARG_MAX
#undef __undef_ARG_MAX
#endif
#define MAXSYMLINKS 20
#define NOFILE 256
#define NCARGS 131072
#define NBBY CHAR_BIT
#if !defined NGROUPS && defined NGROUPS_MAX
#define NGROUPS NGROUPS_MAX
#endif
#if !defined MAXSYMLINKS && defined SYMLOOP_MAX
#define MAXSYMLINKS SYMLOOP_MAX
#endif
#if !defined CANBSIZ && defined MAX_CANON
#define CANBSIZ MAX_CANON
#endif
#if !defined MAXPATHLEN && defined PATH_MAX
#define MAXPATHLEN PATH_MAX
#endif
#if !defined NOFILE && defined OPEN_MAX
#define NOFILE OPEN_MAX
#endif
#if !defined MAXHOSTNAMELEN && defined HOST_NAME_MAX
#define MAXHOSTNAMELEN HOST_NAME_MAX
#endif
#ifndef NCARGS
#ifdef ARG_MAX
#define NCARGS ARG_MAX
#else
#define NCARGS INT_MAX
#endif
#endif
#ifndef NOGROUP
#define NOGROUP 65535 /* Marker for empty group set member. */
#endif
#ifndef NODEV
#define NODEV ((dev_t) -1) /* Non-existent device. */
#endif
#ifndef DEV_BSIZE
#define DEV_BSIZE 512
#endif
#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
#ifndef howmany
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
#endif
#ifdef __GNUC__
#define roundup(x, y) (__builtin_constant_p (y) && powerof2 (y) \
? (((x) + (y) - 1) & ~((y) - 1)) \
: ((((x) + ((y) - 1)) / (y)) * (y)))
#else
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
#endif
#define powerof2(x) ((((x) - 1) & (x)) == 0)
/* Macros for min/max. */
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif

24
libc/sys/linux/sys/stat.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef SYS_LINUX_SYS_STAT_H_
#define SYS_LINUX_SYS_STAT_H_
#include <time.h>
#include <sys/types.h>
struct stat {
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
};
#endif

View File

@@ -0,0 +1,24 @@
#ifndef SYS_LINUX_SYSCALL_H_
#define SYS_LINUX_SYSCALL_H_
#define SYS_read 0
#define SYS_write 1
#define SYS_open 2
#define SYS_close 3
#define SYS_stat 4
#define SYS_fstat 5
#define SYS_lstat 6
#define SYS_poll 7
#define SYS_lseek 8
#define SYS_mmap 9
#define SYS_mprotect 10
#define SYS_munmap 11
#define SYS_brk 12
#define SYS_rt_sigaction 13
#define SYS_rt_sigprocmask 14
#define SYS_rt_sigreturn 15
#define SYS_ioctl 16
#define SYS_mremap 25
#define SYS__exit 60
#endif

View File

@@ -0,0 +1,32 @@
#ifndef SYS_LINUX_SYS_TYPES_H_
#define SYS_LINUX_SYS_TYPES_H_
#include <machine/_stdint.h>
typedef signed long long blkcnt_t;
typedef signed long long blksize_t;
typedef unsigned long long clock_t;
typedef unsigned int clockid_t;
typedef unsigned long long fsblkcnt_t;
typedef unsigned long long fsfilcnt_t;
typedef unsigned int gid_t;
typedef unsigned int id_t;
typedef unsigned long long ino_t;
typedef unsigned int key_t;
typedef unsigned int mode_t;
typedef unsigned long long nlink_t;
typedef signed long long off_t;
typedef __int64_t off64_t;
typedef signed int pid_t;
typedef unsigned long long time_t;
typedef unsigned int timer_t;
typedef unsigned int uid_t;
typedef unsigned long useconds_t;
typedef unsigned long long dev_t;
#ifndef __SIZE_T_DEFINED
typedef __uintptr_t size_t;
#define __SIZE_T_DEFINED
#endif
#endif

164
libc/sys/linux/syscall.c Normal file
View File

@@ -0,0 +1,164 @@
#include "poll.h"
#include "sys/syscall.h"
#include "__syscall.h"
#include "unistd.h"
extern void *__curr_brk;
ssize_t read(int fd, void *buf, size_t count)
{
intptr_t res = __syscall3(SYS_read, (uintptr_t)fd, (uintptr_t)buf,
(uintptr_t)count);
if (res < 0) {
return -1;
}
return (ssize_t)res;
}
ssize_t write(int fd, const void *buf, size_t count)
{
intptr_t res = __syscall3(SYS_write, (uintptr_t)fd, (uintptr_t)buf,
(uintptr_t)count);
if (res < 0) {
return -1;
}
return (ssize_t)res;
}
int open(const char *pathname, int flags)
{
intptr_t res = __syscall3(SYS_open, (uintptr_t)pathname,
(uintptr_t)flags, 0);
if (res < 0) {
return -1;
}
return (int)res;
}
int close(int fd)
{
intptr_t res = __syscall1(SYS_close, (uintptr_t)fd);
if (res < 0) {
return -1;
}
return (int)res;
}
int stat(const char *pathname, struct stat *statbuf)
{
intptr_t res = __syscall2(SYS_stat, (uintptr_t)pathname,
(uintptr_t)statbuf);
if (res < 0) {
return -1;
}
return (int)res;
}
int fstat(int fd, struct stat *statbuf)
{
intptr_t res = __syscall2(SYS_fstat, (uintptr_t)fd,
(uintptr_t)statbuf);
if (res < 0) {
return -1;
}
return (int)res;
}
int lstat(const char *pathname, struct stat *statbuf)
{
intptr_t res = __syscall2(SYS_lstat, (uintptr_t)pathname,
(uintptr_t)statbuf);
if (res < 0) {
return -1;
}
return (int)res;
}
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
intptr_t res = __syscall3(SYS_poll, (uintptr_t)fds,
(uintptr_t)nfds, (uintptr_t)timeout);
if (res < 0) {
return -1;
}
return (int)res;
}
off_t lseek(int fd, off_t offset, int whence)
{
intptr_t res = __syscall3(SYS_lseek, (uintptr_t)fd,
(uintptr_t)offset, (uintptr_t)whence);
if (res < 0) {
return -1;
}
return (int)res;
}
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off)
{
intptr_t res = __syscall6(SYS_mmap, (uintptr_t)addr, (uintptr_t)len,
(uintptr_t)prot, (uintptr_t)flags, (uintptr_t)fd, (uintptr_t)off);
if (res < 0) {
return NULL;
}
return (void *)res;
}
int mprotect(void *addr, size_t len, int prot)
{
intptr_t res = __syscall3(SYS_mprotect, (uintptr_t)addr, (uintptr_t)len,
(uintptr_t)prot);
if (res < 0) {
return -1;
}
return (int)res;
}
int munmap(void *addr, size_t length)
{
intptr_t res = __syscall2(SYS_munmap, (uintptr_t)addr, (uintptr_t)length);
if (res < 0) {
return -1;
}
return (int)res;
}
int brk(void *addr)
{
intptr_t res = __syscall1(SYS_brk, (uintptr_t)addr);
if (res < 0) {
return -1;
}
__curr_brk = (void *)res;
return (int)res;
}
int ioctl(int fd, unsigned long req, void *arg)
{
intptr_t res = __syscall3(SYS_ioctl, (uintptr_t)fd, (uintptr_t)req,
(uintptr_t)arg);
if (res < 0) {
return -1;
}
return (int)res;
}
void _exit(int code)
{
__syscall1(SYS__exit, code);
}

7
libc/sys/linux/system.c Normal file
View File

@@ -0,0 +1,7 @@
#include "unistd.h"
_Noreturn void __exit(int code)
{
_exit(code);
while (1) {}
}

30
libc/sys/linux/unistd.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef SYS_LINUX_UNISTD_H_
#define SYS_LINUX_UNISTD_H_
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
struct stat;
struct pollfd;
typedef __intptr_t ssize_t;
extern ssize_t read(int fd, void *buf, size_t count);
extern ssize_t write(int fd, const void *buf, size_t count);
extern int open(const char *pathname, int flags);
extern int close(int fd);
extern int stat(const char *pathname, struct stat *statbuf);
extern int fstat(int fd, struct stat *statbuf);
extern int lstat(const char *pathname, struct stat *statbuf);
extern off_t lseek(int fd, off_t offset, int whence);
extern void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
extern int mprotect(void *addr, size_t len, int prot);
extern int munmap(void *addr, size_t length);
extern int brk(void *addr);
extern void *sbrk(intptr_t increment);
extern int ioctl(int fd, unsigned long request, void *arg);
extern void _exit(int code);
#endif