test
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/panic.h>
|
||||
|
||||
#define assert(expr, msg, ...) \
|
||||
({ \
|
||||
if (__unlikely(!(expr))) { \
|
||||
panic( \
|
||||
"In function \"%s\" (%s:%u):\n" \
|
||||
"Assertion \"%s\" failed!\n" msg, \
|
||||
__FUNCTION__, \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#expr, \
|
||||
##__VA_ARGS__ \
|
||||
); \
|
||||
} \
|
||||
})
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define debug_assert(...) assert(__VA_ARGS__)
|
||||
#else
|
||||
#define debug_assert(...) ((void)0)
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start(v, l) __builtin_va_start(v, l)
|
||||
#define va_end(v) __builtin_va_end(v)
|
||||
#define va_arg(v, T) __builtin_va_arg(v, T)
|
||||
#define va_copy(d, s) __builtin_va_copy(d, s)
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum memory_order {
|
||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||
memory_order_consume = __ATOMIC_CONSUME,
|
||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||
memory_order_release = __ATOMIC_RELEASE,
|
||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
||||
} memory_order;
|
||||
|
||||
#define atomic_store_explicit(ptr, des, ord) __atomic_store_n(ptr, des, ord)
|
||||
#define atomic_store(ptr, des) atomic_store_explicit(ptr, des, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_load_explicit(ptr, ord) __atomic_load_n(ptr, ord)
|
||||
#define atomic_load(ptr) atomic_load_explicit(ptr, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_exchange_explicit(ptr, des, ord) __atomic_exchange_n(ptr, des, ord)
|
||||
#define atomic_exchange(ptr, des) atomic_exchange_explicit(ptr, des, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_add_explicit(ptr, op, ord) __atomic_fetch_add(ptr, op, ord)
|
||||
#define atomic_fetch_add(ptr, op) atomic_fetch_add_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_sub_explicit(ptr, op, ord) __atomic_fetch_sub(ptr, op, ord)
|
||||
#define atomic_fetch_sub(ptr, op) atomic_fetch_sub_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_or_explicit(ptr, op, ord) __atomic_fetch_or(ptr, op, ord)
|
||||
#define atomic_fetch_or(ptr, op) atomic_fetch_or_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_xor_explicit(ptr, op, ord) __atomic_fetch_xor(ptr, op, ord)
|
||||
#define atomic_fetch_xor(ptr, op) atomic_fetch_xor_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_fetch_and_explicit(ptr, op, ord) __atomic_fetch_and(ptr, op, ord)
|
||||
#define atomic_fetch_and(ptr, op) atomic_fetch_and_explicit(ptr, op, __ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_thread_fence(ord) __atomic_thread_fence(ord)
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef signed long ssize_t;
|
||||
|
||||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
#define unreachable() __builtin_unreachable()
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
typedef __INT8_TYPE__ int8_t;
|
||||
typedef __UINT8_TYPE__ uint8_t;
|
||||
#define INT8_MAX __INT8_MAX__
|
||||
#define UINT8_MAX __UINT8_MAX__
|
||||
|
||||
typedef __INT16_TYPE__ int16_t;
|
||||
typedef __UINT16_TYPE__ uint16_t;
|
||||
#define INT16_MAX __INT16_MAX__
|
||||
#define UINT16_MAX __UINT16_MAX__
|
||||
|
||||
typedef __INT32_TYPE__ int32_t;
|
||||
typedef __UINT32_TYPE__ uint32_t;
|
||||
#define INT32_MAX __INT32_MAX__
|
||||
#define UINT32_MAX __UINT32_MAX__
|
||||
|
||||
typedef __INT64_TYPE__ int64_t;
|
||||
typedef __UINT64_TYPE__ uint64_t;
|
||||
#define INT64_MAX __INT64_MAX__
|
||||
#define UINT64_MAX __UINT64_MAX__
|
||||
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
#define INTPTR_MAX __INTPTR_MAX__
|
||||
#define UINTPTR_MAX __UINTPTR_MAX__
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
long atol(const char* str, int base);
|
||||
unsigned long atolu(const char* str, int base);
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
size_t strlen(const char* str);
|
||||
size_t strnlen(const char* str, size_t len);
|
||||
int memcmp(const void* s1, const void* s2, size_t size);
|
||||
void* memcpy(void* restrict dest, const void* restrict src, size_t n);
|
||||
void* memmove(void* dstptr, const void* srcptr, size_t size);
|
||||
void* memset(void* dest, int value, size_t n);
|
||||
char* strncpy(char* restrict dst, const char* restrict src, size_t len);
|
||||
int strcmp(const char* str1, const char* str2);
|
||||
int strncmp(const char* str1, const char* str2, size_t len);
|
||||
char* strchr(const char* c, int s);
|
||||
@@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_ARCHCTL_H
|
||||
#define __ZINNIA_UAPI_ARCHCTL_H
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define __ARCHCTL_SET_FSBASE 1
|
||||
#define __ARCHCTL_SET_GSBASE 2
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_EPOLL_H
|
||||
#define __ZINNIA_UAPI_EPOLL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define __EPOLLIN (1 << 0)
|
||||
#define __EPOLLOUT (1 << 1)
|
||||
#define __EPOLLPRI (1 << 2)
|
||||
#define __EPOLLHUP (1 << 3)
|
||||
#define __EPOLLERR (1 << 4)
|
||||
#define __EPOLLRDHUP (1 << 5)
|
||||
#define __EPOLLMSG (1 << 6)
|
||||
#define __EPOLLRDNORM (1 << 7)
|
||||
#define __EPOLLRDBAND (1 << 8)
|
||||
#define __EPOLLWRNORM (1 << 9)
|
||||
#define __EPOLLWRBAND (1 << 10)
|
||||
#define __EPOLLEXCLUSIVE (1 << 11)
|
||||
#define __EPOLLWAKEUP (1 << 12)
|
||||
#define __EPOLLONESHOT (1 << 13)
|
||||
#define __EPOLLET (1 << 14)
|
||||
|
||||
#define __EPOLL_CTL_ADD 1
|
||||
#define __EPOLL_CTL_DEL 2
|
||||
#define __EPOLL_CTL_MOD 3
|
||||
|
||||
union epoll_data {
|
||||
void* ptr;
|
||||
int fd;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
};
|
||||
|
||||
struct epoll_event {
|
||||
uint32_t events;
|
||||
union epoll_data data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,140 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_ERRNO_H
|
||||
#define __ZINNIA_UAPI_ERRNO_H
|
||||
|
||||
#define __EPERM 1
|
||||
#define __ENOENT 2
|
||||
#define __ESRCH 3
|
||||
#define __EINTR 4
|
||||
#define __EIO 5
|
||||
#define __ENXIO 6
|
||||
#define __E2BIG 7
|
||||
#define __ENOEXEC 8
|
||||
#define __EBADF 9
|
||||
#define __ECHILD 10
|
||||
#define __EAGAIN 11
|
||||
#define __ENOMEM 12
|
||||
#define __EACCES 13
|
||||
#define __EFAULT 14
|
||||
#define __ENOTBLK 15
|
||||
#define __EBUSY 16
|
||||
#define __EEXIST 17
|
||||
#define __EXDEV 18
|
||||
#define __ENODEV 19
|
||||
#define __ENOTDIR 20
|
||||
#define __EISDIR 21
|
||||
#define __EINVAL 22
|
||||
#define __ENFILE 23
|
||||
#define __EMFILE 24
|
||||
#define __ENOTTY 25
|
||||
#define __ETXTBSY 26
|
||||
#define __EFBIG 27
|
||||
#define __ENOSPC 28
|
||||
#define __ESPIPE 29
|
||||
#define __EROFS 30
|
||||
#define __EMLINK 31
|
||||
#define __EPIPE 32
|
||||
#define __EDOM 33
|
||||
#define __ERANGE 34
|
||||
#define __EDEADLK 35
|
||||
#define __ENAMETOOLONG 36
|
||||
#define __ENOLCK 37
|
||||
#define __ENOSYS 38
|
||||
#define __ENOTEMPTY 39
|
||||
#define __ELOOP 40
|
||||
#define __EWOULDBLOCK __EAGAIN
|
||||
#define __ENOMSG 42
|
||||
#define __EIDRM 43
|
||||
#define __ECHRNG 44
|
||||
#define __EL2NSYNC 45
|
||||
#define __EL3HLT 46
|
||||
#define __EL3RST 47
|
||||
#define __ELNRNG 48
|
||||
#define __EUNATCH 49
|
||||
#define __ENOCSI 50
|
||||
#define __EL2HLT 51
|
||||
#define __EBADE 52
|
||||
#define __EBADR 53
|
||||
#define __EXFULL 54
|
||||
#define __ENOANO 55
|
||||
#define __EBADRQC 56
|
||||
#define __EBADSLT 57
|
||||
#define __EDEADLOCK __EDEADLK
|
||||
#define __EBFONT 59
|
||||
#define __ENOSTR 60
|
||||
#define __ENODATA 61
|
||||
#define __ETIME 62
|
||||
#define __ENOSR 63
|
||||
#define __ENONET 64
|
||||
#define __ENOPKG 65
|
||||
#define __EREMOTE 66
|
||||
#define __ENOLINK 67
|
||||
#define __EADV 68
|
||||
#define __ESRMNT 69
|
||||
#define __ECOMM 70
|
||||
#define __EPROTO 71
|
||||
#define __EMULTIHOP 72
|
||||
#define __EDOTDOT 73
|
||||
#define __EBADMSG 74
|
||||
#define __EOVERFLOW 75
|
||||
#define __ENOTUNIQ 76
|
||||
#define __EBADFD 77
|
||||
#define __EREMCHG 78
|
||||
#define __ELIBACC 79
|
||||
#define __ELIBBAD 80
|
||||
#define __ELIBSCN 81
|
||||
#define __ELIBMAX 82
|
||||
#define __ELIBEXEC 83
|
||||
#define __EILSEQ 84
|
||||
#define __ERESTART 85
|
||||
#define __ESTRPIPE 86
|
||||
#define __EUSERS 87
|
||||
#define __ENOTSOCK 88
|
||||
#define __EDESTADDRREQ 89
|
||||
#define __EMSGSIZE 90
|
||||
#define __EPROTOTYPE 91
|
||||
#define __ENOPROTOOPT 92
|
||||
#define __EPROTONOSUPPORT 93
|
||||
#define __ESOCKTNOSUPPORT 94
|
||||
#define __EOPNOTSUPP 95
|
||||
#define __ENOTSUP __EOPNOTSUPP
|
||||
#define __EPFNOSUPPORT 96
|
||||
#define __EAFNOSUPPORT 97
|
||||
#define __EADDRINUSE 98
|
||||
#define __EADDRNOTAVAIL 99
|
||||
#define __ENETDOWN 100
|
||||
#define __ENETUNREACH 101
|
||||
#define __ENETRESET 102
|
||||
#define __ECONNABORTED 103
|
||||
#define __ECONNRESET 104
|
||||
#define __ENOBUFS 105
|
||||
#define __EISCONN 106
|
||||
#define __ENOTCONN 107
|
||||
#define __ESHUTDOWN 108
|
||||
#define __ETOOMANYREFS 109
|
||||
#define __ETIMEDOUT 110
|
||||
#define __ECONNREFUSED 111
|
||||
#define __EHOSTDOWN 112
|
||||
#define __EHOSTUNREACH 113
|
||||
#define __EALREADY 114
|
||||
#define __EINPROGRESS 115
|
||||
#define __ESTALE 116
|
||||
#define __EUCLEAN 117
|
||||
#define __ENOTNAM 118
|
||||
#define __ENAVAIL 119
|
||||
#define __EISNAM 120
|
||||
#define __EREMOTEIO 121
|
||||
#define __EDQUOT 122
|
||||
#define __ENOMEDIUM 123
|
||||
#define __EMEDIUMTYPE 124
|
||||
#define __ECANCELED 125
|
||||
#define __ENOKEY 126
|
||||
#define __EKEYEXPIRED 127
|
||||
#define __EKEYREVOKED 128
|
||||
#define __EKEYREJECTED 129
|
||||
#define __EOWNERDEAD 130
|
||||
#define __ENOTRECOVERABLE 131
|
||||
#define __ERFKILL 132
|
||||
#define __EHWPOISON 133
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_FCNTL_H
|
||||
#define __ZINNIA_UAPI_FCNTL_H
|
||||
|
||||
#define __F_OK 0
|
||||
#define __X_OK 1
|
||||
#define __W_OK 2
|
||||
#define __R_OK 4
|
||||
|
||||
#define __O_RDONLY (1 << 0)
|
||||
#define __O_WRONLY (1 << 1)
|
||||
#define __O_RDWR (__O_RDONLY | __O_WRONLY)
|
||||
#define __O_CREAT (1 << 6)
|
||||
#define __O_EXCL (1 << 7)
|
||||
#define __O_NOCTTY (1 << 8)
|
||||
#define __O_TRUNC (1 << 9)
|
||||
#define __O_APPEND (1 << 10)
|
||||
#define __O_NONBLOCK (1 << 11)
|
||||
#define __O_DSYNC (1 << 12)
|
||||
#define __O_ASYNC (1 << 13)
|
||||
#define __O_DIRECT (1 << 14)
|
||||
#define __O_LARGEFILE (1 << 15)
|
||||
#define __O_DIRECTORY (1 << 16)
|
||||
#define __O_NOFOLLOW (1 << 17)
|
||||
#define __O_NOATIME (1 << 18)
|
||||
#define __O_CLOEXEC (1 << 19)
|
||||
#define __O_PATH (1 << 21)
|
||||
#define __O_TMPFILE (1 << 22)
|
||||
#define __O_SYNC (__O_DIRECTORY | __O_TMPFILE)
|
||||
#define __O_RSYNC (__O_SYNC)
|
||||
#define __O_EXEC (__O_PATH)
|
||||
#define __O_SEARCH (__O_PATH)
|
||||
#define __O_ACCMODE (__O_RDWR | __O_PATH)
|
||||
|
||||
#define __AT_FDCWD (-100)
|
||||
|
||||
#define __AT_SYMLINK_NOFOLLOW (1 << 8)
|
||||
#define __AT_SYMLINK_FOLLOW (1 << 9)
|
||||
#define __AT_REMOVEDIR (1 << 10)
|
||||
#define __AT_EACCESS (1 << 11)
|
||||
#define __AT_EMPTY_PATH (1 << 12)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_MMAN_H
|
||||
#define __ZINNIA_UAPI_MMAN_H
|
||||
|
||||
#define __PROT_NONE 0x00
|
||||
#define __PROT_READ 0x01
|
||||
#define __PROT_WRITE 0x02
|
||||
#define __PROT_EXEC 0x04
|
||||
|
||||
#define __MAP_FAILED ((void*)-1)
|
||||
#define __MAP_FILE 0x00
|
||||
#define __MAP_SHARED 0x01
|
||||
#define __MAP_PRIVATE 0x02
|
||||
#define __MAP_FIXED 0x10
|
||||
#define __MAP_ANON 0x20
|
||||
#define __MAP_ANONYMOUS 0x20
|
||||
|
||||
#define __MS_ASYNC 0x1
|
||||
#define __MS_INVALIDATE 0x2
|
||||
#define __MS_SYNC 0x4
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_MOUNT_H
|
||||
#define __ZINNIA_UAPI_MOUNT_H
|
||||
|
||||
#define __MNT_RDONLY (1 << 0)
|
||||
#define __MNT_NOSUID (1 << 1)
|
||||
#define __MNT_NOEXEC (1 << 2)
|
||||
#define __MNT_RELATIME (1 << 3)
|
||||
#define __MNT_NOATIME (1 << 4)
|
||||
#define __MNT_REMOUNT (1 << 5)
|
||||
#define __MNT_FORCE (1 << 6)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_POLL_H
|
||||
#define __ZINNIA_UAPI_POLL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define __POLLIN 0x01
|
||||
#define __POLLOUT 0x02
|
||||
#define __POLLPRI 0x04
|
||||
#define __POLLHUP 0x08
|
||||
#define __POLLERR 0x10
|
||||
#define __POLLRDHUP 0x20
|
||||
#define __POLLNVAL 0x40
|
||||
#define __POLLRDNORM 0x80
|
||||
#define __POLLRDBAND 0x100
|
||||
#define __POLLWRNORM 0x200
|
||||
#define __POLLWRBAND 0x400
|
||||
|
||||
typedef intptr_t nfds_t;
|
||||
|
||||
struct pollfd {
|
||||
int fd;
|
||||
int16_t events;
|
||||
int16_t revents;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_STAT_H
|
||||
#define __ZINNIA_UAPI_STAT_H
|
||||
|
||||
#include <uapi/time.h>
|
||||
#include <uapi/types.h>
|
||||
|
||||
#define __S_IFMT 0x0F000
|
||||
#define __S_IFBLK 0x06000
|
||||
#define __S_IFCHR 0x02000
|
||||
#define __S_IFIFO 0x01000
|
||||
#define __S_IFREG 0x08000
|
||||
#define __S_IFDIR 0x04000
|
||||
#define __S_IFLNK 0x0A000
|
||||
#define __S_IFSOCK 0x0C000
|
||||
#define __S_IRWXU 0700
|
||||
#define __S_IRUSR 0400
|
||||
#define __S_IWUSR 0200
|
||||
#define __S_IXUSR 0100
|
||||
#define __S_IRWXG 070
|
||||
#define __S_IRGRP 040
|
||||
#define __S_IWGRP 020
|
||||
#define __S_IXGRP 010
|
||||
#define __S_IRWXO 07
|
||||
#define __S_IROTH 04
|
||||
#define __S_IWOTH 02
|
||||
#define __S_IXOTH 01
|
||||
#define __S_ISUID 04000
|
||||
#define __S_ISGID 02000
|
||||
#define __S_ISVTX 01000
|
||||
#define __S_IREAD __S_IRUSR
|
||||
#define __S_IWRITE __S_IWUSR
|
||||
#define __S_IEXEC __S_IXUSR
|
||||
|
||||
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;
|
||||
struct timespec st_atim;
|
||||
struct timespec st_mtim;
|
||||
struct timespec st_ctim;
|
||||
blksize_t st_blksize;
|
||||
blkcnt_t st_blocks;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,151 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_SYSCALL_NUMBERS_H
|
||||
#define __ZINNIA_UAPI_SYSCALL_NUMBERS_H
|
||||
|
||||
#define __SYS_exit 0
|
||||
#define __SYS_syslog 1
|
||||
#define __SYS_getuname 2
|
||||
#define __SYS_setuname 3
|
||||
#define __SYS_archctl 4
|
||||
#define __SYS_reboot 5
|
||||
#define __SYS_mmap 6
|
||||
#define __SYS_munmap 7
|
||||
#define __SYS_mprotect 8
|
||||
#define __SYS_madvise 9
|
||||
#define __SYS_sigprocmask 10
|
||||
#define __SYS_sigsuspend 11
|
||||
#define __SYS_sigpending 12
|
||||
#define __SYS_sigaction 13
|
||||
#define __SYS_sigtimedwait 14
|
||||
#define __SYS_sigaltstack 15
|
||||
#define __SYS_sigreturn 16
|
||||
#define __SYS_sigqueue 17
|
||||
#define __SYS_execve 18
|
||||
#define __SYS_fexecve 19
|
||||
#define __SYS_fork 20
|
||||
#define __SYS_kill 21
|
||||
#define __SYS_gettid 22
|
||||
#define __SYS_getpid 23
|
||||
#define __SYS_getppid 24
|
||||
#define __SYS_waitid 25
|
||||
#define __SYS_waitpid 26
|
||||
#define __SYS_pread 27
|
||||
#define __SYS_readv 28
|
||||
#define __SYS_pwrite 29
|
||||
#define __SYS_writev 30
|
||||
#define __SYS_seek 31
|
||||
#define __SYS_ioctl 32
|
||||
#define __SYS_openat 33
|
||||
#define __SYS_close 34
|
||||
#define __SYS_fstat 35
|
||||
#define __SYS_fstatat 36
|
||||
#define __SYS_statvfs 37
|
||||
#define __SYS_fstatvfs 38
|
||||
#define __SYS_faccessat 39
|
||||
#define __SYS_fcntl 40
|
||||
#define __SYS_ftruncate 41
|
||||
#define __SYS_truncate 42
|
||||
#define __SYS_fallocate 43
|
||||
#define __SYS_fadvise 44
|
||||
#define __SYS_utimensat 45
|
||||
#define __SYS_mknodat 46
|
||||
#define __SYS_getcwd 47
|
||||
#define __SYS_chdir 48
|
||||
#define __SYS_fchdir 49
|
||||
#define __SYS_mkdirat 50
|
||||
#define __SYS_rmdirat 51
|
||||
#define __SYS_getdents 52
|
||||
#define __SYS_renameat 53
|
||||
#define __SYS_fchmod 54
|
||||
#define __SYS_fchmodat 55
|
||||
#define __SYS_fchownat 56
|
||||
#define __SYS_linkat 57
|
||||
#define __SYS_symlinkat 58
|
||||
#define __SYS_unlinkat 59
|
||||
#define __SYS_readlinkat 60
|
||||
#define __SYS_flock 61
|
||||
#define __SYS_ppoll 62
|
||||
#define __SYS_dup 63
|
||||
#define __SYS_dup3 64
|
||||
#define __SYS_sync 65
|
||||
#define __SYS_fsync 66
|
||||
#define __SYS_fdatasync 67
|
||||
#define __SYS_getgroups 68
|
||||
#define __SYS_setgroups 69
|
||||
#define __SYS_getsid 70
|
||||
#define __SYS_setsid 71
|
||||
#define __SYS_setuid 72
|
||||
#define __SYS_getuid 73
|
||||
#define __SYS_setgid 74
|
||||
#define __SYS_getgid 75
|
||||
#define __SYS_geteuid 76
|
||||
#define __SYS_seteuid 77
|
||||
#define __SYS_getegid 78
|
||||
#define __SYS_setegid 79
|
||||
#define __SYS_getpgid 80
|
||||
#define __SYS_setpgid 81
|
||||
#define __SYS_getresuid 82
|
||||
#define __SYS_setresuid 83
|
||||
#define __SYS_getresgid 84
|
||||
#define __SYS_setresgid 85
|
||||
#define __SYS_setreuid 86
|
||||
#define __SYS_setregid 87
|
||||
#define __SYS_umask 88
|
||||
#define __SYS_pipe 89
|
||||
#define __SYS_futex_wait 90
|
||||
#define __SYS_futex_wake 91
|
||||
#define __SYS_thread_create 92
|
||||
#define __SYS_thread_kill 93
|
||||
#define __SYS_thread_exit 94
|
||||
#define __SYS_thread_setname 95
|
||||
#define __SYS_thread_getname 96
|
||||
#define __SYS_timer_create 97
|
||||
#define __SYS_timer_set 98
|
||||
#define __SYS_timer_get 99
|
||||
#define __SYS_timer_getoverrun 100
|
||||
#define __SYS_timer_delete 101
|
||||
#define __SYS_itimer_get 102
|
||||
#define __SYS_itimer_set 103
|
||||
#define __SYS_clock_get 104
|
||||
#define __SYS_clock_getres 105
|
||||
#define __SYS_clock_set 106
|
||||
#define __SYS_sleep 107
|
||||
#define __SYS_yield 108
|
||||
#define __SYS_chroot 109
|
||||
#define __SYS_mount 110
|
||||
#define __SYS_umount 111
|
||||
#define __SYS_socket 112
|
||||
#define __SYS_socketpair 113
|
||||
#define __SYS_shutdown 114
|
||||
#define __SYS_bind 115
|
||||
#define __SYS_connect 116
|
||||
#define __SYS_accept 117
|
||||
#define __SYS_listen 118
|
||||
#define __SYS_getpeername 119
|
||||
#define __SYS_getsockname 120
|
||||
#define __SYS_getsockopt 121
|
||||
#define __SYS_setsockopt 122
|
||||
#define __SYS_sendmsg 123
|
||||
#define __SYS_recvmsg 124
|
||||
#define __SYS_getentropy 125
|
||||
#define __SYS_getrusage 126
|
||||
#define __SYS_getrlimit 127
|
||||
#define __SYS_setrlimit 128
|
||||
#define __SYS_getpriority 129
|
||||
#define __SYS_setpriority 130
|
||||
#define __SYS_sched_getparam 131
|
||||
#define __SYS_sched_setparam 132
|
||||
#define __SYS_module_insert 133
|
||||
#define __SYS_module_remove 134
|
||||
#define __SYS_epoll_create 135
|
||||
#define __SYS_epoll_ctl 136
|
||||
#define __SYS_epoll_pwait 137
|
||||
#define __SYS_timerfd_create 138
|
||||
#define __SYS_timerfd_gettime 139
|
||||
#define __SYS_timerfd_settime 140
|
||||
#define __SYS_signalfd_create 141
|
||||
#define __SYS_eventfd_create 142
|
||||
#define __SYS_msync 143
|
||||
#define __SYS_sysconf 144
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_TIME_H
|
||||
#define __ZINNIA_UAPI_TIME_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int64_t time_t;
|
||||
typedef int64_t suseconds_t;
|
||||
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
int64_t tv_nsec;
|
||||
};
|
||||
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
|
||||
struct itimerval {
|
||||
struct timeval it_interval;
|
||||
struct timeval it_value;
|
||||
};
|
||||
|
||||
struct itimerspec {
|
||||
struct timespec it_interval;
|
||||
struct timespec it_value;
|
||||
};
|
||||
|
||||
#define __ITIMER_REAL 0
|
||||
#define __ITIMER_VIRTUAL 1
|
||||
#define __ITIMER_PROF 2
|
||||
|
||||
#define __CLOCK_REALTIME 0
|
||||
#define __CLOCK_MONOTONIC 1
|
||||
#define __CLOCK_PROCESS_CPUTIME_ID 2
|
||||
#define __CLOCK_THREAD_CPUTIME_ID 3
|
||||
#define __CLOCK_MONOTONIC_RAW 4
|
||||
#define __CLOCK_REALTIME_COARSE 5
|
||||
#define __CLOCK_MONOTONIC_COARSE 6
|
||||
#define __CLOCK_BOOTTIME 7
|
||||
|
||||
#define __TFD_CLOEXEC __O_CLOEXEC
|
||||
#define __TFD_NONBLOCK __O_NONBLOCK
|
||||
#define __TFD_TIMER_ABSTIME 1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_TYPES_H
|
||||
#define __ZINNIA_UAPI_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int64_t off_t;
|
||||
typedef off_t off64_t;
|
||||
typedef uintptr_t blksize_t;
|
||||
typedef uintptr_t blkcnt_t;
|
||||
typedef uintptr_t clockid_t;
|
||||
typedef uintptr_t dev_t;
|
||||
typedef uint32_t gid_t;
|
||||
typedef uintptr_t ino_t;
|
||||
typedef uint32_t mode_t;
|
||||
typedef uintptr_t nlink_t;
|
||||
typedef int32_t pid_t;
|
||||
typedef uintptr_t rlim_t;
|
||||
typedef uint32_t uid_t;
|
||||
typedef uintptr_t fsblkcnt_t;
|
||||
typedef uintptr_t fsfilcnt_t;
|
||||
typedef uintptr_t pthread_attr_t;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_UIO_H
|
||||
#define __ZINNIA_UAPI_UIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct iovec {
|
||||
void* base;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef __ZINNIA_UAPI_UTSNAME_H
|
||||
#define __ZINNIA_UAPI_UTSNAME_H
|
||||
|
||||
struct utsname {
|
||||
char sysname[65];
|
||||
char nodename[65];
|
||||
char release[65];
|
||||
char version[65];
|
||||
char machine[65];
|
||||
char domainname[65];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include <uapi/archctl.h>
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/elf.h>
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/irq.h>
|
||||
|
||||
void arch_irq_set_state(bool state);
|
||||
bool arch_irq_get_state();
|
||||
void arch_irq_wait();
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
size_t arch_mem_page_size();
|
||||
size_t arch_mem_page_bits();
|
||||
size_t arch_mem_level_bits();
|
||||
size_t arch_mem_num_levels();
|
||||
uintptr_t arch_mem_hhdm_addr();
|
||||
uintptr_t arch_vm_pfndb_addr();
|
||||
uintptr_t arch_mem_mapping_addr();
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/usercopy.h>
|
||||
|
||||
bool arch_usercopy_read(void* dst, const __user void* src, size_t len, struct usercopy_region** region);
|
||||
bool arch_usercopy_write(__user void* dst, const void* src, size_t len, struct usercopy_region** region);
|
||||
bool arch_usercopy_strlen(const __user char* str, size_t max, size_t* len, struct usercopy_region** region);
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct clock {
|
||||
const char* name;
|
||||
uint8_t priority;
|
||||
|
||||
void (*reset)(struct clock* c);
|
||||
uint64_t (*get_elapsed_ns)(struct clock* c);
|
||||
};
|
||||
|
||||
// Attempts to set a new clock. Returns true if the clock was changed.
|
||||
bool clock_switch(struct clock* clock);
|
||||
|
||||
// Returns true, if a clock is available.
|
||||
bool clock_available();
|
||||
|
||||
// Gets the current timestamp in nanoseconds since the last reset.
|
||||
uint64_t clock_get_elapsed_ns();
|
||||
|
||||
// Spin for `ns` nanoseconds.
|
||||
void clock_spin_ns(uint64_t ns);
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/utils.h>
|
||||
|
||||
#define _CMDLINE_OPTION(x, opt_name, opt_func) \
|
||||
static const struct cmdline_option x = { \
|
||||
.name = opt_name, \
|
||||
.option_type = _Generic( \
|
||||
(opt_func), \
|
||||
void (*)(const char*): CMDLINE_STRING, \
|
||||
void (*)(bool): CMDLINE_BOOL, \
|
||||
void (*)(intptr_t): CMDLINE_INTPTR, \
|
||||
void (*)(uintptr_t): CMDLINE_UINTPTR \
|
||||
), \
|
||||
.func = (void*)(opt_func), \
|
||||
}; \
|
||||
[[__used, __section(".cmdline")]] \
|
||||
static const struct cmdline_option* CONCAT(x, _ptr) = &x;
|
||||
|
||||
#define CMDLINE_OPTION(opt_name, opt_func) _CMDLINE_OPTION(UNIQUE_IDENT(cmdline_option), opt_name, opt_func)
|
||||
|
||||
enum cmdline_type {
|
||||
CMDLINE_STRING,
|
||||
CMDLINE_BOOL,
|
||||
CMDLINE_INTPTR,
|
||||
CMDLINE_UINTPTR,
|
||||
};
|
||||
|
||||
struct cmdline_option {
|
||||
// The name of this option.
|
||||
const char* name;
|
||||
// Gets called if this option is present on the command line.
|
||||
union {
|
||||
void (*func_str)(const char* value);
|
||||
void (*func_bool)(bool value);
|
||||
void (*func_intptr)(intptr_t value);
|
||||
void (*func_uintptr)(uintptr_t value);
|
||||
void* func;
|
||||
};
|
||||
enum cmdline_type option_type;
|
||||
};
|
||||
|
||||
// Parses the command line and invokes all options.
|
||||
void cmdline_parse(const char* cmdline);
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
// Attributes that affect data layout.
|
||||
#define __section(x) gnu::section(x)
|
||||
#define __aligned(x) gnu::aligned(x)
|
||||
#define __packed gnu::packed
|
||||
#define __naked gnu::naked
|
||||
|
||||
// These hints may improve code generation.
|
||||
#define __cold gnu::cold
|
||||
#define __hot gnu::hot
|
||||
#define __used gnu::used
|
||||
#define __unused gnu::unused
|
||||
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
|
||||
#define __likely(x) __builtin_expect(!!(x), 1)
|
||||
#define __unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define __always_inline gnu::always_inline
|
||||
|
||||
// Only clang has these hints, GCC will throw a warning here.
|
||||
// They also don't support the C23 attribute format.
|
||||
#ifdef __clang__
|
||||
#define __user __attribute__((noderef, address_space(1)))
|
||||
#define __phys __attribute__((noderef, address_space(2)))
|
||||
#else
|
||||
#define __user
|
||||
#define __phys
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/utils.h>
|
||||
|
||||
struct console {
|
||||
const char* name;
|
||||
void* private;
|
||||
|
||||
// Initializes the console.
|
||||
bool (*init)(struct console* con);
|
||||
// Writes to the console.
|
||||
void (*write)(struct console* con, const char* buf, size_t count);
|
||||
};
|
||||
|
||||
// Initializes a console for logging.
|
||||
void console_init();
|
||||
|
||||
// Writes a message to a console.
|
||||
void console_write(const char* buf, size_t len);
|
||||
|
||||
// Defines a new early console which can be used to log early boot messages.
|
||||
// An early console must not make any heap allocations.
|
||||
#define DEFINE_CONSOLE(con) \
|
||||
[[__used, __section(".console")]] \
|
||||
static struct console* UNIQUE_IDENT(console) = (con)
|
||||
@@ -0,0 +1,340 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
constexpr char ELF_MAG[4] = {0x7F, 'E', 'L', 'F'};
|
||||
|
||||
typedef uint64_t elf64_addr_t;
|
||||
typedef uint64_t elf64_off_t;
|
||||
typedef uint32_t elf32_addr_t;
|
||||
typedef uint32_t elf32_off_t;
|
||||
|
||||
enum : uint8_t {
|
||||
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,
|
||||
EI_NIDENT = 16,
|
||||
};
|
||||
|
||||
enum : uint16_t {
|
||||
EM_X86_64 = 62,
|
||||
EM_AARCH64 = 183,
|
||||
EM_RISCV = 243,
|
||||
EM_LOONGARCH = 258,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
ELFCLASS32 = 1,
|
||||
ELFCLASS64 = 2,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
ELFDATA2LSB = 1,
|
||||
ELFDATA2MSB = 2,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
EV_NONE = 0,
|
||||
EV_CURRENT = 1,
|
||||
EV_NUM = 2,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
ELFOSABI_SYSV = 0,
|
||||
ELFOSABI_HPUX = 1,
|
||||
ELFOSABI_STANDALONE = 255,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
ET_NONE = 0,
|
||||
ET_REL = 1,
|
||||
ET_EXEC = 2,
|
||||
ET_DYN = 3,
|
||||
ET_CORE = 4,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
PT_NULL = 0x00000000,
|
||||
PT_LOAD = 0x00000001,
|
||||
PT_DYNAMIC = 0x00000002,
|
||||
PT_INTERP = 0x00000003,
|
||||
PT_NOTE = 0x00000004,
|
||||
PT_SHLIB = 0x00000005,
|
||||
PT_PHDR = 0x00000006,
|
||||
PT_TLS = 0x00000007,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
PF_X = 0x00000001,
|
||||
PF_W = 0x00000002,
|
||||
PF_R = 0x00000004,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
DT_NULL = 0,
|
||||
DT_NEEDED = 1,
|
||||
DT_PLTRELSZ = 2,
|
||||
DT_PLTGOT = 3,
|
||||
DT_HASH = 4,
|
||||
DT_STRTAB = 5,
|
||||
DT_SYMTAB = 6,
|
||||
DT_RELA = 7,
|
||||
DT_RELASZ = 8,
|
||||
DT_RELAENT = 9,
|
||||
DT_STRSZ = 10,
|
||||
DT_SYMENT = 11,
|
||||
DT_INIT = 12,
|
||||
DT_FINI = 13,
|
||||
DT_SONAME = 14,
|
||||
DT_RPATH = 15,
|
||||
DT_SYMBOLIC = 16,
|
||||
DT_REL = 17,
|
||||
DT_RELSZ = 18,
|
||||
DT_RELENT = 19,
|
||||
DT_PLTREL = 20,
|
||||
DT_DEBUG = 21,
|
||||
DT_TEXTREL = 22,
|
||||
DT_JMPREL = 23,
|
||||
DT_BIND_NOW = 24,
|
||||
DT_INIT_ARRAY = 25,
|
||||
DT_FINI_ARRAY = 26,
|
||||
DT_INIT_ARRAYSZ = 27,
|
||||
DT_FINI_ARRAYSZ = 28,
|
||||
DT_LOOS = 0x60000000,
|
||||
DT_HIOS = 0x6FFFFFFF,
|
||||
DT_LOPROC = 0x70000000,
|
||||
DT_HIPROC = 0x7FFFFFFF,
|
||||
};
|
||||
|
||||
enum : uint32_t {
|
||||
AT_NULL = 0,
|
||||
AT_IGNORE = 1,
|
||||
AT_EXECFD = 2,
|
||||
AT_PHDR = 3,
|
||||
AT_PHENT = 4,
|
||||
AT_PHNUM = 5,
|
||||
AT_PAGESZ = 6,
|
||||
AT_BASE = 7,
|
||||
AT_FLAGS = 8,
|
||||
AT_ENTRY = 9,
|
||||
AT_NOTELF = 10,
|
||||
AT_UID = 11,
|
||||
AT_EUID = 12,
|
||||
AT_GID = 13,
|
||||
AT_EGID = 14,
|
||||
AT_HWCAP = 16,
|
||||
AT_SECURE = 23,
|
||||
AT_RANDOM = 25,
|
||||
AT_EXECFN = 31,
|
||||
AT_SYSINFO_EHDR = 33,
|
||||
AT_INIT_HANDLE = 0x1000,
|
||||
};
|
||||
|
||||
struct elf64_ehdr {
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
elf64_addr_t e_entry;
|
||||
elf64_off_t e_phoff;
|
||||
elf64_off_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
struct elf32_ehdr {
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
elf32_addr_t e_entry;
|
||||
elf32_off_t e_phoff;
|
||||
elf32_off_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
struct elf64_phdr {
|
||||
uint32_t p_type;
|
||||
uint32_t p_flags;
|
||||
elf64_off_t p_offset;
|
||||
elf64_addr_t p_vaddr;
|
||||
elf64_addr_t p_paddr;
|
||||
uint64_t p_filesz;
|
||||
uint64_t p_memsz;
|
||||
uint64_t p_align;
|
||||
};
|
||||
|
||||
struct elf32_phdr {
|
||||
uint32_t p_type;
|
||||
elf32_off_t p_offset;
|
||||
elf32_addr_t p_vaddr;
|
||||
elf32_addr_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
};
|
||||
|
||||
struct elf64_dyn {
|
||||
int64_t d_tag;
|
||||
union {
|
||||
uint64_t d_val;
|
||||
elf64_addr_t d_ptr;
|
||||
} d_un;
|
||||
};
|
||||
|
||||
struct elf32_dyn {
|
||||
int32_t r_offset;
|
||||
union {
|
||||
uint32_t d_val;
|
||||
elf32_addr_t d_ptr;
|
||||
} d_un;
|
||||
};
|
||||
|
||||
struct elf64_nhdr {
|
||||
uint64_t n_namesz;
|
||||
uint64_t n_descsz;
|
||||
uint64_t n_type;
|
||||
};
|
||||
|
||||
struct elf32_nhdr {
|
||||
uint32_t n_namesz;
|
||||
uint32_t n_descsz;
|
||||
uint32_t n_type;
|
||||
};
|
||||
|
||||
struct elf64_auxv {
|
||||
uint64_t atype;
|
||||
uint64_t avalue;
|
||||
};
|
||||
|
||||
struct elf32_auxv {
|
||||
uint32_t atype;
|
||||
uint32_t avalue;
|
||||
};
|
||||
|
||||
struct elf_hash {
|
||||
uint32_t n_buckets;
|
||||
uint32_t n_chain;
|
||||
};
|
||||
|
||||
struct elf32_sym {
|
||||
elf32_off_t st_name;
|
||||
elf32_addr_t st_value;
|
||||
elf32_off_t st_size;
|
||||
uint8_t st_info;
|
||||
uint8_t st_other;
|
||||
uint16_t st_shndx;
|
||||
};
|
||||
|
||||
struct elf64_sym {
|
||||
uint32_t st_name;
|
||||
uint8_t st_info;
|
||||
uint8_t st_other;
|
||||
uint16_t st_shndx;
|
||||
uint64_t st_value;
|
||||
uint64_t st_size;
|
||||
};
|
||||
|
||||
static uint8_t ELF64_ST_BIND(uint8_t info) {
|
||||
return info >> 4;
|
||||
}
|
||||
|
||||
static inline uint8_t ELF64_ST_TYPE(uint8_t info) {
|
||||
return info & 0x0F;
|
||||
}
|
||||
|
||||
static inline uint8_t ELF64_ST_INFO(uint8_t bind, uint8_t type) {
|
||||
return (bind << 4) | type;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint16_t si_boundto;
|
||||
uint16_t si_flags;
|
||||
} elf64_syminfo;
|
||||
|
||||
static inline uint8_t ELF32_ST_BIND(uint8_t info) {
|
||||
return info >> 4;
|
||||
}
|
||||
|
||||
static inline uint8_t ELF32_ST_TYPE(uint8_t info) {
|
||||
return info & 0xF;
|
||||
}
|
||||
|
||||
static inline uint8_t ELF32_ST_INFO(uint8_t bind, uint8_t type) {
|
||||
return (bind << 4) | (type & 0xF);
|
||||
}
|
||||
|
||||
enum {
|
||||
STB_GLOBAL = 1,
|
||||
STB_WEAK = 2,
|
||||
STB_GNU_UNIQUE = 10,
|
||||
STB_LOPROC = 13,
|
||||
STB_HIPROC = 15
|
||||
};
|
||||
|
||||
enum {
|
||||
STT_NOTYPE = 0,
|
||||
STT_OBJECT = 1,
|
||||
STT_FUNC = 2,
|
||||
STT_TLS = 6,
|
||||
STT_GNU_IFUNC = 10,
|
||||
STT_LOPROC = 13,
|
||||
STT_HIPROC = 15
|
||||
};
|
||||
|
||||
struct elf32_rela {
|
||||
elf32_addr_t r_offset;
|
||||
uint32_t r_info;
|
||||
int32_t r_addend;
|
||||
};
|
||||
|
||||
struct elf64_rela {
|
||||
elf64_addr_t r_offset;
|
||||
uint64_t r_info;
|
||||
int64_t r_addend;
|
||||
};
|
||||
|
||||
struct elf32_rel {
|
||||
elf32_addr_t r_offset;
|
||||
uint32_t r_info;
|
||||
};
|
||||
|
||||
struct elf64_rel {
|
||||
elf64_addr_t r_offset;
|
||||
uint64_t r_info;
|
||||
};
|
||||
|
||||
static inline uint32_t ELF32_R_SYM(uint32_t info) {
|
||||
return info >> 8;
|
||||
}
|
||||
|
||||
static inline uint32_t ELF32_R_TYPE(uint32_t info) {
|
||||
return info & 0xF;
|
||||
}
|
||||
|
||||
static inline uint32_t ELF64_R_SYM(uint64_t info) {
|
||||
return info >> 32;
|
||||
}
|
||||
|
||||
static inline uint32_t ELF64_R_TYPE(uint64_t info) {
|
||||
return info & 0xFFFFFFFF;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <uapi/errno.h>
|
||||
|
||||
typedef enum : int32_t {
|
||||
EOK = 0, // Not really an error.
|
||||
EPERM = __EPERM,
|
||||
ENOENT = __ENOENT,
|
||||
ESRCH = __ESRCH,
|
||||
EINTR = __EINTR,
|
||||
EIO = __EIO,
|
||||
ENXIO = __ENXIO,
|
||||
E2BIG = __E2BIG,
|
||||
ENOEXEC = __ENOEXEC,
|
||||
EBADF = __EBADF,
|
||||
ECHILD = __ECHILD,
|
||||
EAGAIN = __EAGAIN,
|
||||
ENOMEM = __ENOMEM,
|
||||
EACCES = __EACCES,
|
||||
EFAULT = __EFAULT,
|
||||
ENOTBLK = __ENOTBLK,
|
||||
EBUSY = __EBUSY,
|
||||
EEXIST = __EEXIST,
|
||||
EXDEV = __EXDEV,
|
||||
ENODEV = __ENODEV,
|
||||
ENOTDIR = __ENOTDIR,
|
||||
EISDIR = __EISDIR,
|
||||
EINVAL = __EINVAL,
|
||||
ENFILE = __ENFILE,
|
||||
EMFILE = __EMFILE,
|
||||
ENOTTY = __ENOTTY,
|
||||
ETXTBSY = __ETXTBSY,
|
||||
EFBIG = __EFBIG,
|
||||
ENOSPC = __ENOSPC,
|
||||
ESPIPE = __ESPIPE,
|
||||
EROFS = __EROFS,
|
||||
EMLINK = __EMLINK,
|
||||
EPIPE = __EPIPE,
|
||||
EDOM = __EDOM,
|
||||
ERANGE = __ERANGE,
|
||||
EDEADLK = __EDEADLK,
|
||||
ENAMETOOLONG = __ENAMETOOLONG,
|
||||
ENOLCK = __ENOLCK,
|
||||
ENOSYS = __ENOSYS,
|
||||
ENOTEMPTY = __ENOTEMPTY,
|
||||
ELOOP = __ELOOP,
|
||||
EWOULDBLOCK = __EWOULDBLOCK,
|
||||
ENOMSG = __ENOMSG,
|
||||
EIDRM = __EIDRM,
|
||||
ECHRNG = __ECHRNG,
|
||||
EL2NSYNC = __EL2NSYNC,
|
||||
EL3HLT = __EL3HLT,
|
||||
EL3RST = __EL3RST,
|
||||
ELNRNG = __ELNRNG,
|
||||
EUNATCH = __EUNATCH,
|
||||
ENOCSI = __ENOCSI,
|
||||
EL2HLT = __EL2HLT,
|
||||
EBADE = __EBADE,
|
||||
EBADR = __EBADR,
|
||||
EXFULL = __EXFULL,
|
||||
ENOANO = __ENOANO,
|
||||
EBADRQC = __EBADRQC,
|
||||
EBADSLT = __EBADSLT,
|
||||
EDEADLOCK = __EDEADLOCK,
|
||||
EBFONT = __EBFONT,
|
||||
ENOSTR = __ENOSTR,
|
||||
ENODATA = __ENODATA,
|
||||
ETIME = __ETIME,
|
||||
ENOSR = __ENOSR,
|
||||
ENONET = __ENONET,
|
||||
ENOPKG = __ENOPKG,
|
||||
EREMOTE = __EREMOTE,
|
||||
ENOLINK = __ENOLINK,
|
||||
EADV = __EADV,
|
||||
ESRMNT = __ESRMNT,
|
||||
ECOMM = __ECOMM,
|
||||
EPROTO = __EPROTO,
|
||||
EMULTIHOP = __EMULTIHOP,
|
||||
EDOTDOT = __EDOTDOT,
|
||||
EBADMSG = __EBADMSG,
|
||||
EOVERFLOW = __EOVERFLOW,
|
||||
ENOTUNIQ = __ENOTUNIQ,
|
||||
EBADFD = __EBADFD,
|
||||
EREMCHG = __EREMCHG,
|
||||
ELIBACC = __ELIBACC,
|
||||
ELIBBAD = __ELIBBAD,
|
||||
ELIBSCN = __ELIBSCN,
|
||||
ELIBMAX = __ELIBMAX,
|
||||
ELIBEXEC = __ELIBEXEC,
|
||||
EILSEQ = __EILSEQ,
|
||||
ERESTART = __ERESTART,
|
||||
ESTRPIPE = __ESTRPIPE,
|
||||
EUSERS = __EUSERS,
|
||||
ENOTSOCK = __ENOTSOCK,
|
||||
EDESTADDRREQ = __EDESTADDRREQ,
|
||||
EMSGSIZE = __EMSGSIZE,
|
||||
EPROTOTYPE = __EPROTOTYPE,
|
||||
ENOPROTOOPT = __ENOPROTOOPT,
|
||||
EPROTONOSUPPORT = __EPROTONOSUPPORT,
|
||||
ESOCKTNOSUPPORT = __ESOCKTNOSUPPORT,
|
||||
EOPNOTSUPP = __EOPNOTSUPP,
|
||||
ENOTSUP = __ENOTSUP,
|
||||
EPFNOSUPPORT = __EPFNOSUPPORT,
|
||||
EAFNOSUPPORT = __EAFNOSUPPORT,
|
||||
EADDRINUSE = __EADDRINUSE,
|
||||
EADDRNOTAVAIL = __EADDRNOTAVAIL,
|
||||
ENETDOWN = __ENETDOWN,
|
||||
ENETUNREACH = __ENETUNREACH,
|
||||
ENETRESET = __ENETRESET,
|
||||
ECONNABORTED = __ECONNABORTED,
|
||||
ECONNRESET = __ECONNRESET,
|
||||
ENOBUFS = __ENOBUFS,
|
||||
EISCONN = __EISCONN,
|
||||
ENOTCONN = __ENOTCONN,
|
||||
ESHUTDOWN = __ESHUTDOWN,
|
||||
ETOOMANYREFS = __ETOOMANYREFS,
|
||||
ETIMEDOUT = __ETIMEDOUT,
|
||||
ECONNREFUSED = __ECONNREFUSED,
|
||||
EHOSTDOWN = __EHOSTDOWN,
|
||||
EHOSTUNREACH = __EHOSTUNREACH,
|
||||
EALREADY = __EALREADY,
|
||||
EINPROGRESS = __EINPROGRESS,
|
||||
ESTALE = __ESTALE,
|
||||
EUCLEAN = __EUCLEAN,
|
||||
ENOTNAM = __ENOTNAM,
|
||||
ENAVAIL = __ENAVAIL,
|
||||
EISNAM = __EISNAM,
|
||||
EREMOTEIO = __EREMOTEIO,
|
||||
EDQUOT = __EDQUOT,
|
||||
ENOMEDIUM = __ENOMEDIUM,
|
||||
EMEDIUMTYPE = __EMEDIUMTYPE,
|
||||
ECANCELED = __ECANCELED,
|
||||
ENOKEY = __ENOKEY,
|
||||
EKEYEXPIRED = __EKEYEXPIRED,
|
||||
EKEYREVOKED = __EKEYREVOKED,
|
||||
EKEYREJECTED = __EKEYREJECTED,
|
||||
EOWNERDEAD = __EOWNERDEAD,
|
||||
ENOTRECOVERABLE = __ENOTRECOVERABLE,
|
||||
ERFKILL = __ERFKILL,
|
||||
EHWPOISON = __EHWPOISON,
|
||||
} errno_t;
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/wait.h>
|
||||
|
||||
struct futex {};
|
||||
|
||||
// Initializes the global futex table.
|
||||
void futex_init(void);
|
||||
|
||||
// Blocks the calling task if *addr == expected.
|
||||
errno_t futex_wait(__user int* addr, int expected);
|
||||
|
||||
// Wakes up to `count` tasks waiting on the given address.
|
||||
// Returns the number of tasks woken.
|
||||
errno_t futex_wake(__user int* addr, int count);
|
||||
@@ -0,0 +1,223 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/errno.h>
|
||||
|
||||
// FNV-1a hash over raw bytes.
|
||||
static inline uint64_t hashmap_hash_default(const void* key, size_t len) {
|
||||
const uint8_t* data = (const uint8_t*)key;
|
||||
uint64_t hash = 0xcbf29ce484222325;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
hash ^= data[i];
|
||||
hash *= 0x100000001b3;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Byte-wise equality.
|
||||
static inline bool hashmap_eq_default(const void* a, const void* b, size_t len) {
|
||||
return memcmp(a, b, len) == 0;
|
||||
}
|
||||
|
||||
// Ensure a hash is never zero (zero is the empty sentinel).
|
||||
#define _HASHMAP_FIXHASH(h) ((h) == 0 ? (uint64_t)1 : (h))
|
||||
|
||||
#define HASHMAP(K, V) \
|
||||
struct { \
|
||||
K* keys; \
|
||||
V* values; \
|
||||
uint64_t* hashes; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
}
|
||||
|
||||
#define HASHMAP_INIT(map) \
|
||||
do { \
|
||||
(map)->keys = nullptr; \
|
||||
(map)->values = nullptr; \
|
||||
(map)->hashes = nullptr; \
|
||||
(map)->capacity = 0; \
|
||||
(map)->count = 0; \
|
||||
} while (0)
|
||||
|
||||
#define HASHMAP_DESTROY(map) \
|
||||
do { \
|
||||
mem_free((map)->keys); \
|
||||
mem_free((map)->values); \
|
||||
mem_free((map)->hashes); \
|
||||
(map)->keys = nullptr; \
|
||||
(map)->values = nullptr; \
|
||||
(map)->hashes = nullptr; \
|
||||
(map)->capacity = 0; \
|
||||
(map)->count = 0; \
|
||||
} while (0)
|
||||
|
||||
#define HASHMAP_COUNT(map) ((map)->count)
|
||||
|
||||
// Internal: probe distance from ideal position.
|
||||
#define _HASHMAP_PROBE_DIST(hash, pos, cap) (((pos) - ((hash) & ((cap) - 1))) & ((cap) - 1))
|
||||
|
||||
// Internal: grow and rehash.
|
||||
#define _HASHMAP_GROW(map, hash_fn, eq_fn) \
|
||||
do { \
|
||||
size_t _old_cap = (map)->capacity; \
|
||||
size_t _new_cap = _old_cap == 0 ? 16 : _old_cap * 2; \
|
||||
typeof((map)->keys) _old_keys = (map)->keys; \
|
||||
typeof((map)->values) _old_values = (map)->values; \
|
||||
uint64_t* _old_hashes = (map)->hashes; \
|
||||
(map)->keys = mem_alloc(_new_cap * sizeof(*(map)->keys), ALLOC_NOZERO); \
|
||||
(map)->values = mem_alloc(_new_cap * sizeof(*(map)->values), ALLOC_NOZERO); \
|
||||
(map)->hashes = mem_alloc(_new_cap * sizeof(uint64_t), 0); \
|
||||
(map)->capacity = _new_cap; \
|
||||
(map)->count = 0; \
|
||||
for (size_t _i = 0; _i < _old_cap; _i++) { \
|
||||
if (_old_hashes[_i] != 0) { \
|
||||
_HASHMAP_INSERT_INNER(map, _old_keys[_i], _old_values[_i], _old_hashes[_i]); \
|
||||
} \
|
||||
} \
|
||||
mem_free(_old_keys); \
|
||||
mem_free(_old_values); \
|
||||
mem_free(_old_hashes); \
|
||||
} while (0)
|
||||
|
||||
// Internal: insert with a precomputed hash. Used by grow and the public INSERT macro.
|
||||
#define _HASHMAP_INSERT_INNER(map, k, v, h) \
|
||||
do { \
|
||||
size_t _cap = (map)->capacity; \
|
||||
size_t _pos = (h) & (_cap - 1); \
|
||||
typeof(*(map)->keys) _ik = (k); \
|
||||
typeof(*(map)->values) _iv = (v); \
|
||||
uint64_t _ih = (h); \
|
||||
for (;;) { \
|
||||
if ((map)->hashes[_pos] == 0) { \
|
||||
(map)->keys[_pos] = _ik; \
|
||||
(map)->values[_pos] = _iv; \
|
||||
(map)->hashes[_pos] = _ih; \
|
||||
(map)->count++; \
|
||||
break; \
|
||||
} \
|
||||
size_t _existing_dist = _HASHMAP_PROBE_DIST((map)->hashes[_pos], _pos, _cap); \
|
||||
size_t _insert_dist = _HASHMAP_PROBE_DIST(_ih, _pos, _cap); \
|
||||
if (_insert_dist > _existing_dist) { \
|
||||
typeof(*(map)->keys) _tk = (map)->keys[_pos]; \
|
||||
typeof(*(map)->values) _tv = (map)->values[_pos]; \
|
||||
uint64_t _th = (map)->hashes[_pos]; \
|
||||
(map)->keys[_pos] = _ik; \
|
||||
(map)->values[_pos] = _iv; \
|
||||
(map)->hashes[_pos] = _ih; \
|
||||
_ik = _tk; \
|
||||
_iv = _tv; \
|
||||
_ih = _th; \
|
||||
} \
|
||||
_pos = (_pos + 1) & (_cap - 1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Insert or update a key-value pair. Returns 0 or ENOMEM.
|
||||
#define HASHMAP_INSERT(map, key, val, hash_fn, eq_fn) \
|
||||
({ \
|
||||
errno_t _status = 0; \
|
||||
typeof(*(map)->keys) _k = (key); \
|
||||
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
|
||||
/* Check for existing key first. */ \
|
||||
bool _found = false; \
|
||||
if ((map)->capacity > 0) { \
|
||||
size_t _cap = (map)->capacity; \
|
||||
size_t _pos = _h & (_cap - 1); \
|
||||
for (size_t _d = 0; _d < _cap; _d++) { \
|
||||
if ((map)->hashes[_pos] == 0) \
|
||||
break; \
|
||||
if (_HASHMAP_PROBE_DIST((map)->hashes[_pos], _pos, _cap) < _d) \
|
||||
break; \
|
||||
if ((map)->hashes[_pos] == _h && (eq_fn)(&(map)->keys[_pos], &_k, sizeof(_k))) { \
|
||||
(map)->values[_pos] = (val); \
|
||||
_found = true; \
|
||||
break; \
|
||||
} \
|
||||
_pos = (_pos + 1) & (_cap - 1); \
|
||||
} \
|
||||
} \
|
||||
if (!_found) { \
|
||||
if ((map)->count * 4 >= (map)->capacity * 3 || (map)->capacity == 0) { \
|
||||
_HASHMAP_GROW(map, hash_fn, eq_fn); \
|
||||
if ((map)->keys == nullptr || (map)->values == nullptr || (map)->hashes == nullptr) { \
|
||||
_status = ENOMEM; \
|
||||
} \
|
||||
} \
|
||||
if (_status == 0) { \
|
||||
_HASHMAP_INSERT_INNER(map, _k, (val), _h); \
|
||||
} \
|
||||
} \
|
||||
_status; \
|
||||
})
|
||||
|
||||
// Look up a key. Returns a pointer to the value, or nullptr if not found.
|
||||
#define HASHMAP_GET(map, key, hash_fn, eq_fn) \
|
||||
({ \
|
||||
typeof(*(map)->values)* _result = nullptr; \
|
||||
if ((map)->capacity > 0) { \
|
||||
typeof(*(map)->keys) _k = (key); \
|
||||
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
|
||||
size_t _cap = (map)->capacity; \
|
||||
size_t _pos = _h & (_cap - 1); \
|
||||
for (size_t _d = 0; _d < _cap; _d++) { \
|
||||
if ((map)->hashes[_pos] == 0) \
|
||||
break; \
|
||||
if (_HASHMAP_PROBE_DIST((map)->hashes[_pos], _pos, _cap) < _d) \
|
||||
break; \
|
||||
if ((map)->hashes[_pos] == _h && (eq_fn)(&(map)->keys[_pos], &_k, sizeof(_k))) { \
|
||||
_result = &(map)->values[_pos]; \
|
||||
break; \
|
||||
} \
|
||||
_pos = (_pos + 1) & (_cap - 1); \
|
||||
} \
|
||||
} \
|
||||
_result; \
|
||||
})
|
||||
|
||||
// Remove a key. Returns true if the key was found and removed.
|
||||
// Uses backward-shift deletion to avoid tombstones.
|
||||
#define HASHMAP_REMOVE(map, key, hash_fn, eq_fn) \
|
||||
({ \
|
||||
bool _removed = false; \
|
||||
if ((map)->capacity > 0) { \
|
||||
typeof(*(map)->keys) _k = (key); \
|
||||
uint64_t _h = _HASHMAP_FIXHASH((hash_fn)(&_k, sizeof(_k))); \
|
||||
size_t _cap = (map)->capacity; \
|
||||
size_t _pos = _h & (_cap - 1); \
|
||||
for (size_t _d = 0; _d < _cap; _d++) { \
|
||||
if ((map)->hashes[_pos] == 0) \
|
||||
break; \
|
||||
if (_HASHMAP_PROBE_DIST((map)->hashes[_pos], _pos, _cap) < _d) \
|
||||
break; \
|
||||
if ((map)->hashes[_pos] == _h && (eq_fn)(&(map)->keys[_pos], &_k, sizeof(_k))) { \
|
||||
(map)->hashes[_pos] = 0; \
|
||||
(map)->count--; \
|
||||
/* Backward-shift: move subsequent displaced entries back. */ \
|
||||
size_t _empty = _pos; \
|
||||
size_t _next = (_pos + 1) & (_cap - 1); \
|
||||
while ((map)->hashes[_next] != 0 && _HASHMAP_PROBE_DIST((map)->hashes[_next], _next, _cap) > 0) { \
|
||||
(map)->keys[_empty] = (map)->keys[_next]; \
|
||||
(map)->values[_empty] = (map)->values[_next]; \
|
||||
(map)->hashes[_empty] = (map)->hashes[_next]; \
|
||||
(map)->hashes[_next] = 0; \
|
||||
_empty = _next; \
|
||||
_next = (_next + 1) & (_cap - 1); \
|
||||
} \
|
||||
_removed = true; \
|
||||
break; \
|
||||
} \
|
||||
_pos = (_pos + 1) & (_cap - 1); \
|
||||
} \
|
||||
} \
|
||||
_removed; \
|
||||
})
|
||||
|
||||
// Iterate over all occupied entries. `idx` is a size_t loop variable.
|
||||
// Access keys and values via (map)->keys[idx] and (map)->values[idx].
|
||||
#define HASHMAP_FOREACH(map, idx) \
|
||||
for (size_t idx = 0; idx < (map)->capacity; idx++) \
|
||||
if ((map)->hashes[idx] != 0)
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/types.h>
|
||||
#include <zinnia/utils.h>
|
||||
|
||||
#define __init __used, __section(".init.text"), __cold
|
||||
#define __initdata __used, __section(".init.data")
|
||||
#define __initdata_sorted(name) __used, __section(".init.data." name)
|
||||
|
||||
struct boot_file {
|
||||
phys_t data;
|
||||
size_t length;
|
||||
char path[128];
|
||||
};
|
||||
|
||||
struct boot_info {
|
||||
char* cmdline;
|
||||
struct phys_mem* mem_map;
|
||||
size_t num_mem_maps;
|
||||
phys_t phys_base;
|
||||
uintptr_t virt_base;
|
||||
uintptr_t hhdm_base;
|
||||
struct boot_file* files;
|
||||
size_t num_files;
|
||||
phys_t rsdp;
|
||||
};
|
||||
|
||||
extern uint8_t __ld_stack_top[];
|
||||
extern uint8_t __ld_stack_bottom[];
|
||||
|
||||
extern phys_t rsdp_addr;
|
||||
|
||||
// Entry point for the kernel after arch-specific setup has finished.
|
||||
void kernel_entry();
|
||||
|
||||
// Initializes the early parts of the kernel.
|
||||
void kernel_early_init();
|
||||
|
||||
[[noreturn]]
|
||||
void kernel_main(struct boot_info* info);
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <uapi/uio.h>
|
||||
|
||||
struct iovec_iter {
|
||||
struct iovec* iovecs;
|
||||
size_t iovecs_len;
|
||||
size_t total_len;
|
||||
size_t total_offset;
|
||||
size_t current_idx;
|
||||
size_t current_offset;
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <bits/irq.h>
|
||||
#include <stdint.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/list.h>
|
||||
|
||||
enum irq_status : uint8_t {
|
||||
IRQ_STATUS_HANDLED,
|
||||
IRQ_STATUS_IGNORED,
|
||||
};
|
||||
|
||||
enum irq_polarity : uint8_t {
|
||||
IRQ_POLARITY_LOW,
|
||||
IRQ_POLARITY_HIGH,
|
||||
};
|
||||
|
||||
enum irq_trigger_mode : uint8_t {
|
||||
IRQ_TRIGGER_EDGE,
|
||||
IRQ_TRIGGER_LEVEL,
|
||||
};
|
||||
|
||||
struct irq_handler {
|
||||
enum irq_status (*handler)(void* self);
|
||||
list_link(struct irq_handler*) next;
|
||||
};
|
||||
|
||||
struct irq_line {
|
||||
int (*set_config)(enum irq_trigger_mode mode, enum irq_polarity polarity);
|
||||
void (*mask)(struct irq_line* self);
|
||||
void (*unmask)(struct irq_line* self);
|
||||
void (*eoi)(struct irq_line* self);
|
||||
|
||||
list_head(struct irq_handler*) handlers;
|
||||
bool is_busy;
|
||||
};
|
||||
|
||||
void irq_line_attach(struct irq_line* self, struct irq_handler* handler);
|
||||
|
||||
struct irq_percpu {
|
||||
uint32_t level;
|
||||
bool in_interrupt;
|
||||
};
|
||||
|
||||
void irq_lock();
|
||||
void irq_unlock();
|
||||
bool irq_set_interrupted(bool is_interrupted);
|
||||
void irq_raise();
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#define list_head(type) \
|
||||
struct { \
|
||||
type _sl_head; \
|
||||
}
|
||||
|
||||
#define list_link(type) \
|
||||
struct { \
|
||||
type _sl_link; \
|
||||
}
|
||||
|
||||
#define list_is_empty(head) ((head)->_sl_head == NULL)
|
||||
#define list_first(head) ((head)->_sl_head)
|
||||
#define list_next(elm, field) ((elm)->field._sl_link)
|
||||
|
||||
#define list_insert_end(slistelm, elm, field) \
|
||||
do { \
|
||||
list_next((elm), field) = list_next((slistelm), field); \
|
||||
list_next((slistelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define list_insert_head(head, elm, field) \
|
||||
do { \
|
||||
list_next((elm), field) = list_first((head)); \
|
||||
list_first((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define list_foreach(var, head, field) for ((var) = list_first((head)); (var); (var) = list_next((var), field))
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <bits/mem.h>
|
||||
#include <stddef.h>
|
||||
#include <zinnia/errno.h>
|
||||
|
||||
enum alloc_flags {
|
||||
ALLOC_NOZERO = 1 << 0, // Don't zero out the allocated memory.
|
||||
ALLOC_MEM32 = 1 << 1, // Allocated memory needs to fit inside 32 bits.
|
||||
ALLOC_MEM20 = 1 << 2, // Allocated memory needs to fit inside 20 bits.
|
||||
};
|
||||
|
||||
enum phys_mem_usage {
|
||||
PHYS_RESERVED,
|
||||
PHYS_USABLE,
|
||||
PHYS_STATIC,
|
||||
PHYS_RECLAIMABLE,
|
||||
};
|
||||
|
||||
struct phys_mem {
|
||||
phys_t address;
|
||||
size_t length;
|
||||
enum phys_mem_usage usage;
|
||||
};
|
||||
|
||||
// Base address of the HHDM.
|
||||
extern uintptr_t mem_hhdm_base;
|
||||
#define HHDM_PTR(paddr) (void*)(mem_hhdm_base + (paddr))
|
||||
|
||||
// Allocates a region of memory which can be smaller than the page size.
|
||||
// Returns `nullptr` if the allocator cannot provide an allocation for the given `length` + `flags`.
|
||||
// Always returns `nullptr` if `length` is 0.
|
||||
void* mem_alloc(size_t length, enum alloc_flags flags);
|
||||
|
||||
// Frees an allocation created by `mem_alloc`.
|
||||
// Passing `nullptr` is a no-op.
|
||||
void mem_free(void* mem);
|
||||
|
||||
errno_t mem_phys_alloc(size_t num_pages, enum alloc_flags flags, phys_t* out);
|
||||
errno_t mem_phys_free(phys_t start, size_t num_pages);
|
||||
|
||||
void mem_init(struct phys_mem* map, size_t length, uintptr_t kernel_virt, phys_t kernel_phys, uintptr_t tmp_hhdm);
|
||||
void slab_init();
|
||||
void mem_phys_bootstrap(struct phys_mem* mem);
|
||||
void mem_phys_init(struct phys_mem* map, size_t length);
|
||||
|
||||
uintptr_t arch_mem_hhdm_addr();
|
||||
uintptr_t arch_vm_pfndb_addr();
|
||||
uintptr_t arch_mem_mapping_addr();
|
||||
size_t arch_mem_page_bits();
|
||||
size_t arch_mem_page_size();
|
||||
size_t arch_mem_level_bits();
|
||||
size_t arch_mem_num_levels();
|
||||
|
||||
static inline size_t mem_high_shift() {
|
||||
return arch_mem_level_bits() * arch_mem_num_levels() + arch_mem_page_bits();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/list.h>
|
||||
#include <zinnia/mem/page.h>
|
||||
#include <zinnia/spin.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct vmo {
|
||||
errno_t (*get_page)(struct vmo* vmo, uintptr_t offset_idx, struct page** out);
|
||||
};
|
||||
|
||||
errno_t vmo_read(struct vmo* obj, uintptr_t offset, void* buf, size_t len, size_t* actual_read);
|
||||
errno_t vmo_write(struct vmo* obj, uintptr_t offset, const void* buf, size_t len, size_t* actual_written);
|
||||
errno_t vmo_copy(
|
||||
struct vmo* target,
|
||||
uintptr_t target_offset,
|
||||
struct vmo* src,
|
||||
uintptr_t src_offset,
|
||||
size_t len,
|
||||
size_t* actual_copied
|
||||
);
|
||||
|
||||
struct pager_ops {
|
||||
errno_t (*get_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page** out);
|
||||
errno_t (*put_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page* page);
|
||||
};
|
||||
|
||||
struct page_list {
|
||||
uintptr_t offset;
|
||||
struct page* value;
|
||||
list_link(struct page_list*) next;
|
||||
};
|
||||
|
||||
struct paged_vmo {
|
||||
struct vmo object;
|
||||
struct pager_ops source;
|
||||
list_head(struct page_list*) cache;
|
||||
struct spinlock lock;
|
||||
};
|
||||
|
||||
errno_t vmo_new_paged(struct pager_ops ops, struct paged_vmo** out);
|
||||
errno_t vmo_new_phys(struct paged_vmo** out);
|
||||
|
||||
// Creates a VMO backed by a specific physical address range (e.g. for MMIO).
|
||||
errno_t vmo_new_phys_range(uintptr_t addr, size_t length, struct vmo** out);
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum page_type : uint32_t {
|
||||
PAGE_PHYS = 0, // Regular physical memory.
|
||||
};
|
||||
|
||||
struct page {
|
||||
enum page_type type;
|
||||
uint32_t flags;
|
||||
size_t refcount;
|
||||
union {
|
||||
struct {
|
||||
struct page* next; // Pointer to the next chunk.
|
||||
size_t count; // Amount of free pages.
|
||||
} freelist;
|
||||
};
|
||||
};
|
||||
static_assert(0x1000 % sizeof(struct page) == 0, "struct must fit cleanly inside a page!");
|
||||
static_assert(sizeof(struct page) <= 64, "struct must be smaller than 64 bytes!");
|
||||
|
||||
void* vm_alloc(size_t length);
|
||||
void vm_free(void* addr, size_t length);
|
||||
|
||||
// Base address of the `struct page` array.
|
||||
extern struct page* vm_pfndb;
|
||||
|
||||
uintptr_t vm_page_addr(struct page* page);
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zinnia/errno.h>
|
||||
|
||||
struct pager {
|
||||
errno_t (*try_get_page)(struct pager* pager, uintptr_t offset);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/mem/alloc.h>
|
||||
#include <zinnia/spin.h>
|
||||
#include <zinnia/utils.h>
|
||||
#include <bits/mmu.h>
|
||||
|
||||
enum pte_flags {
|
||||
PTE_READ = 1 << 0, // Can read from this page.
|
||||
PTE_WRITE = 1 << 1, // Can write to this page.
|
||||
PTE_EXEC = 1 << 2, // Can execute code on this page.
|
||||
PTE_USER = 1 << 3, // Can be accessed by the user.
|
||||
PTE_DIR = 1 << 4, // Is a non-leaf page.
|
||||
};
|
||||
|
||||
enum cache_mode {
|
||||
CACHE_NONE, // None means "nothing explicit" here.
|
||||
CACHE_WRITE_COMBINE,
|
||||
CACHE_WRITE_THROUGH,
|
||||
CACHE_WRITE_BACK,
|
||||
CACHE_MMIO,
|
||||
};
|
||||
|
||||
struct pmap {
|
||||
phys_t root;
|
||||
struct spinlock lock;
|
||||
bool is_user;
|
||||
};
|
||||
|
||||
errno_t pmap_kernel(struct pmap* pt, enum alloc_flags flags);
|
||||
errno_t pmap_user(struct pmap* pt, enum alloc_flags flags);
|
||||
errno_t pmap_map(struct pmap* pt, uintptr_t vaddr, phys_t paddr, enum pte_flags flags, enum cache_mode cache);
|
||||
errno_t pmap_protect(struct pmap* pt, uintptr_t vaddr, enum pte_flags flags);
|
||||
errno_t pmap_unmap(struct pmap* pt, uintptr_t vaddr);
|
||||
void pmap_set(struct pmap* pt);
|
||||
|
||||
pte_t* pmap_pte_resolve(struct pmap* pt, virt_t virt);
|
||||
|
||||
void pte_clear(pte_t* pte);
|
||||
pte_t pte_build(phys_t addr, enum pte_flags flags, enum cache_mode cache);
|
||||
bool pte_is_present(pte_t* pte);
|
||||
bool pte_is_dir(pte_t* pte);
|
||||
phys_t pte_address(pte_t* pte);
|
||||
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct mmio_view {
|
||||
volatile void* base;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
#define _MMIO_REG(x) \
|
||||
typedef struct { \
|
||||
size_t offset; \
|
||||
bool swapped; \
|
||||
} mmio_reg##x;
|
||||
|
||||
_MMIO_REG(8)
|
||||
_MMIO_REG(16)
|
||||
_MMIO_REG(32)
|
||||
_MMIO_REG(64)
|
||||
|
||||
#define bswap_16(x) (uint16_t)x
|
||||
#define bswap_32(x) (uint32_t)x
|
||||
#define bswap_64(x) (uint64_t)x
|
||||
|
||||
#define mmio_load(_view, _reg) \
|
||||
({ \
|
||||
auto _mmio_ptr = _Generic( \
|
||||
(_reg), \
|
||||
mmio_reg8: (volatile uint8_t*)((_view)->base + (_reg).offset), \
|
||||
mmio_reg16: (volatile uint16_t*)((_view)->base + (_reg).offset), \
|
||||
mmio_reg32: (volatile uint32_t*)((_view)->base + (_reg).offset), \
|
||||
mmio_reg64: (volatile uint64_t*)((_view)->base + (_reg).offset) \
|
||||
); \
|
||||
auto _mmio_val = *_mmio_ptr; \
|
||||
if ((_reg).swapped) \
|
||||
_Generic( \
|
||||
(_mmio_val), \
|
||||
char: (void)(_mmio_val), \
|
||||
uint8_t: (void)(_mmio_val), \
|
||||
uint16_t: (_mmio_val = bswap_16(_mmio_val)), \
|
||||
uint32_t: (_mmio_val = bswap_32(_mmio_val)), \
|
||||
uint64_t: (_mmio_val = bswap_64(_mmio_val)) \
|
||||
); \
|
||||
_mmio_val; \
|
||||
})
|
||||
|
||||
#define mmio_store(_view, _reg, _val) \
|
||||
({ \
|
||||
auto _mmio_val = _val; \
|
||||
if ((_reg).swapped) \
|
||||
_Generic( \
|
||||
(_mmio_val), \
|
||||
char: (void)(_mmio_val), \
|
||||
uint8_t: (void)(_mmio_val), \
|
||||
uint16_t: (_mmio_val = bswap_16(_mmio_val)), \
|
||||
uint32_t: (_mmio_val = bswap_32(_mmio_val)), \
|
||||
uint64_t: (_mmio_val = bswap_64(_mmio_val)) \
|
||||
); \
|
||||
auto _mmio_ptr = _Generic( \
|
||||
(_reg), \
|
||||
mmio_reg8: (volatile uint8_t*)((_view)->base + (_reg).offset), \
|
||||
mmio_reg16: (volatile uint16_t*)((_view)->base + (_reg).offset), \
|
||||
mmio_reg32: (volatile uint32_t*)((_view)->base + (_reg).offset), \
|
||||
mmio_reg64: (volatile uint64_t*)((_view)->base + (_reg).offset) \
|
||||
); \
|
||||
*_mmio_ptr = _mmio_val; \
|
||||
})
|
||||
|
||||
struct mmio_view mmio_new(phys_t addr, size_t length);
|
||||
void mmio_free(struct mmio_view* view);
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
struct task;
|
||||
|
||||
struct mutex {
|
||||
struct task* owner;
|
||||
bool flag;
|
||||
};
|
||||
|
||||
void mutex_lock(struct mutex* mutex);
|
||||
void mutex_unlock(struct mutex* mutex);
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <zinnia/compiler.h>
|
||||
|
||||
// Stop all execution upon panic.
|
||||
[[noreturn, __format(printf, 1, 2)]]
|
||||
void panic(const char* msg, ...);
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <bits/percpu.h>
|
||||
#include <stddef.h>
|
||||
#include <zinnia/compiler.h>
|
||||
#include <zinnia/irq.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/usercopy.h>
|
||||
|
||||
ASSERT_TYPE(struct arch_percpu);
|
||||
|
||||
// CPU-relative information.
|
||||
struct percpu {
|
||||
struct percpu* self; // A pointer to this structure.
|
||||
size_t id; // The virtual ID of this CPU.
|
||||
bool online; // Whether this CPU is initialized and active.
|
||||
uintptr_t kernel_stack; // The kernel mode stack.
|
||||
uintptr_t user_stack; // The user mode stack.
|
||||
struct arch_percpu arch; // Architecture-specific fields.
|
||||
struct irq_percpu irq; // IRQ information.
|
||||
struct sched_percpu sched; // Scheduler information.
|
||||
};
|
||||
|
||||
// Per-CPU data for the bootstrap processor.
|
||||
extern struct percpu percpu_bsp;
|
||||
|
||||
// Allocates a block of memory for a new CPU.
|
||||
struct percpu* percpu_new();
|
||||
|
||||
// Gets the per-CPU data on the current CPU.
|
||||
static inline struct percpu* percpu_get() {
|
||||
return arch_percpu_get();
|
||||
}
|
||||
|
||||
// Initializes the bootstrap processor.
|
||||
static inline void percpu_bsp_init() {
|
||||
arch_percpu_bsp_init();
|
||||
}
|
||||
|
||||
// Initializes all processors.
|
||||
static inline void percpu_init() {
|
||||
arch_percpu_init();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <uapi/poll.h>
|
||||
|
||||
enum poll_flags : uint16_t {
|
||||
POLLIN = __POLLIN,
|
||||
POLLOUT = __POLLOUT,
|
||||
POLLPRI = __POLLPRI,
|
||||
POLLHUP = __POLLHUP,
|
||||
POLLERR = __POLLERR,
|
||||
POLLRDHUP = __POLLRDHUP,
|
||||
POLLNVAL = __POLLNVAL,
|
||||
POLLRDNORM = __POLLRDNORM,
|
||||
POLLRDBAND = __POLLRDBAND,
|
||||
POLLWRNORM = __POLLWRNORM,
|
||||
POLLWRBAND = __POLLWRBAND,
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/compiler.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
[[__format(printf, 1, 2)]]
|
||||
void printf(const char* message, ...);
|
||||
|
||||
void kvprintf(const char* message, va_list args);
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/utils.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct refcount {
|
||||
size_t count;
|
||||
};
|
||||
|
||||
static inline void refcount_inc(struct refcount* rc) {
|
||||
rc->count++;
|
||||
}
|
||||
|
||||
struct foo {
|
||||
int a;
|
||||
struct refcount rc;
|
||||
};
|
||||
|
||||
static void do_foo() {
|
||||
struct foo f = {.a = 4, .rc = {0}};
|
||||
|
||||
refcount_inc(&f.rc);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/init.h>
|
||||
#include <zinnia/tailq.h>
|
||||
#include <zinnia/types.h>
|
||||
#include <zinnia/wait.h>
|
||||
#include <bits/sched.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
ASSERT_TYPE(struct arch_context);
|
||||
ASSERT_TYPE(struct arch_task_context);
|
||||
|
||||
enum task_state {
|
||||
TASK_STATE_RUNNING, // Task is active and running.
|
||||
TASK_STATE_READY, // Task is active, but not currently scheduled.
|
||||
TASK_STATE_BLOCKED, // Task is waiting on another object.
|
||||
TASK_STATE_DEAD, // Task is killed.
|
||||
};
|
||||
|
||||
#define TASK_NAME_MAX 128
|
||||
#define KERNEL_STACK_SIZE 0x4000
|
||||
|
||||
// A task is the smallest unit of the scheduler.
|
||||
struct task {
|
||||
size_t id;
|
||||
char name[TASK_NAME_MAX];
|
||||
struct vas* space;
|
||||
struct namespace* namespace;
|
||||
enum task_state state;
|
||||
struct arch_task_context context;
|
||||
struct usercopy_region* usercopy_region;
|
||||
uintptr_t kernel_stack;
|
||||
uintptr_t user_stack;
|
||||
size_t time_slice;
|
||||
int8_t priority;
|
||||
|
||||
tailq_link(struct task) next;
|
||||
};
|
||||
|
||||
// Per-CPU data for scheduling.
|
||||
struct sched_percpu {
|
||||
struct task* current;
|
||||
struct task* idle_task;
|
||||
size_t preempt_level;
|
||||
tailq_head(struct task) run_queue;
|
||||
};
|
||||
|
||||
// Blocks the current task on the given wait queue.
|
||||
// The caller must NOT hold any spinlocks. Returns after the task is woken.
|
||||
void sched_block(struct sched_percpu* sched, struct wait_queue* wq);
|
||||
|
||||
// Wakes the first task blocked on the given wait queue, if any.
|
||||
void sched_wake(struct sched_percpu* sched, struct wait_queue* wq);
|
||||
|
||||
// Wakes all tasks blocked on the given wait queue.
|
||||
void sched_wake_all(struct sched_percpu* sched, struct wait_queue* wq);
|
||||
|
||||
typedef void (*task_fn_t)(uintptr_t arg0);
|
||||
|
||||
errno_t task_create(
|
||||
const char* name,
|
||||
struct vas* space,
|
||||
struct namespace* ns,
|
||||
task_fn_t entry,
|
||||
uintptr_t arg0,
|
||||
struct task** out
|
||||
);
|
||||
[[noreturn]]
|
||||
void task_entry(task_fn_t entry, uintptr_t arg0);
|
||||
|
||||
void sched_init(struct sched_percpu* sched);
|
||||
void sched_reschedule(struct sched_percpu* sched);
|
||||
void sched_yield(struct sched_percpu* sched);
|
||||
void sched_add_task(struct sched_percpu* sched, struct task* task);
|
||||
[[noreturn]]
|
||||
void sched_to_user(uintptr_t ctx);
|
||||
[[noreturn]]
|
||||
void sched_to_user_context(uintptr_t ctx);
|
||||
|
||||
// Info block for sched_to_user. Heap-allocated by the caller, freed by sched_to_user_arg.
|
||||
struct task_start_info {
|
||||
uintptr_t ip;
|
||||
uintptr_t sp;
|
||||
uintptr_t arg;
|
||||
};
|
||||
|
||||
void arch_sched_preempt_disable();
|
||||
bool arch_sched_preempt_enable();
|
||||
void arch_sched_switch(struct task* from, struct task* to);
|
||||
errno_t arch_task_init(
|
||||
struct arch_task_context* context,
|
||||
void* entry,
|
||||
uintptr_t arg0,
|
||||
uintptr_t stack_start,
|
||||
bool is_user
|
||||
);
|
||||
[[noreturn]]
|
||||
void arch_sched_jump_to_context(struct arch_context* context);
|
||||
[[noreturn]]
|
||||
void arch_sched_jump_to_user(uintptr_t ip, uintptr_t sp, uintptr_t arg);
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Busy-waits in a loop until the lock is freed.
|
||||
// Does not put the CPU to sleep.
|
||||
struct spinlock {
|
||||
uint32_t owner;
|
||||
uint32_t next;
|
||||
};
|
||||
|
||||
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
|
||||
void spin_lock(struct spinlock* spin);
|
||||
|
||||
// Unlocks a spinlock.
|
||||
void spin_unlock(struct spinlock* spin);
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/sched.h>
|
||||
|
||||
typedef void (*syscall_fn_t)(struct arch_context* ctx);
|
||||
|
||||
void syscall_dispatch(struct arch_context* ctx);
|
||||
|
||||
#define __SYSCALL_DEFINE(_idx, name) void syscall_##name(struct arch_context* ctx);
|
||||
#include <uapi/syscall_numbers.h>
|
||||
#undef __SYSCALL_DEFINE
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#define tailq_head(type) \
|
||||
struct { \
|
||||
type* tqh_first; \
|
||||
type** tqh_last; \
|
||||
}
|
||||
|
||||
#define tailq_link(type) \
|
||||
struct { \
|
||||
type* tqe_next; \
|
||||
type** tqe_prev; \
|
||||
}
|
||||
|
||||
#define tailq_init(head) \
|
||||
do { \
|
||||
(head)->tqh_first = nullptr; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define tailq_first(head) ((head)->tqh_first)
|
||||
|
||||
#define tailq_next(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define tailq_empty(head) (tailq_first(head) == nullptr)
|
||||
|
||||
#define tailq_insert_tail(head, elm, field) \
|
||||
do { \
|
||||
(elm)->field.tqe_next = nullptr; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define tailq_insert_head(head, elm, field) \
|
||||
do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != nullptr) \
|
||||
(head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define tailq_remove(head, elm, field) \
|
||||
do { \
|
||||
if (((elm)->field.tqe_next) != nullptr) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <uapi/time.h>
|
||||
|
||||
struct timespec time_from_sec(uint64_t sec);
|
||||
struct timespec time_from_nano(uint64_t nsec);
|
||||
struct timespec time_from_milli(uint64_t msec);
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <bits/types.h>
|
||||
#include <zinnia/utils.h>
|
||||
|
||||
ASSERT_TYPE(phys_t);
|
||||
ASSERT_TYPE(uintptr_t);
|
||||
ASSERT_TYPE(reg_t);
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <zinnia/compiler.h>
|
||||
|
||||
struct usercopy_region {
|
||||
void (*start_ip)();
|
||||
void (*end_ip)();
|
||||
void (*fault_ip)();
|
||||
};
|
||||
|
||||
// Copies a block of data from user to kernel memory.
|
||||
bool usercopy_read(void* dst, const __user void* src, size_t len);
|
||||
|
||||
// Copies a block of data from kernel to user memory.
|
||||
bool usercopy_write(__user void* dst, const void* src, size_t len);
|
||||
|
||||
// Performs a strlen() on a user string.
|
||||
bool usercopy_strlen(const __user char* str, size_t max, size_t* len);
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
#define ROUND_UP(value, to) (((value) + ((to) - 1)) / (to))
|
||||
#define ALIGN_DOWN(value, align) (((value) / (align)) * (align))
|
||||
#define ALIGN_UP(value, align) (ROUND_UP(value, align) * align)
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define BIT_TEST(value, bit) (((value) & (1 << bit)) == (1 << bit))
|
||||
|
||||
#if defined(__has_builtin)
|
||||
#if __has_builtin(__builtin_types_compatible_p)
|
||||
// Get pointer to parent object given pointer to a struct or union member.
|
||||
#define containerof(ptr, type, member) \
|
||||
({ \
|
||||
static_assert( \
|
||||
__builtin_types_compatible_p(typeof(*(ptr)), typeof(((type*)0)->member)), \
|
||||
"Incompatible types for containerof" \
|
||||
); \
|
||||
(type*)((size_t)(ptr) - offsetof(type, member)); \
|
||||
})
|
||||
#endif
|
||||
#endif
|
||||
#ifndef containerof
|
||||
// Get pointer to parent object given pointer to a struct or union member.
|
||||
#define containerof(ptr, type, member) (type*)((size_t)(ptr) - offsetof(type, member))
|
||||
#endif
|
||||
|
||||
#define CONCAT(A, B) _CONCAT(A, B)
|
||||
#define _CONCAT(A, B) A##B
|
||||
|
||||
// Creates a unique identifier for a compilation unit.
|
||||
#define UNIQUE_IDENT(ident) CONCAT(__unique_##ident, __COUNTER__)
|
||||
|
||||
// Ensures that a type is properly defined at this point.
|
||||
// This is used to ensure that e.g. architecture-specific structures are defined.
|
||||
#define ASSERT_TYPE(type) static_assert(sizeof(type) == sizeof(type))
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/mem/alloc.h>
|
||||
#include <zinnia/mem/object.h>
|
||||
#include <zinnia/mem/pmap.h>
|
||||
#include <zinnia/mutex.h>
|
||||
|
||||
// Virtual address space.
|
||||
struct vas {
|
||||
// Architecture-specific virtual memory map implementation.
|
||||
struct pmap pmap;
|
||||
};
|
||||
|
||||
// Try to create a new, empty virtual address space.
|
||||
errno_t vma_new(struct vas** out);
|
||||
|
||||
// Delete a virtual address space.
|
||||
void vma_delete(struct vas* vm);
|
||||
|
||||
errno_t vma_map_vmo(struct vas* vm, struct vmo* vmo, uintptr_t addr, size_t len, enum flags, uintptr_t vmo_offset);
|
||||
|
||||
// Remove any mappings in the given address range.
|
||||
errno_t vma_unmap(struct vas* vm, uintptr_t vaddr, size_t size);
|
||||
|
||||
// Change the protection of an existing mapping.
|
||||
errno_t vma_protect(struct vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags);
|
||||
|
||||
// Try to handle a page fault.
|
||||
bool vma_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type);
|
||||
|
||||
extern struct vas kernel_vas;
|
||||
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h> // IWYU pragma: keep
|
||||
#include <string.h> // IWYU pragma: keep
|
||||
#include <zinnia/alloc.h>
|
||||
#include <zinnia/errno.h>
|
||||
|
||||
#define vec(T) \
|
||||
struct { \
|
||||
T* data; \
|
||||
size_t length; \
|
||||
size_t capacity; \
|
||||
}
|
||||
|
||||
#define vec_init(vec) \
|
||||
do { \
|
||||
(vec)->data = nullptr; \
|
||||
(vec)->length = 0; \
|
||||
(vec)->capacity = 0; \
|
||||
} while (0)
|
||||
|
||||
#define vec_destroy(vec) \
|
||||
do { \
|
||||
mem_free((vec)->data); \
|
||||
(vec)->data = nullptr; \
|
||||
(vec)->length = 0; \
|
||||
(vec)->capacity = 0; \
|
||||
} while (0)
|
||||
|
||||
#define vec_length(vec) ((vec)->length)
|
||||
#define vec_capacity(vec) ((vec)->capacity)
|
||||
#define vec_empty(vec) ((vec)->length == 0)
|
||||
#define vec_at(vec, i) ((vec)->data[i])
|
||||
|
||||
// Internal: grow to at least `needed` capacity.
|
||||
#define _vec_grow(vec, needed) \
|
||||
do { \
|
||||
size_t _new_cap = (vec)->capacity == 0 ? 8 : (vec)->capacity; \
|
||||
while (_new_cap < (needed)) \
|
||||
_new_cap *= 2; \
|
||||
typeof((vec)->data) _new = mem_alloc(_new_cap * sizeof(*(vec)->data), ALLOC_NOZERO); \
|
||||
if (_new != nullptr && (vec)->length > 0) \
|
||||
memcpy(_new, (vec)->data, (vec)->length * sizeof(*(vec)->data)); \
|
||||
mem_free((vec)->data); \
|
||||
(vec)->data = _new; \
|
||||
(vec)->capacity = _new_cap; \
|
||||
} while (0)
|
||||
|
||||
// Append an element. Returns 0 or ENOMEM.
|
||||
#define vec_push(vec, val) \
|
||||
({ \
|
||||
errno_t _status = 0; \
|
||||
if ((vec)->length >= (vec)->capacity) { \
|
||||
_vec_grow(vec, (vec)->length + 1); \
|
||||
if ((vec)->data == nullptr) \
|
||||
_status = ENOMEM; \
|
||||
} \
|
||||
if (_status == 0) \
|
||||
(vec)->data[(vec)->length++] = (val); \
|
||||
_status; \
|
||||
})
|
||||
|
||||
// Remove and return the last element. Undefined if empty.
|
||||
#define vec_pop(vec) ((vec)->data[--(vec)->length])
|
||||
|
||||
// Insert at index, shifting subsequent elements right. Returns 0 or ENOMEM.
|
||||
#define vec_insert(vec, i, val) \
|
||||
({ \
|
||||
errno_t _status = 0; \
|
||||
size_t _idx = (i); \
|
||||
if ((vec)->length >= (vec)->capacity) { \
|
||||
_vec_grow(vec, (vec)->length + 1); \
|
||||
if ((vec)->data == nullptr) \
|
||||
_status = ENOMEM; \
|
||||
} \
|
||||
if (_status == 0) { \
|
||||
memmove(&(vec)->data[_idx + 1], &(vec)->data[_idx], ((vec)->length - _idx) * sizeof(*(vec)->data)); \
|
||||
(vec)->data[_idx] = (val); \
|
||||
(vec)->length++; \
|
||||
} \
|
||||
_status; \
|
||||
})
|
||||
|
||||
// Remove element at index, shifting subsequent elements left.
|
||||
#define vec_remove(vec, i) \
|
||||
do { \
|
||||
size_t _idx = (i); \
|
||||
(vec)->length--; \
|
||||
if (_idx < (vec)->length) \
|
||||
memmove(&(vec)->data[_idx], &(vec)->data[_idx + 1], ((vec)->length - _idx) * sizeof(*(vec)->data)); \
|
||||
} while (0)
|
||||
|
||||
// Remove element at index by swapping with the last element (O(1), unordered).
|
||||
#define vec_swap_remove(vec, i) \
|
||||
do { \
|
||||
size_t _idx = (i); \
|
||||
(vec)->length--; \
|
||||
if (_idx < (vec)->length) \
|
||||
(vec)->data[_idx] = (vec)->data[(vec)->length]; \
|
||||
} while (0)
|
||||
|
||||
// Clear all elements without freeing memory.
|
||||
#define vec_clear(vec) ((vec)->length = 0)
|
||||
|
||||
#define vec_foreach(vec, idx) for (size_t idx = 0; idx < (vec)->length; idx++)
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <uapi/fcntl.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/iovec.h>
|
||||
#include <zinnia/refcount.h>
|
||||
#include <zinnia/string.h>
|
||||
|
||||
struct vfs_mount {
|
||||
struct refcount rc;
|
||||
};
|
||||
|
||||
struct vfs_entry {
|
||||
struct refcount rc;
|
||||
};
|
||||
|
||||
struct vfs_path {
|
||||
struct vfs_mount* mount;
|
||||
struct vfs_entry* entry;
|
||||
};
|
||||
|
||||
struct vfs_node;
|
||||
struct vfs_regular_ops {
|
||||
errno_t (*read)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_read);
|
||||
errno_t (*write)(struct vfs_node* file, struct iovec_iter* buffer, uint64_t offset, ssize_t* out_written);
|
||||
errno_t (*devctl)(struct vfs_node* file, );
|
||||
};
|
||||
|
||||
struct vfs_node {
|
||||
struct refcount rc;
|
||||
const struct vfs_regular_ops* ops;
|
||||
struct vfs_vnode* vnode;
|
||||
struct vfs_path path;
|
||||
struct string abs_path;
|
||||
bool has_path;
|
||||
};
|
||||
|
||||
enum open_flags : uint32_t {
|
||||
O_RDONLY = __O_RDONLY,
|
||||
O_WRONLY = __O_WRONLY,
|
||||
O_RDWR = __O_RDWR,
|
||||
O_CREAT = __O_CREAT,
|
||||
O_EXCL = __O_EXCL,
|
||||
O_NOCTTY = __O_NOCTTY,
|
||||
O_TRUNC = __O_TRUNC,
|
||||
O_APPEND = __O_APPEND,
|
||||
O_NONBLOCK = __O_NONBLOCK,
|
||||
O_DSYNC = __O_DSYNC,
|
||||
O_ASYNC = __O_ASYNC,
|
||||
O_DIRECT = __O_DIRECT,
|
||||
O_LARGEFILE = __O_LARGEFILE,
|
||||
O_DIRECTORY = __O_DIRECTORY,
|
||||
O_NOFOLLOW = __O_NOFOLLOW,
|
||||
O_NOATIME = __O_NOATIME,
|
||||
O_CLOEXEC = __O_CLOEXEC,
|
||||
O_PATH = __O_PATH,
|
||||
O_TMPFILE = __O_TMPFILE,
|
||||
O_SYNC = __O_SYNC,
|
||||
O_RSYNC = __O_RSYNC,
|
||||
O_EXEC = __O_EXEC,
|
||||
O_SEARCH = __O_SEARCH,
|
||||
O_ACCMODE = __O_ACCMODE,
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/spin.h>
|
||||
#include <zinnia/tailq.h>
|
||||
|
||||
struct task;
|
||||
|
||||
// A queue of tasks waiting for an event.
|
||||
struct wait_queue {
|
||||
tailq_head(struct task) waiters;
|
||||
struct spinlock lock;
|
||||
};
|
||||
|
||||
void wait_queue_init(struct wait_queue* wq);
|
||||
Reference in New Issue
Block a user