This commit is contained in:
2026-07-20 01:53:04 +02:00
commit e71245c082
149 changed files with 8571 additions and 0 deletions
+25
View File
@@ -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
+7
View File
@@ -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)
+36
View File
@@ -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)
+7
View File
@@ -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()
+26
View File
@@ -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__
+4
View File
@@ -0,0 +1,4 @@
#pragma once
long atol(const char* str, int base);
unsigned long atolu(const char* str, int base);
+14
View File
@@ -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);
+10
View File
@@ -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
+39
View File
@@ -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
+140
View File
@@ -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
+43
View File
@@ -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
+22
View File
@@ -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
+13
View File
@@ -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
+27
View File
@@ -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
+51
View File
@@ -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
+151
View File
@@ -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
+47
View File
@@ -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
+24
View File
@@ -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
+12
View File
@@ -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
+14
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include <uapi/archctl.h>
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include <zinnia/elf.h>
+7
View File
@@ -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();
+12
View File
@@ -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();
+9
View File
@@ -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);
+23
View File
@@ -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);
+46
View File
@@ -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);
+27
View File
@@ -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
+27
View File
@@ -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)
+340
View File
@@ -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;
}
+142
View File
@@ -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;
+17
View File
@@ -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);
+223
View File
@@ -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)
+43
View File
@@ -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);
+12
View File
@@ -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;
};
+48
View File
@@ -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();
+29
View File
@@ -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))
+57
View File
@@ -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();
}
+47
View File
@@ -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);
+30
View File
@@ -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);
+8
View File
@@ -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);
};
+44
View File
@@ -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);
+71
View File
@@ -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);
+11
View File
@@ -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);
+6
View File
@@ -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, ...);
+43
View File
@@ -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();
}
+18
View File
@@ -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,
};
+9
View File
@@ -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);
+23
View File
@@ -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);
}
+102
View File
@@ -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);
+16
View File
@@ -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);
+11
View File
@@ -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
+52
View File
@@ -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)
+7
View File
@@ -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);
+8
View File
@@ -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);
+19
View File
@@ -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);
+40
View File
@@ -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))
+32
View File
@@ -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;
+105
View File
@@ -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++)
+65
View File
@@ -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,
};
+14
View File
@@ -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);