Skip to content

Commit

Permalink
kernel: add linux compatibility layer
Browse files Browse the repository at this point in the history
  • Loading branch information
willdurand committed Mar 3, 2022
1 parent a8452c0 commit c520edb
Show file tree
Hide file tree
Showing 22 changed files with 742 additions and 49 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ ifeq ($(CONFIG_USE_FAKE_CLOCK), 1)
libk_c_files += $(kernel_src_dir)/time/fake_clock.c
endif

ifeq ($(CONFIG_LINUX_COMPAT), 1)
KERNEL_CONFIG += -DCONFIG_LINUX_COMPAT
LIBC_CONFIG += -DCONFIG_LINUX_COMPAT
endif

# This file exists in a Docker container because we copy it in `Dockerfile`.
in_docker = $(wildcard /tmp/install-linux-deps)
ifneq ($(in_docker),)
Expand Down Expand Up @@ -432,6 +437,7 @@ what: ## display some information about the current configuration
echo "OS_NAME : $(OS_NAME)"
echo "ARCH : $(ARCH)"
echo ""
echo "CONFIG_LINUX_COMPAT = $(CONFIG_LINUX_COMPAT)"
echo "CONFIG_SEMIHOSTING = $(CONFIG_SEMIHOSTING)"
echo "CONFIG_USE_DLMALLOC = $(CONFIG_USE_DLMALLOC)"
echo "CONFIG_USE_FAKE_CLOCK = $(CONFIG_USE_FAKE_CLOCK)"
Expand Down
2 changes: 2 additions & 0 deletions Makefile-cfg.include
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LLVM_SUFFIX ?=

# When set to 1, enable the Undefined Behavior SANitizer.
UBSAN ?=
# When set to 1, enable Linux (binary) compatibility.
CONFIG_LINUX_COMPAT ?=
# When set to 1, enable semi-hosting mode (QEMU, mainly).
CONFIG_SEMIHOSTING ?=
# When set to 1, use dlmalloc for malloc/free/realloc (instead of liballoc).
Expand Down
1 change: 1 addition & 0 deletions data/initrd/etc/hosts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
140.82.121.4 github
1 change: 1 addition & 0 deletions data/initrd/etc/passwd
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root:x:0:0::/:none
8 changes: 8 additions & 0 deletions include/kernel/proc/descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
#ifndef PROC_DESCRIPTOR_H
#define PROC_DESCRIPTOR_H

#include <arpa/inet.h>
#include <fs/vfs.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>

#define STDIN 0
Expand All @@ -23,6 +25,8 @@ typedef struct descriptor
uint32_t type;
uint32_t protocol;
uint16_t port;
struct sockaddr_in addr;
socklen_t addr_len;
} descriptor_t;

/**
Expand Down Expand Up @@ -82,4 +86,8 @@ int descriptor_udp_lookup(uint16_t port);
*/
bool is_protocol_supported(uint32_t type, uint32_t protocol);

void duplicate_descriptor(int oldfd, int newfd);

int descriptor_raw_lookup(uint32_t protocol, in_addr_t src_addr);

#endif
95 changes: 95 additions & 0 deletions include/libc/sys/linux_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/syscalls.md
#ifndef SYS_LINUX_COMPAT_H
#define SYS_LINUX_COMPAT_H

#ifdef __x86_64__

#define SYSCALL_READ 0
#define SYSCALL_WRITE 1
#define SYSCALL_OPEN 2
#define SYSCALL_CLOSE 3
#define SYSCALL_FSTAT 5
#define SYSCALL_LSEEK 8
#define SYSCALL_BRK 12
#define SYSCALL_IOCTL 16
#define SYSCALL_WRITEV 20
#define SYSCALL_DUP2 33
#define SYSCALL_GETPID 39
#define SYSCALL_SOCKET 41
#define SYSCALL_SENDTO 44
#define SYSCALL_RECVFROM 45
#define SYSCALL_EXECV 49
#define SYSCALL_EXIT 60
#define SYSCALL_GETTIMEOFDAY 96
#define SYSCALL_GETEUID 107
#define SYSCALL_ARCH_PRCTL 158
#define SYSCALL_REBOOT 169
#define SYSCALL_SET_TID_ADDR 218
#define SYSCALL_EXIT_GROUP 231
#define SYSCALL_OPENAT 257

#elif __arm__

