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 Feb 17, 2022
1 parent 01262dd commit c5fe5e8
Show file tree
Hide file tree
Showing 24 changed files with 612 additions and 64 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 @@ -429,6 +434,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
3 changes: 3 additions & 0 deletions include/libc/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
/// Truncate file.
#define O_TRUNC 0x0200

/// Mask to determine the file access mode.
#define O_ACCMODE 0x3

/// Set file descriptor offset to offset.
#define SEEK_SET 0
/// Set file descriptor offset to current plus offset.
Expand Down
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
2 changes: 1 addition & 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 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
33 changes: 32 additions & 1 deletion src/kernel/arch/x86_64/proc/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ process_t* process_exec(uint8_t* image, const char* name, char* const argv[])
}

// 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);

Expand All @@ -66,8 +71,35 @@ process_t* process_exec(uint8_t* image, const char* name, char* const argv[])
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);
Expand All @@ -81,7 +113,6 @@ process_t* process_exec(uint8_t* image, const char* name, char* const argv[])
// argv
PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL);

size_t off = 0;
for (int i = argc - 1; i >= 0; i--) {
size_t len = strlen(argv[i]);
// Copy argv[i] to high address in initial process stack.
Expand Down
11 changes: 7 additions & 4 deletions src/kernel/arch/x86_64/proc/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
#include <core/elf.h>
#include <sys/types.h>

#define USER_STACK_SIZE 0x3000
#define USER_STACK_TOP 0x1000
#define USER_STACK_BUF 0x2000
#define USER_STACK_SIZE 0x30000
#define USER_STACK_TOP 0x01000
#define USER_STACK_BUF 0x02000
#define USER_HEAP_SIZE 0x10000

typedef struct process
{
pid_t pid;
char* name;
elf_header_t* elf;
uint64_t user_stack[USER_STACK_SIZE];
uint64_t user_rsp;
uintptr_t user_rsp;
uint64_t user_heap[USER_HEAP_SIZE];
uintptr_t user_brk;
// TODO: We should probably retain the file descriptors that are opened by
// the process so that we can close them.
} process_t;
Expand Down
9 changes: 9 additions & 0 deletions src/kernel/net/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
#include <net/icmpv4.h>
#include <net/logging.h>
#include <net/udp.h>
#include <proc/descriptor.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>

ipv4_header_t ipv4_create_header(uint8_t src_ip[4],
in_addr_t dst_addr,
Expand Down Expand Up @@ -36,6 +38,13 @@ void ipv4_receive_packet(net_interface_t* interface,
src_ip[3],
interface->id);

int sockfd = descriptor_raw_lookup(header.proto, header.src_addr);
if (sockfd >= 0) {
// Handle SOCK_RAW.
write(sockfd, data, len);
return;
}

switch (header.proto) {
case IPV4_PROTO_ICMP:
icmpv4_receive_packet(interface, data, &header);
Expand Down
2 changes: 1 addition & 1 deletion src/kernel/net/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void udp_receive_packet(net_interface_t* interface,
int sockfd = descriptor_udp_lookup(udp_header.dst_port);
NET_DEBUG("got sockfd=%d for dst_port=%d", sockfd, udp_header.dst_port);

if (sockfd > 0) {
if (sockfd >= 0) {
write(sockfd, udp_data, udp_header.len - sizeof(udp_header_t));
return;
}
Expand Down
Loading

0 comments on commit c5fe5e8

Please sign in to comment.