Skip to content

Commit

Permalink
Continue implementation work on Orchid nanokernel.
Browse files Browse the repository at this point in the history
  • Loading branch information
saurik committed Feb 15, 2024
1 parent 6c6a81a commit 58ffe6a
Show file tree
Hide file tree
Showing 13 changed files with 796 additions and 142 deletions.
7 changes: 7 additions & 0 deletions env/output.mk
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,10 @@ object := $(filter-out $(1)%.o,$(object))
linked += $(1)_.a
endef
$(foreach archive,$(archive),$(eval $(call _,$(archive))))

define _
object := $$(patsubst $(1).o,$(1)-.o,$$(object))
$$(output)/%/$(1)-.o: $$(output)/%/$(1).o
objcopy $(2) $$< $$@
endef
$(foreach oflags,$(filter oflags/%,$(.VARIABLES)),$(eval $(call _,$(patsubst oflags/%,%,$(oflags)),$($(oflags)))))
2 changes: 1 addition & 1 deletion env/setup-sys.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ shift 1
export DEBIAN_FRONTEND=noninteractive
apt-get -y update
apt-get -y dist-upgrade
apt-get -y install --no-install-recommends libstdc++-"${llvm}"-dev{,-arm{hf,64}-cross} "$@"
apt-get -y install --no-install-recommends libstdc++-"${llvm}"-dev{,-{arm{hf,64},i386}-cross} "$@"
for root in /usr/*-gnu*; do
ln -s .. "${root}"/usr
done
7 changes: 4 additions & 3 deletions env/sys-ubuntu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ if [[ $(uname -s) = Linux ]]; then

debootstrap=${mount}/debootstrap
# XXX: proot -0 runs the command but fails on exit; fakeroot works correctly
DEBOOTSTRAP_DIR=${debootstrap} fakeroot "${debootstrap}"/debootstrap \
--foreign --variant=minbase --arch amd64 "${distro}" .
DEBOOTSTRAP_DIR=${debootstrap} fakeroot "${debootstrap}"/debootstrap --foreign \
--variant=minbase --arch amd64 --components=main,universe "${distro}" .

"${proot}" -0 -r . -w / -b /proc -b /sys /debootstrap/debootstrap --second-stage
echo "deb http://archive.ubuntu.com/ubuntu/ ${distro}-updates main" >>etc/apt/sources.list
# XXX: https://groups.google.com/g/linux.debian.bugs.dist/c/-p06sQmwamA
echo "deb http://archive.ubuntu.com/ubuntu/ ${distro}-updates main universe" >>etc/apt/sources.list
HOME= "${proot}" -S . -w / -b "${mount}:/mnt" /mnt/setup-sys.sh "$@"
else
# https://stackoverflow.com/questions/29934204/mount-data-volume-to-docker-with-readwrite-permission
Expand Down
1 change: 1 addition & 0 deletions env/target-apl.mk
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ lflags += -Wl,-no_dead_strip_inits_and_terms
# libtool
qflags += -DPIC
qflags += -fPIC
lflags += -fPIC

signature := /_CodeSignature/CodeResources

Expand Down
3 changes: 2 additions & 1 deletion env/target-elf.mk
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ lflags += -Wl,-error-limit=0
lflags += -Wl,--build-id=none
lflags += -Wl,-z,relro
lflags += -Wl,--no-undefined
qflags += -fpic
qflags += -fpie
lflags += -fpie
231 changes: 196 additions & 35 deletions srv-daemon/source/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@

#include <linux/kvm.h>

#if 0
#elif defined(__aarch64__)
//#include <arm/esr.h>
#elif defined(__x86_64__)
#else
#error
#endif

#include "buffer.hpp"
#include "kernel.hpp"
#include "scope.hpp"
Expand All @@ -40,6 +48,9 @@

#include "load.hpp"

// XXX: move this somewhere and maybe find a library
namespace gsl { template <typename Type_> using owner = Type_; }

// NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
namespace orc {

Expand All @@ -56,81 +67,200 @@ int Engine() {


const Fd zygote(memfd_create("zygote", MFD_CLOEXEC));
const size_t physical(64*megabyte);
const size_t physical(128*megabyte);
orc_syscall(ftruncate(zygote, physical));


const Fd kvm(orc_syscall(open("/dev/kvm", O_RDWR | O_CLOEXEC)));
orc_assert(orc_syscall(ioctl(kvm, KVM_GET_API_VERSION, nullptr)) == 12);
const auto size(orc_syscall(ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, nullptr)));

// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
const auto memory(reinterpret_cast<uint8_t *>(orc_syscall(mmap(nullptr, physical, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, zygote, 0))));
//madvise(memory, physical, MADV_MERGEABLE);

const auto &header(*reinterpret_cast<const Elf64_Ehdr *>(kernel_data));
const uint64_t entry(header.e_entry);
const auto commands(reinterpret_cast<const Elf64_Phdr *>(kernel_data + header.e_phoff));
for (size_t i(0); i != header.e_phnum; ++i)
if (const auto &command(commands[i]); command.p_type == PT_LOAD)
memcpy(memory + command.p_paddr, kernel_data + command.p_offset, command.p_filesz);
const auto entry([&]() -> uint64_t {
const auto ident(reinterpret_cast<const uint8_t *>(kernel_data));
orc_assert(memcmp(ident, ELFMAG, SELFMAG) == 0);
orc_assert(ident[EI_DATA] == ELFDATA2LSB);
orc_assert(ident[EI_VERSION] == EV_CURRENT);
orc_assert(ident[EI_OSABI] == ELFOSABI_NONE);

const auto load([&]<typename Elf_Ehdr, typename Elf_Phdr>() {
const auto &header(*reinterpret_cast<const Elf_Ehdr *>(kernel_data));
const auto commands(reinterpret_cast<const Elf_Phdr *>(kernel_data + header.e_phoff));
// XXX: I can't figure out how to get objcopy to edit the paddr field :/
for (size_t i(0); i != header.e_phnum; ++i)
if (const auto &command(commands[i]); command.p_type == PT_LOAD)
memcpy(memory + (command.p_paddr & 0x3fffffff), kernel_data + command.p_offset, command.p_filesz);
return (header.e_entry & 0x3fffffff);
});

switch (const auto value = ident[EI_CLASS]) {
#define caseELF(bits) case ELFCLASS##bits: \
return load.operator ()<Elf##bits##_Ehdr, Elf##bits##_Phdr>();
caseELF(32) caseELF(64) default:
orc_assert_(false, "unknown EI_CLASS " << unsigned(value));
}
}());
std::cout << "entry: " << std::hex << entry << std::endl;


const Fd kvm(orc_syscall(open("/dev/kvm", O_RDWR | O_CLOEXEC)));
orc_assert(orc_syscall(ioctl(kvm, KVM_GET_API_VERSION, nullptr)) == 12);
const auto size(orc_syscall(ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, nullptr)));

const auto vm(orc_syscall(ioctl(kvm, KVM_CREATE_VM, 0)));
const auto cpu(orc_syscall(ioctl(vm, KVM_CREATE_VCPU, 0)));
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
const auto run(static_cast<struct kvm_run *>(orc_syscall(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, cpu, 0))));

#if 0
#elif defined(__aarch64__)
struct kvm_vcpu_init cpuid{};
cpuid.target = KVM_ARM_TARGET_GENERIC_V8;
#elif defined(__x86_64__)
decltype(std::declval<struct kvm_cpuid2 *>()->nent) cpuids(128);
// XXX: implement allocation loop using cpuid: label
const auto cpuid(static_cast<struct kvm_cpuid2 *>(malloc(sizeof(struct kvm_cpuid2) + cpuids * sizeof(struct kvm_cpuid_entry2))));
_scope({ free(cpuid); });
cpuid->nent = cpuids;
orc_syscall(ioctl(kvm, KVM_GET_SUPPORTED_CPUID, cpuid));

for (decltype(cpuid->nent) i(0); i != cpuid->nent; ++i) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
auto &entry(cpuid->entries[i]);
switch (entry.function) {
// supports long mode
case 0x80000001:
orc_assert((entry.edx & (1 << 29)) != 0);
break;
}
}
#else
#error
#endif

struct kvm_userspace_memory_region region = {};
#if 0
#elif defined(__aarch64__)
orc_syscall(ioctl(cpu, KVM_ARM_VCPU_INIT, &cpuid));
#elif defined(__x86_64__)
orc_syscall(ioctl(cpu, KVM_SET_CPUID2, cpuid));
#else
#error
#endif

struct kvm_userspace_memory_region region{};
region.slot = 0;
region.flags = 0;
region.guest_phys_addr = 0x0;
region.memory_size = physical;
region.userspace_addr = reinterpret_cast<uintptr_t>(memory);
orc_syscall(ioctl(vm, KVM_SET_USER_MEMORY_REGION, &region));

#ifdef __aarch64__
struct kvm_vcpu_init init = {};
init.target = KVM_ARM_TARGET_GENERIC_V8;
orc_syscall(ioctl(cpu, KVM_ARM_VCPU_INIT, &init));

struct kvm_one_reg reg = {};
#if 0
#elif defined(__aarch64__)
struct kvm_one_reg reg{};
uintptr_t value;
reg.addr = reinterpret_cast<uintptr_t>(&value);

reg.id = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(regs.pc);
value = entry;
orc_syscall(ioctl(cpu, KVM_SET_ONE_REG, &reg));

reg.id = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(sp_el1);
value = 2 * megabyte;
orc_syscall(ioctl(cpu, KVM_SET_ONE_REG, &reg));
#elif defined(__x86_64__)
struct kvm_sregs sregs{};
orc_syscall(ioctl(cpu, KVM_GET_SREGS, &sregs));

struct kvm_segment seg{
.base = 0, .limit = 0xffffffff,
.selector = 1 << 3, .type = 0xb,
.present = 1, .dpl = 0, .db = 1,
.s = 1, .l = 0, .g = 1,
};

sregs.cs = seg;
seg.selector = 2 << 3; seg.type = 0x3;
sregs.ds = seg; sregs.es = seg;
sregs.fs = seg; sregs.gs = seg;
sregs.ss = seg;

sregs.cr0 |= 0x1;
orc_syscall(ioctl(cpu, KVM_SET_SREGS, &sregs));

struct kvm_regs regs{};
orc_syscall(ioctl(cpu, KVM_GET_REGS, &regs));
regs.rip = entry;
regs.rflags = 0x2;
orc_syscall(ioctl(cpu, KVM_SET_REGS, &regs));
#else
#error
#endif

#ifdef __x86_64__
(void) entry;
#if 0
struct kvm_guest_debug debug{};
debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
orc_syscall(ioctl(cpu, KVM_SET_GUEST_DEBUG, &debug));
#endif

const auto dump([&]() {
#if 0
struct kvm_regs regs = {};
orc_syscall(ioctl(cpu, KVM_GET_REGS, &regs));
std::cout << std::hex;
for (size_t i(0); i != 34; ++i)
std::cout << regs.regs.regs[i] << std::endl;
orc_syscall(ioctl(cpu, KVM_SET_REGS, &regs));
#elif defined(__aarch64__)
std::vector<uint64_t> regs;
regs.resize(1024);
regs[0] = regs.size() - 1;
orc_syscall(ioctl(cpu, KVM_GET_REG_LIST, regs.data()));

//v=0xc290; z=[14,11,7,3,0]; [(v>>b)&((1<<(a-b))-1) for a,b in zip(([16]+z)[:-1],z)]

struct kvm_one_reg reg{};
uintptr_t value;
reg.addr = reinterpret_cast<uintptr_t>(&value);

for (size_t i(0); i != regs[0]; ++i) {
reg.id = regs[i+1];
orc_syscall(ioctl(cpu, KVM_GET_ONE_REG, &reg));
std::cout << std::hex << reg.id << " " << value << std::endl;
}
#elif defined(__x86_64__)
struct kvm_regs regs{};
orc_syscall(ioctl(cpu, KVM_GET_REGS, &regs));
std::cout << std::hex;
std::cout << "ax:" << regs.rax << std::endl;
std::cout << "bx:" << regs.rbx << std::endl;
std::cout << "cx:" << regs.rcx << std::endl;
std::cout << "dx:" << regs.rdx << std::endl;
std::cout << "si:" << regs.rsi << std::endl;
std::cout << "di:" << regs.rdi << std::endl;
std::cout << "sp:" << regs.rsp << std::endl;
std::cout << "bp:" << regs.rbp << std::endl;
std::cout << "r8:" << regs.r8 << std::endl;
std::cout << "r9:" << regs.r9 << std::endl;
std::cout << "rA:" << regs.r10 << std::endl;
std::cout << "rB:" << regs.r11 << std::endl;
std::cout << "rC:" << regs.r12 << std::endl;
std::cout << "rD:" << regs.r13 << std::endl;
std::cout << "rE:" << regs.r14 << std::endl;
std::cout << "rF:" << regs.r15 << std::endl;
std::cout << "ip:" << regs.rip << std::endl;
std::cout << "fl:" << regs.rflags << std::endl;
#endif
}); (void) dump;

const auto buffer(reinterpret_cast<char *>(memory + megabyte));

for (;;) {
#ifdef __aarch64__
#if 0
#elif defined(__aarch64__)
reg.id = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(regs.pc);
orc_syscall(ioctl(cpu, KVM_GET_ONE_REG, &reg));
std::cerr << std::hex << "KVM_RUN(0x" << value << ")" << std::endl;
if (value == 0x200) {
dump();
orc_insist_(false, std::hex << value);
}
#elif defined(__x86_64__)
struct kvm_regs regs{};
orc_syscall(ioctl(cpu, KVM_GET_REGS, &regs));
std::cerr << std::hex << "KVM_RUN(0x" << regs.rip << ")" << std::endl;
//dump();
#else
#error
#endif

//__asm__ volatile ("dc civac, %0" : : "r" (buffer) : "memory");
orc_syscall(ioctl(cpu, KVM_RUN, nullptr), EINTR);
switch (run->exit_reason) {
case KVM_EXIT_INTR:
Expand All @@ -142,6 +272,10 @@ int Engine() {
orc_assert(run->mmio.is_write);
orc_assert(run->mmio.len == sizeof(uintptr_t));
switch (const auto command = *reinterpret_cast<const uintptr_t *>(run->mmio.data)) {
case 1: {
std::cout << "abort()" << std::endl;
return 0;
} break;
case 2: {
std::cout << buffer << std::flush;
} break;
Expand All @@ -151,7 +285,34 @@ int Engine() {
}
} break;

default: orc_insist(false);
case KVM_EXIT_DEBUG: {
#ifdef __aarch64__
#if 0
const auto esr(run->debug.arch.hsr >> 26);
const auto iss(run->debug.arch.hsr >> 26);
#endif
//ESR_ELx_EC_SOFTSTP_LOW;
//ESR_ELx_EC_SOFTSTP_CUR;
//KVM_DEBUG_ARCH_HSR_HIGH_VALID && hsr_high
std::cout << std::hex << run->debug.arch.hsr << " " << run->debug.arch.far << std::endl;
#endif
} break;

case KVM_EXIT_IO: {
std::cout << run->io.direction << std::endl;
} break;

case KVM_EXIT_HLT:
std::cout << "HLT" << std::endl;
return 0;
case KVM_EXIT_SHUTDOWN:
std::cout << "SHUTDOWN" << std::endl;
return 0;
case KVM_EXIT_FAIL_ENTRY:
std::cout << "FAIL_ENTRY" << std::endl;
return 0;

default: orc_insist_(false, "unknown reason: " << run->exit_reason);
}
}

Expand Down
Loading

0 comments on commit 58ffe6a

Please sign in to comment.