#define SYSCALL_EXIT 1
#define SYSCALL_READ 3
#define SYSCALL_WRITE 4
#define SYSCALL_OPEN 5
#define SYSCALL_CLOSE 6
#define SYSCALL_EXECV 11
#define SYSCALL_LSEEK 19
#define SYSCALL_GETPID 20
#define SYSCALL_BRK 45
#define SYSCALL_GETEUID 49
#define SYSCALL_IOCTL 54
#define SYSCALL_DUP2 63
#define SYSCALL_GETTIMEOFDAY 78
#define SYSCALL_REBOOT 88
#define SYSCALL_FSTAT 108
#define SYSCALL_WRITEV 146
#define SYSCALL_EXIT_GROUP 248
#define SYSCALL_SET_TID_ADDR 256
#define SYSCALL_SOCKET 281
#define SYSCALL_SENDTO 290
#define SYSCALL_RECVFROM 292
#define SYSCALL_OPENAT 322

// Not available on AArch32:
//
// - SYSCALL_ARCH_PRCTL

#elif __aarch64__

#define SYSCALL_IOCTL 29
#define SYSCALL_OPENAT 56
#define SYSCALL_CLOSE 57
#define SYSCALL_LSEEK 62
#define SYSCALL_READ 63
#define SYSCALL_WRITE 64
#define SYSCALL_WRITEV 66
#define SYSCALL_FSTAT 80
#define SYSCALL_EXIT 93
#define SYSCALL_EXIT_GROUP 94
#define SYSCALL_SET_TID_ADDR 96
#define SYSCALL_REBOOT 142
#define SYSCALL_GETTIMEOFDAY 169
#define SYSCALL_GETPID 172
#define SYSCALL_GETEUID 175
#define SYSCALL_SOCKET 198
#define SYSCALL_SENDTO 206
#define SYSCALL_RECVFROM 207
#define SYSCALL_BRK 214
#define SYSCALL_EXECV 221

// Not available on AArch64:
//
// - SYSCALL_OPEN
// - SYSCALL_DUP2
// - SYSCALL_ARCH_PRCTL

#endif

// Not available outside ArvernOS:
#define SYSCALL_TEST 348
#define SYSCALL_GETHOSTBYNAME2 349

#endif
5 changes: 4 additions & 1 deletion include/libc/sys/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
#define AF_INET 2
// Types
#define SOCK_DGRAM 2
#define SOCK_RAW 3
// Protocols
#define IPPROTO_UDP 17
#define IPPROTO_IP 0
#define IPPROTO_ICMP 1
#define IPPROTO_UDP 17

typedef uint16_t sa_family_t;

Expand Down
8 changes: 8 additions & 0 deletions include/libc/sys/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
#include <sys/time.h>
#include <sys/types.h>

#ifdef CONFIG_LINUX_COMPAT

#include <sys/linux_compat.h>

#else

#define SYSCALL_TEST 1
#define SYSCALL_WRITE 2
#define SYSCALL_READ 3
Expand All @@ -29,6 +35,8 @@
#define SYSCALL_EXIT 16
#define SYSCALL_OPENAT 17

#endif // CONFIG_LINUX_COMPAT

