Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39b2af7626 | |||
| 5f343c991b | |||
| fb55cb1b9a | |||
| bedb03fc37 | |||
| 08248e3f3c |
@@ -6,3 +6,4 @@ compile_commands.json
|
|||||||
ide-swift-toolchain.txt
|
ide-swift-toolchain.txt
|
||||||
.cache
|
.cache
|
||||||
.zed
|
.zed
|
||||||
|
Runtime/.clangd
|
||||||
|
|||||||
+179
-11
@@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
#define PAGE_SIZE 0x1000
|
#define PAGE_SIZE 0x1000
|
||||||
#define WSTR(str) ((wchar_t*)L##str)
|
#define WSTR(str) ((wchar_t*)L##str)
|
||||||
|
#define MAX_MODULES 16
|
||||||
|
|
||||||
static wchar_t* kernel_path = WSTR("ksOSKernel.elf");
|
static wchar_t* kernel_path = WSTR("ksOSKernel.elf");
|
||||||
|
static wchar_t* system_dir_path = WSTR("System");
|
||||||
static efi_guid_t dtb_guid = {
|
static efi_guid_t dtb_guid = {
|
||||||
0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}
|
0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}
|
||||||
};
|
};
|
||||||
@@ -79,6 +81,8 @@ static efi_status_t open_root_volume(efi_file_handle_t** root) {
|
|||||||
return fs->OpenVolume(fs, root);
|
return fs->OpenVolume(fs, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static efi_status_t validate_elf(efi_physical_address_t addr);
|
||||||
|
|
||||||
static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** file_info) {
|
static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** file_info) {
|
||||||
efi_guid_t file_info_guid = EFI_FILE_INFO_GUID;
|
efi_guid_t file_info_guid = EFI_FILE_INFO_GUID;
|
||||||
uintn_t file_info_size = 0;
|
uintn_t file_info_size = 0;
|
||||||
@@ -95,6 +99,161 @@ static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** fi
|
|||||||
return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info);
|
return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static efi_status_t load_modules(efi_file_handle_t* root, Bootinfo* boot_info) {
|
||||||
|
efi_file_handle_t* sys_dir = NULL;
|
||||||
|
efi_status_t status = root->Open(root, &sys_dir, system_dir_path, EFI_FILE_MODE_READ, 0);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
boot_info->moduleCount = 0;
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_info->moduleCount = 0;
|
||||||
|
|
||||||
|
uint8_t dir_buffer[8192];
|
||||||
|
uintn_t dir_buffer_size;
|
||||||
|
boolean_t first_entry = 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
dir_buffer_size = sizeof(dir_buffer);
|
||||||
|
status = sys_dir->Read(sys_dir, &dir_buffer_size, dir_buffer);
|
||||||
|
if (EFI_ERROR(status) || dir_buffer_size == 0) break;
|
||||||
|
|
||||||
|
efi_file_info_t* entry = (efi_file_info_t*)dir_buffer;
|
||||||
|
|
||||||
|
if (first_entry) { first_entry = 0; continue; }
|
||||||
|
|
||||||
|
// Only process subdirectories (skip bare files)
|
||||||
|
if (!(entry->Attribute & 0x10)) continue;
|
||||||
|
|
||||||
|
// Skip . and .. entries
|
||||||
|
if (entry->FileName[0] == L'.') continue;
|
||||||
|
|
||||||
|
// Build path: System\DirName\DirName (module file matches directory name)
|
||||||
|
wchar_t file_path[FILENAME_MAX * 2 + 16];
|
||||||
|
wchar_t* p = file_path;
|
||||||
|
wchar_t* prefix = system_dir_path;
|
||||||
|
while (*prefix) *p++ = *prefix++;
|
||||||
|
*p++ = L'\\';
|
||||||
|
wchar_t* dir_name_start = p;
|
||||||
|
wchar_t* name = entry->FileName;
|
||||||
|
while (*name) *p++ = *name++;
|
||||||
|
*p++ = L'\\';
|
||||||
|
// Copy directory name again as the inner file name
|
||||||
|
wchar_t* inner = dir_name_start;
|
||||||
|
while (*inner != L'\\') *p++ = *inner++;
|
||||||
|
*p = L'\0';
|
||||||
|
|
||||||
|
efi_file_handle_t* module_file = NULL;
|
||||||
|
status = root->Open(root, &module_file, file_path, EFI_FILE_MODE_READ, 0);
|
||||||
|
if (EFI_ERROR(status)) continue;
|
||||||
|
|
||||||
|
efi_file_info_t* mod_info = NULL;
|
||||||
|
status = read_file_info(module_file, &mod_info);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
module_file->Close(module_file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t file_size = mod_info->FileSize;
|
||||||
|
gBS->FreePool(mod_info);
|
||||||
|
|
||||||
|
if (file_size == 0) {
|
||||||
|
module_file->Close(module_file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintn_t pages = (file_size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
efi_physical_address_t module_addr = 0;
|
||||||
|
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, pages, &module_addr);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
module_file->Close(module_file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintn_t bytes_to_read = (uintn_t)file_size;
|
||||||
|
status = module_file->Read(module_file, &bytes_to_read, (void*)module_addr);
|
||||||
|
module_file->Close(module_file);
|
||||||
|
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
gBS->FreePages(module_addr, pages);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EFI_ERROR(validate_elf(module_addr))) {
|
||||||
|
Elf64_Ehdr* mod_elf = (Elf64_Ehdr*)module_addr;
|
||||||
|
Elf64_Phdr* phdrs = (Elf64_Phdr*)(module_addr + mod_elf->e_phoff);
|
||||||
|
|
||||||
|
BootModule* mod = &boot_info->modules[boot_info->moduleCount];
|
||||||
|
mod->entry = (void*)mod_elf->e_entry;
|
||||||
|
mod->capabilities = 0;
|
||||||
|
mod->segmentCount = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 31; i++) {
|
||||||
|
wchar_t wc = entry->FileName[i];
|
||||||
|
if (wc == L'\0') { mod->name[i] = '\0'; break; }
|
||||||
|
mod->name[i] = (wc < 128) ? (char)wc : '?';
|
||||||
|
}
|
||||||
|
mod->name[31] = '\0';
|
||||||
|
|
||||||
|
int alloc_failed = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < mod_elf->e_phnum && mod->segmentCount < BOOT_MODULE_MAX_SEGMENTS; i++) {
|
||||||
|
if (phdrs[i].p_type != PT_LOAD) continue;
|
||||||
|
|
||||||
|
uint64_t vaddr_page = phdrs[i].p_vaddr & ~0xFFFULL;
|
||||||
|
uint64_t offset_in_page = phdrs[i].p_vaddr & 0xFFFULL;
|
||||||
|
uint64_t total_size = offset_in_page + phdrs[i].p_memsz;
|
||||||
|
uint64_t aligned_size = (total_size + 0xFFFULL) & ~0xFFFULL;
|
||||||
|
uintn_t seg_pages = aligned_size / PAGE_SIZE;
|
||||||
|
|
||||||
|
efi_physical_address_t seg_phys = 0;
|
||||||
|
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, seg_pages, &seg_phys);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
alloc_failed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((void*)seg_phys, 0, aligned_size);
|
||||||
|
|
||||||
|
if (phdrs[i].p_filesz > 0) {
|
||||||
|
uint8_t* dest = (uint8_t*)(seg_phys + offset_in_page);
|
||||||
|
uint8_t* src = (uint8_t*)(module_addr + phdrs[i].p_offset);
|
||||||
|
for (uintn_t j = 0; j < phdrs[i].p_filesz; j++) dest[j] = src[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
BootModuleSegment* seg = &mod->segments[mod->segmentCount];
|
||||||
|
seg->physicalBase = seg_phys;
|
||||||
|
seg->virtualBase = vaddr_page;
|
||||||
|
seg->size = aligned_size;
|
||||||
|
seg->flags = phdrs[i].p_flags;
|
||||||
|
|
||||||
|
mod->segmentCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alloc_failed) {
|
||||||
|
for (int i = 0; i < (int)mod->segmentCount; i++) {
|
||||||
|
uint64_t sz = mod->segments[i].size;
|
||||||
|
uintn_t pg = sz / PAGE_SIZE;
|
||||||
|
gBS->FreePages(mod->segments[i].physicalBase, pg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print(WSTR(" [MODULE] "));
|
||||||
|
print(entry->FileName);
|
||||||
|
print(WSTR("\r\n"));
|
||||||
|
|
||||||
|
boot_info->moduleCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gBS->FreePages(module_addr, pages);
|
||||||
|
|
||||||
|
if (boot_info->moduleCount >= MAX_MODULES) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_dir->Close(sys_dir);
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size, efi_file_handle_t** out_handle) {
|
static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size, efi_file_handle_t** out_handle) {
|
||||||
efi_file_handle_t* kernel_file = NULL;
|
efi_file_handle_t* kernel_file = NULL;
|
||||||
efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0);
|
efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0);
|
||||||
@@ -118,17 +277,25 @@ static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t*
|
|||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static efi_status_t validate_elf(efi_physical_address_t addr) {
|
||||||
|
Elf64_Ehdr* elf = (Elf64_Ehdr*)addr;
|
||||||
|
|
||||||
|
if (elf->e_ident[0] != 0x7f || elf->e_ident[1] != 'E' ||
|
||||||
|
elf->e_ident[2] != 'L' || elf->e_ident[3] != 'F') {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
if (elf->e_machine != 0xB7) {
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static efi_status_t parse_elf_headers(efi_physical_address_t kernel_addr) {
|
static efi_status_t parse_elf_headers(efi_physical_address_t kernel_addr) {
|
||||||
Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr;
|
efi_status_t status = validate_elf(kernel_addr);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
if (elf_header->e_ident[0] != 0x7f || elf_header->e_ident[1] != 'E' ||
|
return fail(WSTR("Invalid kernel ELF\r\n"));
|
||||||
elf_header->e_ident[2] != 'L' || elf_header->e_ident[3] != 'F') {
|
|
||||||
return fail(WSTR("Invalid ELF header\r\n"));
|
|
||||||
}
|
}
|
||||||
if (elf_header->e_machine != 0xB7) { // AArch64
|
|
||||||
return fail(WSTR("Invalid ELF machine\r\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,8 +413,6 @@ efi_status_t bootloader_main(void) {
|
|||||||
return fail(WSTR("Failed to load ksOSKernel.bin\r\n"));
|
return fail(WSTR("Failed to load ksOSKernel.bin\r\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf64_Ehdr* elf_header = (Elf64_Ehdr*)kernel_addr;
|
|
||||||
|
|
||||||
status = parse_elf_headers(kernel_addr);
|
status = parse_elf_headers(kernel_addr);
|
||||||
if (EFI_ERROR(status)) return status;
|
if (EFI_ERROR(status)) return status;
|
||||||
|
|
||||||
@@ -271,6 +436,9 @@ efi_status_t bootloader_main(void) {
|
|||||||
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
||||||
boot_info->dtb = dtb_address;
|
boot_info->dtb = dtb_address;
|
||||||
|
|
||||||
|
print(WSTR("Loading System modules...\r\n"));
|
||||||
|
status = load_modules(root, boot_info);
|
||||||
|
|
||||||
print(WSTR("Almost ready to jump. Reading memory map\r\n"));
|
print(WSTR("Almost ready to jump. Reading memory map\r\n"));
|
||||||
status = populate_memory_map(boot_info);
|
status = populate_memory_map(boot_info);
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
|
|||||||
@@ -33,3 +33,7 @@ typedef struct {
|
|||||||
} Elf64_Phdr;
|
} Elf64_Phdr;
|
||||||
|
|
||||||
#define PT_LOAD 1
|
#define PT_LOAD 1
|
||||||
|
|
||||||
|
#define PF_X 1
|
||||||
|
#define PF_W 2
|
||||||
|
#define PF_R 4
|
||||||
@@ -27,11 +27,27 @@ typedef struct {
|
|||||||
void* kernelAddress;
|
void* kernelAddress;
|
||||||
} BIKernelInfo;
|
} BIKernelInfo;
|
||||||
|
|
||||||
|
#define BOOT_MODULE_MAX_SEGMENTS 8
|
||||||
|
|
||||||
|
#define PF_X 1
|
||||||
|
#define PF_W 2
|
||||||
|
#define PF_R 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
BIUInt64 physicalBase;
|
BIUInt64 physicalBase;
|
||||||
|
BIUInt64 virtualBase;
|
||||||
BIUInt64 size;
|
BIUInt64 size;
|
||||||
|
BIUInt32 flags;
|
||||||
|
BIUInt32 reserved;
|
||||||
|
} BootModuleSegment;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void* entry;
|
||||||
char name[32];
|
char name[32];
|
||||||
BIUInt64 capabilities;
|
BIUInt64 capabilities;
|
||||||
|
BIUInt32 segmentCount;
|
||||||
|
BIUInt32 reserved;
|
||||||
|
BootModuleSegment segments[BOOT_MODULE_MAX_SEGMENTS];
|
||||||
} BootModule;
|
} BootModule;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Copyright (c) 2026 0xKSor
|
// Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Arch/Exceptions.h"
|
||||||
#include <Types.h>
|
#include <Types.h>
|
||||||
|
|
||||||
static inline void CPUYield() {
|
static inline void CPUYield() {
|
||||||
@@ -111,4 +112,13 @@ static inline void CPUSwitchAddressSpace(Address l0Physical) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void CPUCopyIPCRegisters(ExceptionsContext* source, ExceptionsContext* destination) {
|
||||||
|
destination->x2 = source->x2;
|
||||||
|
destination->x3 = source->x3;
|
||||||
|
destination->x4 = source->x4;
|
||||||
|
destination->x5 = source->x5;
|
||||||
|
destination->x6 = source->x6;
|
||||||
|
destination->x7 = source->x7;
|
||||||
|
}
|
||||||
|
|
||||||
#define CPUException(number) __asm__ volatile ("svc %0" :: "i" (number) : "memory")
|
#define CPUException(number) __asm__ volatile ("svc %0" :: "i" (number) : "memory")
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Arch/Exceptions.h"
|
||||||
|
#include <Types.h>
|
||||||
|
#include <OS/Scheduler.h>
|
||||||
|
|
||||||
|
UInt64 IPCSend(OSTask* sender, UInt64 handleID, UInt64 data);
|
||||||
|
void IPCReceive(ExceptionsContext* receiverFrame);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Types.h>
|
||||||
|
#include "../Common/bootinfo.h"
|
||||||
|
#include <OS/Scheduler.h>
|
||||||
|
|
||||||
|
OSTask* ModuleLoad(BootModule* module);
|
||||||
@@ -4,12 +4,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Types.h>
|
#include <Types.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kOSHandleTypeNone = 0,
|
||||||
|
kOSHandleTypeTask
|
||||||
|
} OSHandleType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
OSHandleType type;
|
||||||
|
Pointer object;
|
||||||
|
} OSHandle;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kOSSchedulerTaskStackSize = 16 * 1024,
|
||||||
|
kOSSchedulerExceptionNumber = 0xF0F0,
|
||||||
|
kOSMaxHandlesPerProcess = 256,
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum OSTaskState {
|
typedef enum OSTaskState {
|
||||||
OSTaskStateDead,
|
OSTaskStateDead,
|
||||||
OSTaskStateRunning,
|
OSTaskStateRunning,
|
||||||
OSTaskStateReady,
|
OSTaskStateReady,
|
||||||
OSTaskStateBlocked,
|
OSTaskStateBlocked,
|
||||||
OSTaskStateSleeping,
|
OSTaskStateSleeping,
|
||||||
|
|
||||||
|
OSTaskStateBlockedReceive,
|
||||||
|
OSTaskStateBlockedSend,
|
||||||
} OSTaskState;
|
} OSTaskState;
|
||||||
|
|
||||||
typedef struct OSProcess {
|
typedef struct OSProcess {
|
||||||
@@ -20,11 +39,12 @@ typedef struct OSProcess {
|
|||||||
Address heapCurrent;
|
Address heapCurrent;
|
||||||
struct OSProcess* parent;
|
struct OSProcess* parent;
|
||||||
ASCII name[32];
|
ASCII name[32];
|
||||||
|
|
||||||
|
OSHandle handles[kOSMaxHandlesPerProcess];
|
||||||
} OSProcess;
|
} OSProcess;
|
||||||
|
|
||||||
typedef struct OSTask {
|
typedef struct OSTask {
|
||||||
Address stackPointer;
|
Address stackPointer;
|
||||||
struct OSTask* next;
|
|
||||||
UInt32 id;
|
UInt32 id;
|
||||||
UInt32 sleepTicks;
|
UInt32 sleepTicks;
|
||||||
OSTaskState state;
|
OSTaskState state;
|
||||||
@@ -32,14 +52,19 @@ typedef struct OSTask {
|
|||||||
Pointer kernelStackBase;
|
Pointer kernelStackBase;
|
||||||
OSProcess* process;
|
OSProcess* process;
|
||||||
Int32 waitingForProcessId;
|
Int32 waitingForProcessId;
|
||||||
|
|
||||||
|
struct OSTask* next;
|
||||||
|
struct OSTask* senderWaiting;
|
||||||
} OSTask;
|
} OSTask;
|
||||||
|
|
||||||
enum {
|
extern UInt32 gOSSchedulerNextProcessID;
|
||||||
kOSSchedulerTaskStackSize = 16 * 1024,
|
|
||||||
kOSSchedulerExceptionNumber = 0xF0F0
|
|
||||||
};
|
|
||||||
|
|
||||||
void SchedulerInitialize();
|
void SchedulerInitialize();
|
||||||
OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Address fixedUserStackAddress);
|
OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Address fixedUserStackAddress);
|
||||||
Address SchedulerNext(Address stackPointer);
|
Address SchedulerNext(Address stackPointer);
|
||||||
void SchedulerYield(UInt64 ticks);
|
void SchedulerYield(UInt64 ticks);
|
||||||
|
UInt64 SchedulerGetNextProcessID();
|
||||||
|
void SchedulerBlockCurrentTask(UInt32 newState);
|
||||||
|
OSTask* SchedulerGetCurrentTask();
|
||||||
|
Int32 SchedulerProcessAllocateHandle(OSProcess* process, OSHandleType type, Pointer object);
|
||||||
|
Pointer SchedulerProcessGetHandle(OSProcess* process, UInt32 handleId, OSHandleType expectedType);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Types.h>
|
||||||
|
#include <Arch/Exceptions.h>
|
||||||
|
|
||||||
|
enum Syscalls {
|
||||||
|
kSyscallSend,
|
||||||
|
kSyscallReceive,
|
||||||
|
};
|
||||||
|
|
||||||
|
Address SyscallDispatch(ExceptionsContext* frame);
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <Arch/GIC.h>
|
#include <Arch/GIC.h>
|
||||||
#include <OS/Panic.h>
|
#include <OS/Panic.h>
|
||||||
#include <OS/Scheduler.h>
|
#include <OS/Scheduler.h>
|
||||||
|
#include <OS/Syscall.h>
|
||||||
|
|
||||||
Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) {
|
Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) {
|
||||||
if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(frame, type);
|
if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(frame, type);
|
||||||
@@ -13,10 +14,9 @@ Address ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) {
|
|||||||
UInt32 class = (esr >> 26) & 0x3F;
|
UInt32 class = (esr >> 26) & 0x3F;
|
||||||
UInt32 syndrome = esr & 0x1FFFFFF;
|
UInt32 syndrome = esr & 0x1FFFFFF;
|
||||||
|
|
||||||
if (class == 0x11 || class == 0x15) {
|
if (class == 0x15) {
|
||||||
if (syndrome == kOSSchedulerExceptionNumber) {
|
if (syndrome == kOSSchedulerExceptionNumber) return SchedulerNext((Address)frame);
|
||||||
return SchedulerNext((Address)frame);
|
if (syndrome == 0) return SyscallDispatch(frame);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OSPanicException(frame);
|
OSPanicException(frame);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <OS/Log.h>
|
#include <OS/Log.h>
|
||||||
#include <OS/Panic.h>
|
#include <OS/Panic.h>
|
||||||
#include <OS/Scheduler.h>
|
#include <OS/Scheduler.h>
|
||||||
|
#include <OS/Modules.h>
|
||||||
|
|
||||||
void KernelMain(Bootinfo* bootinfo) {
|
void KernelMain(Bootinfo* bootinfo) {
|
||||||
OSLog("Kernel started.\n");
|
OSLog("Kernel started.\n");
|
||||||
@@ -26,6 +27,7 @@ void KernelMain(Bootinfo* bootinfo) {
|
|||||||
DTBParse(bootinfo->dtb, &bootMap);
|
DTBParse(bootinfo->dtb, &bootMap);
|
||||||
PMMInitialize(&bootMap);
|
PMMInitialize(&bootMap);
|
||||||
VMMInitialize(&bootMap, bootinfo);
|
VMMInitialize(&bootMap, bootinfo);
|
||||||
|
bootinfo = (Bootinfo*)VMPhysToHHDM((Address)bootinfo);
|
||||||
SerialUpdate(VMPhysToHHDM(bootMap.UART.base));
|
SerialUpdate(VMPhysToHHDM(bootMap.UART.base));
|
||||||
HeapInitialize();
|
HeapInitialize();
|
||||||
|
|
||||||
@@ -37,5 +39,9 @@ void KernelMain(Bootinfo* bootinfo) {
|
|||||||
CPUEnableInterrupts();
|
CPUEnableInterrupts();
|
||||||
SchedulerInitialize();
|
SchedulerInitialize();
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < bootinfo->moduleCount; i++) {
|
||||||
|
ModuleLoad(&bootinfo->modules[i]); // TODO: priority
|
||||||
|
}
|
||||||
|
|
||||||
OSLog("Kernel initialized.\n");
|
OSLog("Kernel initialized.\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#include <OS/IPC.h>
|
||||||
|
#include <OS/Scheduler.h>
|
||||||
|
#include <Arch/CPU.h>
|
||||||
|
#include <Arch/Exceptions.h>
|
||||||
|
|
||||||
|
UInt64 IPCSend(OSTask* sender, UInt64 handleID, UInt64 data) {
|
||||||
|
if (handleID == 0) return -1;
|
||||||
|
OSProcess* currentProcess = sender->process;
|
||||||
|
OSTask* targetTask = (OSTask*)SchedulerProcessGetHandle(currentProcess, handleID, kOSHandleTypeTask);
|
||||||
|
if (!targetTask) return -1;
|
||||||
|
|
||||||
|
if (targetTask->state == OSTaskStateBlockedReceive) {
|
||||||
|
ExceptionsContext* receiverContext = (ExceptionsContext*)targetTask->stackPointer;
|
||||||
|
receiverContext->x1 = data;
|
||||||
|
receiverContext->x0 = currentProcess->id;
|
||||||
|
|
||||||
|
targetTask->state = OSTaskStateRunning;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetTask->senderWaiting != nullptr) return -2;
|
||||||
|
|
||||||
|
targetTask->senderWaiting = sender;
|
||||||
|
|
||||||
|
SchedulerBlockCurrentTask(OSTaskStateBlockedSend);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPCReceive(ExceptionsContext* receiverFrame) {
|
||||||
|
OSTask* receiver = SchedulerGetCurrentTask();
|
||||||
|
|
||||||
|
if (receiver->senderWaiting != nullptr) {
|
||||||
|
OSTask* sender = receiver->senderWaiting;
|
||||||
|
|
||||||
|
ExceptionsContext* senderContext = (ExceptionsContext*)sender->stackPointer;
|
||||||
|
|
||||||
|
receiverFrame->x1 = senderContext->x1; // Data
|
||||||
|
receiverFrame->x0 = sender->process->id; // Sender ID
|
||||||
|
|
||||||
|
receiver->senderWaiting = nullptr;
|
||||||
|
sender->state = OSTaskStateRunning;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SchedulerBlockCurrentTask(OSTaskStateBlockedReceive);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#include <OS/Modules.h>
|
||||||
|
#include <OS/Scheduler.h>
|
||||||
|
#include <OS/Log.h>
|
||||||
|
#include <VM/Heap.h>
|
||||||
|
#include <VM/VMM.h>
|
||||||
|
#include <Lib/String.h>
|
||||||
|
#include <Arch/CPU.h>
|
||||||
|
#include "../Common/bootinfo.h"
|
||||||
|
|
||||||
|
OSTask* ModuleLoad(BootModule* module) {
|
||||||
|
OSProcess* userProc = HeapAllocate(sizeof(OSProcess));
|
||||||
|
MemorySet(userProc, 0, sizeof(OSProcess));
|
||||||
|
userProc->id = SchedulerGetNextProcessID();
|
||||||
|
userProc->state = OSTaskStateRunning;
|
||||||
|
StringCopy(userProc->name, module->name);
|
||||||
|
|
||||||
|
Address userL0Phys = (Address)PMMAllocatePage();
|
||||||
|
Address* userL0Virt = (Address*)VMPhysToHHDM(userL0Phys);
|
||||||
|
MemorySet(userL0Virt, 0, kVMPageSize);
|
||||||
|
userProc->l0Table = userL0Virt;
|
||||||
|
|
||||||
|
for (BIUInt32 s = 0; s < module->segmentCount; s++) {
|
||||||
|
BootModuleSegment* seg = &module->segments[s];
|
||||||
|
|
||||||
|
UInt64 segFlags = kPTENormalMem | kPTEUser;
|
||||||
|
|
||||||
|
if (seg->flags & PF_W) {
|
||||||
|
// writable: AP[2]=0 (RW), which is the default
|
||||||
|
} else {
|
||||||
|
segFlags |= kPTEAccessRO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seg->flags & PF_X) {
|
||||||
|
// executable: default is already executable
|
||||||
|
} else {
|
||||||
|
segFlags |= kPTEPrivNX | kPTEUserNX;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Size i = 0; i < seg->size; i += kVMPageSize) {
|
||||||
|
VMMMapPage((Address*)userL0Phys,
|
||||||
|
seg->physicalBase + i,
|
||||||
|
seg->virtualBase + i,
|
||||||
|
segFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPUCleanAndInvalidateCode((void*)VMPhysToHHDM(seg->physicalBase), seg->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Address stackPhys = (Address)PMMAllocatePage();
|
||||||
|
Address userStackVirt = 0x80000000;
|
||||||
|
UInt64 stackFlags = kPTENormalMem | kPTEUser | kPTEAccessRW | kPTEPrivNX | kPTEUserNX;
|
||||||
|
|
||||||
|
VMMMapPage((Address*)userL0Phys, stackPhys, userStackVirt, stackFlags);
|
||||||
|
|
||||||
|
void (*userEntryPoint)() = (void(*)())module->entry;
|
||||||
|
|
||||||
|
if ((Address)userEntryPoint == 0x0) {
|
||||||
|
OSLog("Skipping module %s: entry point is 0x0.\n", module->name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SchedulerSpawn(userEntryPoint, userProc, true, userStackVirt + kVMPageSize);
|
||||||
|
}
|
||||||
@@ -69,6 +69,7 @@ OSTask* SchedulerSpawn(void(*entryPoint)(), OSProcess* owner, Boolean isUser, Ad
|
|||||||
task->waitingForProcessId = -1;
|
task->waitingForProcessId = -1;
|
||||||
|
|
||||||
task->next = gOSSchedulerCurrentTask->next;
|
task->next = gOSSchedulerCurrentTask->next;
|
||||||
|
task->senderWaiting = nullptr;
|
||||||
gOSSchedulerCurrentTask->next = task;
|
gOSSchedulerCurrentTask->next = task;
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
@@ -122,3 +123,34 @@ void SchedulerYield(UInt64 ticks) {
|
|||||||
gOSSchedulerCurrentTask->state = OSTaskStateSleeping;
|
gOSSchedulerCurrentTask->state = OSTaskStateSleeping;
|
||||||
CPUException(kOSSchedulerExceptionNumber);
|
CPUException(kOSSchedulerExceptionNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UInt64 SchedulerGetNextProcessID() {
|
||||||
|
return gOSSchedulerNextProcessID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SchedulerBlockCurrentTask(UInt32 newState) {
|
||||||
|
gOSSchedulerCurrentTask->state = newState;
|
||||||
|
CPUException(kOSSchedulerExceptionNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSTask* SchedulerGetCurrentTask() {
|
||||||
|
return gOSSchedulerCurrentTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 SchedulerProcessAllocateHandle(OSProcess* process, OSHandleType type, Pointer object) {
|
||||||
|
for (Int32 i = 1; i < kOSMaxHandlesPerProcess; i++) {
|
||||||
|
if (process->handles[i].type == kOSHandleTypeNone) {
|
||||||
|
process->handles[i].type = type;
|
||||||
|
process->handles[i].object = object;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointer SchedulerProcessGetHandle(OSProcess* process, UInt32 handleId, OSHandleType expectedType) {
|
||||||
|
if (handleId == 0 || handleId >= kOSMaxHandlesPerProcess) return nullptr;
|
||||||
|
OSHandle* handle = &process->handles[handleId];
|
||||||
|
if (handle->type != expectedType) return nullptr;
|
||||||
|
return handle->object;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <OS/Syscall.h>
|
||||||
|
#include <OS/IPC.h>
|
||||||
|
#include <OS/Scheduler.h>
|
||||||
|
#include <OS/Panic.h>
|
||||||
|
#include <Arch/Exceptions.h>
|
||||||
|
|
||||||
|
Address SyscallDispatch(ExceptionsContext* frame) {
|
||||||
|
UInt64 syscallNumber = frame->x8;
|
||||||
|
OSTask* current = SchedulerGetCurrentTask();
|
||||||
|
|
||||||
|
switch (syscallNumber) {
|
||||||
|
case kSyscallSend:
|
||||||
|
frame->x0 = IPCSend(current, frame->x0, frame->x1);
|
||||||
|
break;
|
||||||
|
case kSyscallReceive:
|
||||||
|
IPCReceive(frame);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
frame->x0 = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current->state != OSTaskStateRunning) return SchedulerNext((Address)frame);
|
||||||
|
return (Address)frame;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
set(CMAKE_SYSTEM_NAME Generic)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||||
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||||
|
|
||||||
|
if(NOT LLVM_BIN)
|
||||||
|
find_program(_CLANG
|
||||||
|
NAMES clang
|
||||||
|
HINTS
|
||||||
|
/opt/homebrew/opt/llvm/bin
|
||||||
|
/usr/local/opt/llvm/bin
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT _CLANG AND APPLE)
|
||||||
|
execute_process(
|
||||||
|
COMMAND brew --prefix llvm
|
||||||
|
OUTPUT_VARIABLE LLVM_PREFIX
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
RESULT_VARIABLE BREW_PREFIX_RESULT
|
||||||
|
)
|
||||||
|
if(BREW_PREFIX_RESULT EQUAL 0 AND EXISTS "${LLVM_PREFIX}/bin/clang")
|
||||||
|
set(_CLANG "${LLVM_PREFIX}/bin/clang")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT _CLANG)
|
||||||
|
message(FATAL_ERROR "clang not found. Set LLVM_BIN or add clang to PATH.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_filename_component(LLVM_BIN "${_CLANG}" DIRECTORY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER "${LLVM_BIN}/clang")
|
||||||
|
set(CMAKE_ASM_COMPILER "${LLVM_BIN}/clang")
|
||||||
|
|
||||||
|
set(TARGET_TRIPLE aarch64-none-elf)
|
||||||
|
set(CMAKE_C_COMPILER_TARGET ${TARGET_TRIPLE})
|
||||||
|
set(CMAKE_ASM_COMPILER_TARGET ${TARGET_TRIPLE})
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
find_program(TERMOS_LD_LLD NAMES ld.lld HINTS /usr/local/bin /opt/homebrew/bin REQUIRED)
|
||||||
|
set(CMAKE_C_LINK_FLAGS "")
|
||||||
|
set(CMAKE_C_LINK_EXECUTABLE
|
||||||
|
"${TERMOS_LD_LLD} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_program(LLVM_OBJCOPY NAMES llvm-objcopy objcopy
|
||||||
|
HINTS
|
||||||
|
"${LLVM_BIN}"
|
||||||
|
/usr/local/opt/llvm/bin
|
||||||
|
/opt/homebrew/opt/llvm/bin
|
||||||
|
/usr/local/bin
|
||||||
|
/opt/homebrew/bin
|
||||||
|
REQUIRED
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS_INIT "-ffreestanding -mgeneral-regs-only -std=c23")
|
||||||
|
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_INIT "-nostdlib -static -no-pie -z max-page-size=0x1000 --no-dynamic-linker -T ${CMAKE_CURRENT_LIST_DIR}/linker.ld -Ttext=0x400000")
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
set(KSOS_SYSROOT_SRC "${CMAKE_CURRENT_LIST_DIR}/..")
|
||||||
|
set(BUILD_DIR $ENV{BUILD_DIR})
|
||||||
|
if(NOT BUILD_DIR)
|
||||||
|
set(BUILD_DIR "${CMAKE_CURRENT_LIST_DIR}/../../.build")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(KSOS_LIB_DIR "${BUILD_DIR}/Runtime/System/libksOS")
|
||||||
|
|
||||||
|
function(add_ksos_executable TARGET_NAME)
|
||||||
|
add_executable(${TARGET_NAME}
|
||||||
|
"${KSOS_SYSROOT_SRC}/System/libksOS/Source/crt0.S"
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${TARGET_NAME} PRIVATE
|
||||||
|
"${KSOS_SYSROOT_SRC}/System/libksOS/Include"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_directories(${TARGET_NAME} PRIVATE
|
||||||
|
"${KSOS_LIB_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${TARGET_NAME} PRIVATE
|
||||||
|
ksOS
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x400000;
|
||||||
|
|
||||||
|
.text : ALIGN(4K) {
|
||||||
|
*(.text .text.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : ALIGN(4K) {
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : ALIGN(4K) {
|
||||||
|
*(.data .data.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : ALIGN(4K) {
|
||||||
|
*(.bss .bss.*)
|
||||||
|
*(COMMON)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(ksOS_init LANGUAGES C ASM)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_SOURCE_DIR}/../../Common/ksOS_SDK.cmake")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE INIT_SOURCES CMAKE_CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/*.S
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/*.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_ksos_executable(Init ${INIT_SOURCES})
|
||||||
|
|
||||||
|
set_target_properties(Init PROPERTIES
|
||||||
|
OUTPUT_NAME "Init"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
#include <ksOS/Syscall.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
SysSend(1, 0xa0a0a0a0a);
|
||||||
|
while (1) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(ksOS_test LANGUAGES C ASM)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_SOURCE_DIR}/../../Common/ksOS_SDK.cmake")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE INIT_SOURCES CMAKE_CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/*.S
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Source/*.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_ksos_executable(Init ${INIT_SOURCES})
|
||||||
|
|
||||||
|
set_target_properties(Init PROPERTIES
|
||||||
|
OUTPUT_NAME "Test"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include <ksOS/Syscall.h>
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
IPCMessage message = SysRecive();
|
||||||
|
if (message.data == 0xa0a0a0a0a) {
|
||||||
|
Sys228();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(libksOS LANGUAGES C ASM)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE LIB_SOURCES CMAKE_CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(ksOS STATIC ${LIB_SOURCES})
|
||||||
|
|
||||||
|
target_include_directories(ksOS PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_options(ksOS PRIVATE
|
||||||
|
-std=c23 -fno-stack-protector -fno-builtin -Wall -Wextra
|
||||||
|
)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <ksOS/Types.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kSyscallSend = 1,
|
||||||
|
kSyscallReceive,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct IPCMessage {
|
||||||
|
UInt64 senderID;
|
||||||
|
UInt64 data;
|
||||||
|
} IPCMessage;
|
||||||
|
|
||||||
|
static inline UInt64 SysSend(UInt64 handleID, UInt64 data) {
|
||||||
|
register UInt64 x8 __asm__("x8") = kSyscallSend;
|
||||||
|
register UInt64 x0 __asm__("x0") = handleID;
|
||||||
|
register UInt64 x1 __asm__("x1") = data;
|
||||||
|
|
||||||
|
__asm__ volatile(
|
||||||
|
"svc #0\n"
|
||||||
|
: "+r" (x0)
|
||||||
|
: "r" (x1), "r" (x8)
|
||||||
|
: "memory", "cc"
|
||||||
|
);
|
||||||
|
return x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline IPCMessage SysRecive(void) {
|
||||||
|
register UInt64 x8 __asm__("x8") = kSyscallReceive;
|
||||||
|
register UInt64 x0 __asm__("x0");
|
||||||
|
register UInt64 x1 __asm__("x1");
|
||||||
|
|
||||||
|
__asm__ volatile(
|
||||||
|
"svc #0\n"
|
||||||
|
: "=r" (x0), "=r" (x1)
|
||||||
|
: "r" (x8)
|
||||||
|
: "memory", "cc"
|
||||||
|
);
|
||||||
|
|
||||||
|
struct IPCMessage msg = { x0, x1 };
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void Sys228(void) {
|
||||||
|
register UInt64 x8 __asm__("x8") = 228;
|
||||||
|
__asm__ volatile(
|
||||||
|
"svc #0\n"
|
||||||
|
:
|
||||||
|
: "r" (x8)
|
||||||
|
: "memory", "cc"
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(NDEBUG) || defined(__OPTIMIZE__)
|
||||||
|
#define IS_RELEASE 1
|
||||||
|
#else
|
||||||
|
#define IS_RELEASE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char UInt8;
|
||||||
|
typedef unsigned short UInt16;
|
||||||
|
typedef unsigned int UInt32;
|
||||||
|
typedef unsigned long long UInt64;
|
||||||
|
typedef unsigned long long UInt;
|
||||||
|
|
||||||
|
typedef void* Pointer;
|
||||||
|
typedef UInt Address;
|
||||||
|
typedef UInt32 Address32;
|
||||||
|
typedef UInt8* BytePointer;
|
||||||
|
typedef UInt8* MemoryPointer;
|
||||||
|
|
||||||
|
typedef signed char Int8;
|
||||||
|
typedef signed short Int16;
|
||||||
|
typedef signed int Int32;
|
||||||
|
typedef signed long long Int64;
|
||||||
|
typedef int Int;
|
||||||
|
|
||||||
|
typedef UInt64 Size;
|
||||||
|
typedef char ASCII;
|
||||||
|
|
||||||
|
typedef _Bool Boolean;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKSor
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
.section .text.entry, "ax"
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
adrp x0, stack_top
|
||||||
|
add sp, x0, :lo12:stack_top
|
||||||
|
bl main
|
||||||
|
b .
|
||||||
|
|
||||||
|
.section .bss, "aw", @nobits
|
||||||
|
.align 12 // 4KB alignment
|
||||||
|
stack_bottom:
|
||||||
|
.space 8192 // 8KB stack
|
||||||
|
stack_top:
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# Copyright (c) 2026 0xKSor
|
||||||
|
|
||||||
|
set quiet := true
|
||||||
|
|
||||||
|
ROOT_BUILD_DIR := env_var_or_default("BUILD_DIR", justfile_directory() + "/../.build")
|
||||||
|
RUNTIME_BUILD_DIR := ROOT_BUILD_DIR + "/Runtime"
|
||||||
|
TEMP_DIR := env_var_or_default("TEMP_DIR", ROOT_BUILD_DIR + "/temp")
|
||||||
|
|
||||||
|
_default:
|
||||||
|
just --list
|
||||||
|
|
||||||
|
@_build_cmake project_dir target_subpath:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
PROJECT_DIR="{{ project_dir }}"
|
||||||
|
TARGET_SUBPATH="{{ target_subpath }}"
|
||||||
|
TEMP_DIR="{{ TEMP_DIR }}/Runtime/${TARGET_SUBPATH}"
|
||||||
|
OUT_DIR="{{ RUNTIME_BUILD_DIR }}/${TARGET_SUBPATH}"
|
||||||
|
|
||||||
|
echo " 🛠️ CMake build: ${TARGET_SUBPATH}"
|
||||||
|
|
||||||
|
TOOLCHAIN_FILE="{{ justfile_directory() }}/Common/aarch64.cmake"
|
||||||
|
TOOLCHAIN=""
|
||||||
|
if [ -f "${TOOLCHAIN_FILE}" ]; then
|
||||||
|
TOOLCHAIN="-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE}"
|
||||||
|
else
|
||||||
|
echo " ⚠️ Warning: Toolchain file not found at ${TOOLCHAIN_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! OUT=$(cmake -B "${TEMP_DIR}" -S "${PROJECT_DIR}" -DCMAKE_BUILD_TYPE=Release ${TOOLCHAIN} -G Ninja 2>&1); then
|
||||||
|
echo "$OUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! OUT=$(cmake --build "${TEMP_DIR}" 2>&1); then
|
||||||
|
echo "$OUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${OUT_DIR}"
|
||||||
|
# Copy everything from build dir except CMake junk
|
||||||
|
rsync -a --exclude='CMakeFiles' --exclude='CMakeCache.txt' --exclude='*.ninja*' --exclude='.ninja*' \
|
||||||
|
"${TEMP_DIR}"/ "${OUT_DIR}"/ 2>/dev/null || \
|
||||||
|
cp -R "${TEMP_DIR}"/* "${OUT_DIR}"/ 2>/dev/null || true
|
||||||
|
|
||||||
|
echo " ✅ CMake done: ${TARGET_SUBPATH}"
|
||||||
|
|
||||||
|
@_build_swiftpm project_dir target_subpath:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
PROJECT_DIR="{{ project_dir }}"
|
||||||
|
TARGET_SUBPATH="{{ target_subpath }}"
|
||||||
|
TEMP_DIR="{{ TEMP_DIR }}/Runtime/${TARGET_SUBPATH}"
|
||||||
|
OUT_DIR="{{ RUNTIME_BUILD_DIR }}/${TARGET_SUBPATH}"
|
||||||
|
|
||||||
|
echo " 🛠️ SwiftPM build: ${TARGET_SUBPATH}"
|
||||||
|
|
||||||
|
cd "${PROJECT_DIR}"
|
||||||
|
|
||||||
|
if ! OUT=$(swift build -c release --build-path "${TEMP_DIR}" 2>&1); then
|
||||||
|
echo "$OUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "${OUT_DIR}"
|
||||||
|
if [ -d "${TEMP_DIR}/release" ]; then
|
||||||
|
rsync -a "${TEMP_DIR}/release"/ "${OUT_DIR}"/ 2>/dev/null || \
|
||||||
|
cp -R "${TEMP_DIR}/release"/* "${OUT_DIR}"/ 2>/dev/null || true
|
||||||
|
elif [ -d "${TEMP_DIR}/Release" ]; then
|
||||||
|
rsync -a "${TEMP_DIR}/Release"/ "${OUT_DIR}"/ 2>/dev/null || \
|
||||||
|
cp -R "${TEMP_DIR}/Release"/* "${OUT_DIR}"/ 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " ✅ SwiftPM done: ${TARGET_SUBPATH}"
|
||||||
|
|
||||||
|
@_discover_and_build category:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
CATEGORY="{{ category }}"
|
||||||
|
RUNTIME_DIR="{{ justfile_directory() }}"
|
||||||
|
SRC_DIR="${RUNTIME_DIR}/${CATEGORY}"
|
||||||
|
|
||||||
|
if [ ! -d "${SRC_DIR}" ]; then
|
||||||
|
echo " 📁 ${CATEGORY}/ not found, skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
projects=("${SRC_DIR}"/*/)
|
||||||
|
shopt -u nullglob
|
||||||
|
|
||||||
|
if [ ${#projects[@]} -eq 0 ]; then
|
||||||
|
echo " 📁 ${CATEGORY}/ is empty, skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# libksOS MUST be built first — everyone depends on it
|
||||||
|
for dir in "${projects[@]}"; do
|
||||||
|
name=$(basename "${dir}")
|
||||||
|
if [ "${name}" = "libksOS" ]; then
|
||||||
|
echo ""
|
||||||
|
echo " 📦 ${CATEGORY}/${name}"
|
||||||
|
just --quiet _build_cmake "${dir}" "${CATEGORY}/${name}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for dir in "${projects[@]}"; do
|
||||||
|
name=$(basename "${dir}")
|
||||||
|
if [ "${name}" = "libksOS" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo " 📦 ${CATEGORY}/${name}"
|
||||||
|
|
||||||
|
if [ -f "${dir}/CMakeLists.txt" ]; then
|
||||||
|
just --quiet _build_cmake "${dir}" "${CATEGORY}/${name}"
|
||||||
|
elif [ -f "${dir}/Package.swift" ]; then
|
||||||
|
just --quiet _build_swiftpm "${dir}" "${CATEGORY}/${name}"
|
||||||
|
else
|
||||||
|
echo " ⚠️ Skipping ${CATEGORY}/${name}: no CMakeLists.txt or Package.swift found"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
@build:
|
||||||
|
@echo "🛠️ Building Runtime..."
|
||||||
|
@just --quiet clangd
|
||||||
|
@mkdir -p {{ RUNTIME_BUILD_DIR }}/System
|
||||||
|
@mkdir -p {{ RUNTIME_BUILD_DIR }}/Apps
|
||||||
|
@just --quiet _discover_and_build System
|
||||||
|
@just --quiet _discover_and_build Apps
|
||||||
|
@echo ""
|
||||||
|
@echo "✅ Runtime ready at: {{ RUNTIME_BUILD_DIR }}"
|
||||||
|
|
||||||
|
@clean:
|
||||||
|
@rm -rf {{ TEMP_DIR }}/Runtime
|
||||||
|
@rm -rf {{ RUNTIME_BUILD_DIR }}
|
||||||
|
@echo "🧹 Runtime cleaned"
|
||||||
|
|
||||||
|
@clangd:
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
RUNTIME_DIR="{{ justfile_directory() }}"
|
||||||
|
INCLUDE_DIR="${RUNTIME_DIR}/System/libksOS/Include"
|
||||||
|
|
||||||
|
printf 'CompileFlags:\n Add:\n - -xc\n - --target=aarch64-none-elf\n - -ffreestanding\n - -I%s\n' "${INCLUDE_DIR}" > "${RUNTIME_DIR}/.clangd"
|
||||||
|
|
||||||
|
echo "✅ Generated ${RUNTIME_DIR}/.clangd"
|
||||||
@@ -3,57 +3,38 @@
|
|||||||
|
|
||||||
set quiet := true
|
set quiet := true
|
||||||
|
|
||||||
OS_NAME := os()
|
OS_NAME := os()
|
||||||
ARCH_NAME := arch()
|
ARCH_NAME := arch()
|
||||||
|
|
||||||
HB_PREFIX := if ARCH_NAME == "aarch64" { "/opt/homebrew" } else { "/usr/local" }
|
HB_PREFIX := if ARCH_NAME == "aarch64" { "/opt/homebrew" } else { "/usr/local" }
|
||||||
export PATH := HB_PREFIX + "/bin:" + HB_PREFIX + "/sbin:" + env_var("PATH")
|
export PATH := HB_PREFIX + "/bin:" + HB_PREFIX + "/sbin:" + env_var("PATH")
|
||||||
|
ACCEL := if OS_NAME == "macos" { if ARCH_NAME == "aarch64" { "-accel hvf" } else { "" } } else if ARCH_NAME == "aarch64" { "-accel kvm" } else { "" }
|
||||||
ACCEL := if OS_NAME == "macos" {
|
|
||||||
if ARCH_NAME == "aarch64" { "-accel hvf" } else { "" }
|
|
||||||
} else {
|
|
||||||
if ARCH_NAME == "aarch64" { "-accel kvm" } else { "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU := if ARCH_NAME == "aarch64" { "host" } else { "max" }
|
CPU := if ARCH_NAME == "aarch64" { "host" } else { "max" }
|
||||||
|
OVMF_ARM := if OS_NAME == "macos" { HB_PREFIX + "/share/qemu/edk2-aarch64-code.fd" } else { BUILD_DIR + "/edk2/edk2-aarch64-code.fd" }
|
||||||
OVMF_ARM := if OS_NAME == "macos" {
|
DISPLAY_FLAGS := if OS_NAME == "macos" { "-display cocoa,show-cursor=on" } else { env_var_or_default("QEMU_DISPLAY", "-display sdl") }
|
||||||
HB_PREFIX + "/share/qemu/edk2-aarch64-code.fd"
|
|
||||||
} else {
|
|
||||||
BUILD_DIR + "/edk2/edk2-aarch64-code.fd"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DISPLAY_FLAGS := if OS_NAME == "macos" {
|
|
||||||
"-display cocoa,show-cursor=on"
|
|
||||||
} else {
|
|
||||||
env_var_or_default("QEMU_DISPLAY", "-display sdl")
|
|
||||||
}
|
|
||||||
|
|
||||||
ACCEL_INFO := if ACCEL == "" { "none (TCG)" } else { ACCEL }
|
ACCEL_INFO := if ACCEL == "" { "none (TCG)" } else { ACCEL }
|
||||||
RAM := "2G"
|
RAM := "2G"
|
||||||
|
|
||||||
export BUILD_DIR := justfile_directory() + "/.build"
|
export BUILD_DIR := justfile_directory() + "/.build"
|
||||||
export TEMP_DIR := BUILD_DIR + "/temp"
|
export TEMP_DIR := BUILD_DIR + "/temp"
|
||||||
export BOOT_BIN := BUILD_DIR + "/Bootloader/BOOTAA64.EFI"
|
export BOOT_BIN := BUILD_DIR + "/Bootloader/BOOTAA64.EFI"
|
||||||
export IMG_FILE := BUILD_DIR + "/ksOS.img"
|
export IMG_FILE := BUILD_DIR + "/ksOS.img"
|
||||||
|
|
||||||
mod Bootloader
|
mod Bootloader
|
||||||
mod Kernel
|
mod Kernel
|
||||||
|
mod Runtime
|
||||||
|
|
||||||
_default:
|
_default:
|
||||||
just --list
|
just --list
|
||||||
|
|
||||||
_prep:
|
_prep:
|
||||||
@mkdir -p {{BUILD_DIR}}/Bootloader
|
@mkdir -p {{ BUILD_DIR }}/Bootloader
|
||||||
@mkdir -p {{TEMP_DIR}}/Bootloader
|
@mkdir -p {{ TEMP_DIR }}/Bootloader
|
||||||
@mkdir -p {{BUILD_DIR}}/Kernel
|
@mkdir -p {{ BUILD_DIR }}/Kernel
|
||||||
@if [ "{{OS_NAME}}" != "macos" ]; then \
|
@if [ "{{ OS_NAME }}" != "macos" ]; then \
|
||||||
mkdir -p {{BUILD_DIR}}/edk2; \
|
mkdir -p {{ BUILD_DIR }}/edk2; \
|
||||||
if [ ! -f "{{OVMF_ARM}}" ]; then \
|
if [ ! -f "{{ OVMF_ARM }}" ]; then \
|
||||||
echo "⬇️ Downloading vanilla EDK2 for Linux..."; \
|
echo "⬇️ Downloading vanilla EDK2 for Linux..."; \
|
||||||
curl -sL -o "{{OVMF_ARM}}.bz2" "https://github.com/qemu/qemu/raw/master/pc-bios/edk2-aarch64-code.fd.bz2"; \
|
curl -sL -o "{{ OVMF_ARM }}.bz2" "https://github.com/qemu/qemu/raw/master/pc-bios/edk2-aarch64-code.fd.bz2"; \
|
||||||
bzip2 -d "{{OVMF_ARM}}.bz2"; \
|
bzip2 -d "{{ OVMF_ARM }}.bz2"; \
|
||||||
fi \
|
fi \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -61,21 +42,32 @@ _prep:
|
|||||||
@echo "🛠️ Building everything..."
|
@echo "🛠️ Building everything..."
|
||||||
just Bootloader build
|
just Bootloader build
|
||||||
just Kernel build
|
just Kernel build
|
||||||
|
just Runtime build
|
||||||
|
|
||||||
@_image: build
|
@_image: build
|
||||||
@echo "💾 Creating image..."
|
@echo "💾 Creating image..."
|
||||||
@dd if=/dev/zero of={{IMG_FILE}} bs=1M count=64 status=none
|
@dd if=/dev/zero of={{ IMG_FILE }} bs=1M count=128 status=none
|
||||||
@mkfs.fat -F 32 {{IMG_FILE}} > /dev/null
|
@mkfs.fat -F 32 {{ IMG_FILE }} > /dev/null
|
||||||
@mmd -i {{IMG_FILE}} ::/EFI ::/EFI/BOOT
|
@mmd -i {{ IMG_FILE }} ::/EFI ::/EFI/BOOT
|
||||||
@mcopy -i {{IMG_FILE}} {{BOOT_BIN}} ::/EFI/BOOT/BOOTAA64.EFI
|
@mmd -i {{ IMG_FILE }} ::/System
|
||||||
@mcopy -i {{IMG_FILE}} {{BUILD_DIR}}/Kernel/ksOSKernel.elf ::/ksOSKernel.elf
|
@mmd -i {{ IMG_FILE }} ::/Apps
|
||||||
|
@mcopy -i {{ IMG_FILE }} {{ BOOT_BIN }} ::/EFI/BOOT/BOOTAA64.EFI
|
||||||
|
@mcopy -i {{ IMG_FILE }} {{ BUILD_DIR }}/Kernel/ksOSKernel.elf ::/ksOSKernel.elf
|
||||||
|
# Pack Runtime into ISO
|
||||||
|
@if [ -d {{ BUILD_DIR }}/Runtime/System ] &&[ "$$(ls {{ BUILD_DIR }}/Runtime/System 2>/dev/null)" ]; then \
|
||||||
|
echo " 📦 Packing System runtime..."; \
|
||||||
|
mcopy -s -i {{ IMG_FILE }} {{ BUILD_DIR }}/Runtime/System/* ::/System/ || true; \
|
||||||
|
fi
|
||||||
|
@if [ -d {{ BUILD_DIR }}/Runtime/Apps ] &&[ "$$(ls {{ BUILD_DIR }}/Runtime/Apps 2>/dev/null)" ]; then \
|
||||||
|
echo " 📦 Packing Apps runtime..."; \
|
||||||
|
mcopy -s -i {{ IMG_FILE }} {{ BUILD_DIR }}/Runtime/Apps/* ::/Apps/ || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
run *FLAGS:
|
run *FLAGS:
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
FLAGS=" {{FLAGS}} "
|
FLAGS=" {{ FLAGS }} "
|
||||||
|
|
||||||
if [[ "$FLAGS" == *" -clean "* ]]; then
|
if [[ "$FLAGS" == *" -clean "* ]]; then
|
||||||
echo "🧹 Cleaning..."
|
echo "🧹 Cleaning..."
|
||||||
@@ -85,7 +77,7 @@ run *FLAGS:
|
|||||||
just _image
|
just _image
|
||||||
|
|
||||||
DEBUG_ARGS=""
|
DEBUG_ARGS=""
|
||||||
DISPLAY_ARGS="{{DISPLAY_FLAGS}}"
|
DISPLAY_ARGS="{{ DISPLAY_FLAGS }}"
|
||||||
STATE_MSG="Launching"
|
STATE_MSG="Launching"
|
||||||
|
|
||||||
if [[ "$FLAGS" == *" -debug "* ]]; then
|
if [[ "$FLAGS" == *" -debug "* ]]; then
|
||||||
@@ -97,16 +89,16 @@ run *FLAGS:
|
|||||||
DISPLAY_ARGS="-nographic"
|
DISPLAY_ARGS="-nographic"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🚀 $STATE_MSG (accel: {{ACCEL_INFO}})..."
|
echo "🚀 $STATE_MSG (accel: {{ ACCEL_INFO }})..."
|
||||||
|
|
||||||
qemu-system-aarch64 {{ACCEL}} \
|
qemu-system-aarch64 {{ ACCEL }} \
|
||||||
-machine virt,acpi=off \
|
-machine virt,acpi=off \
|
||||||
-cpu {{CPU}} \
|
-cpu {{ CPU }} \
|
||||||
-m {{RAM}} \
|
-m {{ RAM }} \
|
||||||
-device ramfb \
|
-device ramfb \
|
||||||
$DISPLAY_ARGS \
|
$DISPLAY_ARGS \
|
||||||
-drive if=pflash,format=raw,readonly=on,file={{OVMF_ARM}} \
|
-drive if=pflash,format=raw,readonly=on,file={{ OVMF_ARM }} \
|
||||||
-drive file={{IMG_FILE}},format=raw,if=none,id=hd0 \
|
-drive file={{ IMG_FILE }},format=raw,if=none,id=hd0 \
|
||||||
-device virtio-blk-device,drive=hd0 \
|
-device virtio-blk-device,drive=hd0 \
|
||||||
-serial stdio \
|
-serial stdio \
|
||||||
-monitor telnet:127.0.0.1:5555,server,nowait \
|
-monitor telnet:127.0.0.1:5555,server,nowait \
|
||||||
@@ -115,6 +107,7 @@ run *FLAGS:
|
|||||||
@clean:
|
@clean:
|
||||||
just Bootloader clean
|
just Bootloader clean
|
||||||
just Kernel clean
|
just Kernel clean
|
||||||
rm -rf {{BUILD_DIR}}
|
just Runtime clean
|
||||||
|
rm -rf {{ BUILD_DIR }}
|
||||||
rm -f compile_commands.json
|
rm -f compile_commands.json
|
||||||
rm -f ide-swift-toolchain.txt
|
rm -f ide-swift-toolchain.txt
|
||||||
|
|||||||
Reference in New Issue
Block a user