#define SYSCALL_SET_ERRNO() \
if (retval < 0) { \
errno = -retval; \
Expand Down
3 changes: 2 additions & 1 deletion src/kernel/arch/x86_64/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ QEMU = qemu-system-x86_64
# Options for the different tools
###############################################################################

QEMU_OPTIONS += -m 512M
QEMU_OPTIONS += -m 512M -cpu IvyBridge
QEMU_OPTIONS += -serial file:$(log_file)
QEMU_OPTIONS += -netdev user,id=u1,ipv6=off,dhcpstart=10.0.2.20
QEMU_OPTIONS += -device rtl8139,netdev=u1
Expand All @@ -51,6 +51,7 @@ libk_c_files += $(wildcard $(arch_src)/drivers/*.c)
libk_c_files += $(wildcard $(arch_src)/fs/dev/*.c)
libk_c_files += $(wildcard $(arch_src)/fs/proc/*.c)
libk_c_files += $(wildcard $(arch_src)/mmu/*.c)
libk_c_files += $(wildcard $(arch_src)/proc/*.c)
libk_c_files += $(wildcard $(arch_src)/sys/*.c)
libk_asm_files += $(wildcard $(arch_src)/asm/*.asm)
libc_test_files += $(patsubst $(tests_dir)/%.c, %, $(shell find $(tests_dir)/libc -name '*.c'))
Expand Down
23 changes: 23 additions & 0 deletions src/kernel/arch/x86_64/asm/boot.asm
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,34 @@ start:
; load the 64-bit GDT
lgdt [gdt64.pointer]

call enable_sse

mov eax, cr4
or eax, 1 << 16
mov cr4, eax

jmp gdt64.kernel_code:long_mode_start

; Should not be reached.
hlt

enable_sse:
mov eax, 0x1 ; check for SSE
cpuid
test edx, 1 << 25
jz .no_sse ; after this, SSE can be enabled
mov eax, cr0
and ax, 0xFFFB ; clear coprocessor emulation CR0.EM
or ax, 0x2 ; set coprocessor monitoring CR0.MP
mov cr0, eax
mov eax, cr4
or ax, 3 << 9 ; set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time
mov cr4, eax
ret

.no_sse:
ret

; -----------------------------------------------------------------------------
; make sure the kernel was really loaded by a Multiboot compliant bootloader
%define MULTIBOOT2_MAGIC_VALUE 0x36d76289
Expand Down
138 changes: 138 additions & 0 deletions src/kernel/arch/x86_64/proc/process.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#include "process.h"

#include <proc/logging.h>
#include <stdlib.h>
#include <string.h>

#define PUSH_TO_STACK(stack, type, value) \
stack = (char*)stack - sizeof(type); \
*((type*)stack) = value

static process_t* current_process = NULL;

process_t* process_create_root()
{
current_process = (process_t*)malloc(sizeof(process_t));
current_process->pid = 0;

return current_process;
}

process_t* process_get_current()
{
return current_process;
}

process_t* process_exec(uint8_t* image, const char* name, char* const argv[])
{
PROC_DEBUG("image=%p name=%s", image, name);

if (current_process == NULL) {
current_process = process_create_root();
} else {
elf_unload(current_process->elf);
free(current_process->elf);
// Free the current name as we'll update it right after.
free(current_process->name);
// Give a new PID to the current process.
current_process->pid++;
}

// Load ELF in current process.
// TODO: Handle the case where the image isn't a valid/supported ELF.
elf_header_t* elf = elf_load(image);
current_process->elf = elf;

// Set current process name.
current_process->name = strdup(name);

memset(current_process->user_heap, 0, USER_HEAP_SIZE);
current_process->user_brk = (uintptr_t)current_process->user_heap;

// Set up user stack.
memset(current_process->user_stack, 0, USER_STACK_SIZE);

// User stack:
//
// +--------+ user_stack[0]
// | |
// | |
// ^ | |
// | | |
// sp --->| | user_stack[USER_STACK_TOP]
// | |
// | |
// | |
// | |
// buf --->| | user_stack[USER_STACK_BUF]
// | | |
// v | |
// | |
// | |
// +--------+ user_stack[USER_STACK_SIZE]
//
void* stack = (void*)&current_process->user_stack[USER_STACK_TOP];
char* buf = (char*)&current_process->user_stack[USER_STACK_BUF];

size_t off = 0;

// auxv
uint8_t rand_bytes[16] = {
0xaa, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0,
0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee,
};
memcpy(&buf[off], rand_bytes, sizeof(rand_bytes));
char* rand_ptr = &buf[off];
off += sizeof(rand_bytes);

// aux: AT_NULL
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL);
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL);
// aux: AT_RANDOM
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)rand_ptr);
PUSH_TO_STACK(stack, uint64_t, 25);
// aux: AT_PAGESZ
PUSH_TO_STACK(stack, uint64_t, 4096);
PUSH_TO_STACK(stack, uint64_t, 6);
// aux: AT_PHNUM
PUSH_TO_STACK(stack, uint64_t, elf->ph_num);
PUSH_TO_STACK(stack, uint64_t, 5);
// aux: AT_PHENT
PUSH_TO_STACK(stack, uint64_t, elf->ph_size);
PUSH_TO_STACK(stack, uint64_t, 4);
// aux: AT_PHDR
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)image + elf->ph_offset);
PUSH_TO_STACK(stack, uint64_t, 3);

// envp
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL);

// We need both `argc` and `argv` so we start by retrieving `argc`.
uint64_t argc = 0;
while (argv[argc]) {
argc++;
}

// argv
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL);

for (int i = argc - 1; i >= 0; i--) {
size_t len = strlen(argv[i]);
// Copy argv[i] to high address in initial process stack.
strncpy(&buf[off], argv[i], len + 1);

// TODO: Check that we have enough space to write argv.

// Add address of argv[i] to the stack.
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)&buf[off]);

off += len + 1;
}

// argc
PUSH_TO_STACK(stack, uint64_t, argc);

current_process->user_rsp = (uintptr_t)stack;

return current_process;
}
Loading

0 comments on commit c520edb

Please sign in to comment.