Compare commits

...

25 Commits

Author SHA1 Message Date
8bf1aac961 Finally, add a README.
It's perhaps too long, but that's better than it being too short.
2022-10-07 20:16:44 +02:00
028a1b1a3c libc: Enable even more warnings 2022-10-07 18:19:06 +02:00
b7ee746da3 Kernel: Enable even more warnings 2022-10-07 18:10:20 +02:00
dc389da74e Implement an ELFImage struct
This struct allows us to keep track of what memory is used by the loaded executable. For some reason, freeing this memory when the task exits triggers a kernel page fault, so I'm not doing that right now.
2022-10-07 17:54:05 +02:00
b2d43d66c4 Remove boot/font.psf from the initrd
This font file is not being used, since we are using an embedded font and that seems to work (should be loaded from the initrd in the future though)
2022-10-07 15:38:08 +02:00
13f69bc4fc Add LICENSE
I knew from the beginning this should be BSD-2 (my favorite license at the moment), but hadn't made a license file yet. Here it is!
2022-10-07 13:27:01 +00:00
1ee5deb0f0 Remove unnecessary include 2022-10-06 19:51:16 +02:00
3fd24133e9 I'm so dumb 2022-10-06 18:04:32 +02:00
4a50a9e027 that was a dumb bug to fix 2022-10-06 18:02:57 +02:00
594d79143e Kernel: enable -Wconversion 2022-10-06 17:13:34 +02:00
952d8fa294 Be more strict with warnings 2022-10-05 17:34:22 +02:00
560b0a1705 libc: Rename the _ folder to bits, as used internally by libraries 2022-10-04 19:11:54 +02:00
48b858af5a libc: Add strncpy and strncat, and deprecate strcpy and strcat (which, since we're building with -Werror, is an instant ban from using these functions) 2022-10-04 19:08:59 +02:00
a050ed9133 libc: add an internal macros.h header with headers to make attributes less verbose 2022-10-04 19:06:56 +02:00
c6ed8d2abb libc: remove duplicate declaration of strcpy 2022-10-04 18:59:13 +02:00
3bfdad7a75 Kernel: Remove outdated rule in Makefile 2022-10-04 18:52:02 +02:00
25928a2a8d Kernel: Always build config.cpp, even when it's not modified 2022-10-04 18:46:10 +02:00
7a998dda4d Kernel: Do not stop interrupts by default in the interrupt handler
I always knew you can choose if interrupts are enabled for a specific ISR in the IDT entry, but at some moment there was a bug and I thought maybe that fixed it. Now reverting that doesn't break anything, so... let's do it :)
2022-10-04 18:45:46 +02:00
8f310dd307 PMM: Map the page bitmap to kernel heap once the PMM and VMM are both initialized 2022-10-04 18:36:09 +02:00
5d8b825659 Add a few example apps/demos in C, and make the kernel choose a random one to demonstrate every boot 2022-10-03 21:24:38 +02:00
885e39f60f libc: fix printf to actually print correct more-than-one-digit numbers (hint: the bugfix was a very stupid one) 2022-10-03 20:30:12 +02:00
cb60e418b2 Add vprintf, (v)sprintf and (v)snprintf to libc + move the non v-printfs to stdio.cpp, since they can now call their v-variants and thus don't depend on internal_printf 2022-10-03 19:59:33 +02:00
9420484c9b Do not use __builtin_alloca in puts (could overflow the stack for large strings) 2022-10-03 19:05:04 +02:00
34aa953dbc Add printf() and puts(), quite primitive, looks like hex printing isn't there yet... 2022-10-03 19:00:10 +02:00
fc9868819f Moon 0.9-dev 2022-10-02 21:19:49 +02:00
60 changed files with 846 additions and 141 deletions

25
LICENSE Normal file
View File

@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2022, apio.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

72
README.md Normal file
View File

@ -0,0 +1,72 @@
# Luna
A simple kernel and userspace for the x86_64 platform, written mostly in C++.
## Features
Not so much at the moment.
- x86_64-compatible [kernel](kernel/).
- Keeps track of which [memory](kernel/src/memory/) is used and which memory is free, and can allocate memory for itself and [user programs](kernel/src/sys/mem.cpp).
- Can [load files](kernel/src/init/InitRD.cpp) from an [initial ramdisk](initrd/), no disk support yet.
- Basic preemptive multitasking, round-robin [scheduler](kernel/src/thread/) that can switch between tasks.
- Can [load userspace ELF programs](kernel/src/sys/elf/) from the initial ramdisk as user tasks.
- [System call](kernel/src/sys/) interface and bare-bones [C Library](libs/libc/).
- Some very simple [example programs](apps/), written in C, that the kernel then loads from the initial ramdisk.
## Setup
To build and run Luna, you will need to build a [GCC Cross-Compiler](https://wiki.osdev.org/Why_do_I_need_a_Cross_Compiler%3F) and cross-binutils for `x86_64-luna`. (Yes, Luna is advanced enough that it can use its own [OS-Specific Toolchain](https://wiki.osdev.org/OS_Specific_Toolchain), instead of a bare metal target like `x86_64-elf`. It is the first of my OS projects to be able to do so. The patches for Binutils and GCC are [binutils.patch](tools/binutils.patch) and [gcc.patch](tools/gcc.patch)).
You should start by installing the [required dependencies](https://wiki.osdev.org/GCC_Cross_Compiler#Installing_Dependencies).
Then, run `tools/setup.sh` to build the toolchain.
This script will check whether you have the required versions of the toolchain already setup, and will skip building them if so. (This means that it is used by the build scripts to install the toolchain if it is missing before building, so you could skip running it manually.)
Please beware that building GCC and Binutils can take some time, depending on your machine.
## Building
Yes, there is a Makefile sitting on the top level of the repository. It's tempting. But do not use it directly, since it depends on environment variables set by the build scripts.
There are a variety of scripts for building Luna.
`tools/build.sh` will build the kernel, libc and binaries.
`tools/rebuild.sh` will do a full rebuild of the kernel, libc and binaries.
`tools/install.sh` will install those to the system root and initial ramdisk.
`tools/sync-libc.sh` will install the libc headers to the system root, build libc and install it.
`tools/build-iso.sh` will build, install, and make an ISO disk image named Luna.iso.
`tools/build-stable-iso.sh` does the same thing as build-iso.sh, but configures the kernel so that the version does not show the commit hash (used for stable versions).
`tools/rebuild-iso.sh` will do a clean rebuild, install, and make an ISO disk image.
In most cases, you should just use `build-iso.sh`.
## Running
You should have [QEMU](https://www.qemu.org/) installed.
You can choose between 3 run scripts:
`tools/run.sh` is the one you should use in most cases. It will build (only files that have changed since last build), install, make an ISO image, and run Luna in QEMU.
`tools/rebuild-and-run.sh` will rebuild, install, make an ISO, and run Luna in QEMU.
`tools/debug.sh` will rebuild the kernel with debug symbols and optimizations disabled, install, make an ISO image, and run Luna in QEMU with a port open for GDB to connect to. (run `gdb initrd/boot/moon.elf`, `break _start`, `target remote :1234`, and then `debug.sh` for an optimal debugging experience)
Beware that running without hardware virtualization/with optimizations disabled may cause the kernel to behave differently, which is why I don't use it that often.
Essentially, since `run.sh` builds the toolchain if it hasn't been built, builds Luna if it hasn't been built, and runs it, you could just checkout this repo, run `run.sh`, and you're done. No need for the other scripts. Those are included for more fine-grained control/building step-by-step.
You can pass any arguments you want to the run scripts, and those will be forwarded to QEMU. Example: `tools/run.sh -m 512M -net none -machine q35`.
## Prebuilt images
Prebuilt ISO images for every version can be found at [pub.cloudapio.eu](https://pub.cloudapio.eu/luna).
These images are built manually whenever I decide to make a new version, and thus don't reflect the latest changes on the `main` branch.
## License
Luna is open-source and free software under the [BSD-2 License](LICENSE).

View File

@ -1,4 +1,4 @@
APPS := init
APPS := init fib leap art memeater
APPS_DIR := $(LUNA_ROOT)/apps
APPS_SRC := $(APPS_DIR)/src

18
apps/src/art.c Normal file
View File

@ -0,0 +1,18 @@
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
int main()
{
sleep(1);
syscall(SYS_paint, 0, 0, 400, 300, 0x000000FF);
sleep(1);
printf("Hello, colorful world!\n");
sleep(1);
printf("Press any key to restart.");
}

34
apps/src/fib.c Normal file
View File

@ -0,0 +1,34 @@
#include <luna.h>
#include <stdio.h>
#include <unistd.h>
void fib_next(unsigned long int* a, unsigned long int* b)
{
unsigned long int _a = *a;
unsigned long int _b = *b;
*a = *b;
*b = _a + _b;
}
int main()
{
unsigned long int fib_a = 1;
unsigned long int fib_b = 1;
printf("Calculating the 50 first Fibonacci numbers...\n");
sleep(2);
printf("%lu\n", fib_a);
msleep(500);
for (int i = 0; i < 49; i++)
{
printf("%lu\n", fib_b);
fib_next(&fib_a, &fib_b);
msleep(500);
}
printf("\nDone, press any key to restart.\n");
}

View File

@ -1,16 +1,10 @@
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
static void print(const char* message)
{
syscall(SYS_write, message, strlen(message));
}
#define println(message) print(message "\n")
int main()
{
if (gettid() == 0) // why are we the idle task?
@ -18,29 +12,27 @@ int main()
__luna_abort("SHENANIGANS! init is tid 0 (which is reserved for the idle task)\n");
}
println("Welcome to Luna from a C init!");
println("");
printf("Welcome to Luna!\n");
printf("Running as tid %ld\n\n", gettid());
sleep(1);
print("Your kernel version is ");
char version[40];
syscall(SYS_getversion, version, sizeof(version));
print(version);
println("\n");
printf("Your kernel version is %s\n\n", version);
sleep(2);
{
[[maybe_unused]] volatile int i;
char* variable = malloc(200);
*variable = 3;
printf("Allocated variable at address %lx\n", (unsigned long int)variable);
free(variable);
}
println("Press any key to restart.");
printf("Press any key to restart.\n");
return 0;
}

38
apps/src/leap.c Normal file
View File

@ -0,0 +1,38 @@
#include <luna.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
unsigned long random_year() // Return a year from 1000 to 2500.
{
unsigned long result = syscall(SYS_rand);
return (result % 1500) + 1000;
}
int is_leap(unsigned long year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main()
{
printf("Welcome to the Luna Leap Year Program!\n\n");
sleep(1);
printf("Choosing a random year between 1000 and 2500... ");
msleep(500);
unsigned long year = random_year();
printf("%lu!\n\n", year);
sleep(1);
printf("%lu is %s\n", year, is_leap(year) ? "a leap year!" : "not a leap year :(");
msleep(500);
printf("Press any key to restart.\n");
}

17
apps/src/memeater.c Normal file
View File

@ -0,0 +1,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define CHUNK 4194304 // 4 MB
int main()
{
printf("Welcome to memeater! This little program is designed to eat up all the memory on your system.\n");
sleep(1);
void* allocated = malloc(CHUNK);
do {
printf("Allocating 4 MB of memory... %lx\n", (unsigned long)allocated);
sleep(1);
} while ((allocated = malloc(CHUNK)));
printf("Out of memory.\n");
}

Binary file not shown.

View File

@ -3,8 +3,8 @@ MOON_SRC := $(MOON_DIR)/src
MOON_OBJ := $(MOON_DIR)/lib
MOON_BIN := $(MOON_DIR)/bin
CFLAGS := -Wall -Wextra -Werror -Os -ffreestanding -fstack-protector-all -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CXXFLAGS := -fno-rtti -fno-exceptions
CFLAGS := -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion -Os -ffreestanding -fstack-protector-all -fno-omit-frame-pointer -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
ASMFLAGS := -felf64
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000
@ -28,14 +28,14 @@ OBJS += $(patsubst $(MOON_SRC)/%.asm, $(MOON_OBJ)/%.asm.o, $(NASM_SRC))
default: $(MOON_BIN)/moon.elf
$(MOON_OBJ)/interrupts/handlers.cpp.o: $(MOON_SRC)/interrupts/handlers.cpp
@mkdir -p $(@D)
$(CXX) $(CFLAGS) -mgeneral-regs-only $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/main.cpp.o: $(MOON_SRC)/main.cpp
@mkdir -p $(@D)
$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/misc/config.cpp.o: $(MOON_SRC)/misc/config.cpp FORCE
@mkdir -p $(@D)
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $(MOON_SRC)/misc/config.cpp
$(MOON_OBJ)/init/Init.cpp.o: $(MOON_SRC)/init/Init.cpp
@mkdir -p $(@D)
$(CXX) $(CFLAGS) -fno-stack-protector $(CXXFLAGS) -o $@ -c $^
@ -63,4 +63,7 @@ clean:
install: $(MOON_BIN)/moon.elf
@mkdir -p $(@D)
cp $^ $(LUNA_ROOT)/initrd/boot/moon.elf
$(LUNA_ROOT)/tools/generate-symbols.sh
$(LUNA_ROOT)/tools/generate-symbols.sh
.PHONY: build clean install FORCE
FORCE:

View File

@ -30,15 +30,15 @@ namespace InitRD
struct File
{
char name[100];
int size;
int size_in_blocks;
uint64_t size;
uint64_t size_in_blocks;
void* addr;
};
int get_total_blocks();
uint64_t get_total_blocks();
File get_file(TarHeader* header);
void free_file(File& file);
TarHeader* get_block(int block_index);
TarHeader* get_block(uint64_t block_index);
bool is_valid_header(TarHeader* header);
uint64_t get_file_physical_address(File& file);

View File

@ -20,4 +20,8 @@ namespace PMM
uint64_t get_free();
uint64_t get_used();
uint64_t get_reserved();
uint64_t get_bitmap_size();
void map_bitmap_to_virtual();
};

View File

@ -16,6 +16,8 @@ namespace Paging
bool ignore1 : 1;
uint8_t Available : 3;
uint64_t Address : 52;
void set_address(uint64_t addr);
};
struct PageTable

View File

@ -13,7 +13,7 @@ namespace Paging
{
public:
void init(); // fetch page table from cr3
void init(PageTable* PML4);
void init(PageTable* cr3);
void map(uint64_t virtualAddress, uint64_t physicalAddress, int flags);
void remap(uint64_t virtualAddress, int flags);

View File

@ -1,8 +1,9 @@
#pragma once
#include "sys/elf/Image.h"
#include <stdint.h>
namespace ELFLoader
{
void* load_elf_from_address(uintptr_t addr);
void* load_elf_from_initrd(const char* filename);
ELFImage* load_elf_from_address(uintptr_t addr);
ELFImage* load_elf_from_initrd(const char* filename);
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
struct ELFSection
{
uintptr_t base;
uint64_t pages;
};
struct ELFImage
{
uintptr_t entry;
uint64_t section_count;
ELFSection sections[1];
};

View File

@ -1,5 +1,6 @@
#pragma once
#include "interrupts/Context.h"
#include "sys/elf/Image.h"
struct Task
{
@ -30,6 +31,8 @@ struct Task
bool floating_saved = false;
bool is_user_task();
ELFImage* image = nullptr;
};
void set_context_from_task(Task& task, Context* ctx);

View File

@ -53,13 +53,13 @@ bool ACPI::is_xsdt()
void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
{
bool isXSDT = is_xsdt();
int entries = (root_sdt->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4);
kdbgln("Searching for table %s in the %s at %lx (table contains %d entries)", signature, isXSDT ? "XSDT" : "RSDT",
uint64_t entries = (root_sdt->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4);
kdbgln("Searching for table %s in the %s at %lx (table contains %ld entries)", signature, isXSDT ? "XSDT" : "RSDT",
(uint64_t)root_sdt, entries);
for (int i = 0; i < entries; i++)
for (uint64_t i = 0; i < entries; i++)
{
kdbgln("Testing for table %s in entry %d", signature, i);
kdbgln("Testing for table %s in entry %ld", signature, i);
SDTHeader* h;
if (isXSDT)
{
@ -74,7 +74,7 @@ void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
}
if (!h)
{
kwarnln("Entry %d in the %s points to null", i, isXSDT ? "XSDT" : "RSDT");
kwarnln("Entry %ld in the %s points to null", i, isXSDT ? "XSDT" : "RSDT");
continue;
}
kdbgln("Physical address of entry: %lx", (uint64_t)h);
@ -82,7 +82,7 @@ void* ACPI::find_table(ACPI::SDTHeader* root_sdt, const char* signature)
kdbgln("Mapped entry to virtual address %lx", (uint64_t)realHeader);
if (!validate_sdt_header(realHeader))
{
kwarnln("Header of entry %d is not valid, skipping this entry", i);
kwarnln("Header of entry %ld is not valid, skipping this entry", i);
MemoryManager::release_unaligned_mapping(realHeader);
continue;
}

View File

@ -1,5 +1,8 @@
#include "acpi/SDT.h"
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wconversion"
bool ACPI::validate_sdt_header(ACPI::SDTHeader* header)
{
uint8_t sum = 0;
@ -7,4 +10,6 @@ bool ACPI::validate_sdt_header(ACPI::SDTHeader* header)
for (uint32_t i = 0; i < header->Length; i++) { sum += ((char*)header)[i]; }
return sum == 0;
}
}
#pragma GCC pop_options

View File

@ -68,14 +68,14 @@ static void set_base(GDTEntry* entry, uint32_t base)
{
entry->base0 = (base & 0xFFFF);
entry->base1 = (base >> 16) & 0xFF;
entry->base2 = (base >> 24) & 0xFF;
entry->base2 = (uint8_t)((base >> 24) & 0xFF);
}
static void set_limit(GDTEntry* entry, uint32_t limit)
{
ASSERT(limit <= 0xFFFFF);
entry->limit0 = limit;
entry->limit1_flags = (entry->limit1_flags & 0xF0) | (limit & 0xF);
entry->limit0 = limit & 0xFFFF;
entry->limit1_flags = (entry->limit1_flags & 0xF0) | ((limit >> 16) & 0xF);
}
void GDT::load()
@ -87,7 +87,7 @@ void GDT::load()
main_tss.rsp[0] = (uint64_t)MemoryManager::get_pages(4) + (4096 * 4) - 8; // allocate 16KB for the syscall stack
main_tss.iomap_base = sizeof(TSS);
set_base(&internal_gdt.tss, (uint64_t)&main_tss & 0xffffffff);
internal_gdt.tss2.base_high = (uint64_t)&main_tss >> 32;
internal_gdt.tss2.base_high = (uint32_t)(((uint64_t)&main_tss >> 32) & 0xffffffff);
set_limit(&internal_gdt.tss, sizeof(TSS) - 1);
kdbgln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size);
load_gdt(&gdtr);

View File

@ -1,3 +1,5 @@
#define MODULE "init"
#include "init/Init.h"
#include "assert.h"
#include "bootboot.h"
@ -57,6 +59,8 @@ void Init::early_init()
Mersenne::init();
kdbgln("Page bitmap uses %ld bytes of memory", PMM::get_bitmap_size());
__stack_chk_guard = Mersenne::get();
}

View File

@ -19,17 +19,17 @@ bool InitRD::is_initialized()
return initrd_initialized;
}
static inline int get_file_size_in_blocks(InitRD::File f)
static inline uint64_t get_file_size_in_blocks(InitRD::File f)
{
return f.size_in_blocks;
}
inline int InitRD::get_total_blocks()
inline uint64_t InitRD::get_total_blocks()
{
return bootboot.initrd_size / TAR_BLOCKSIZE;
}
inline InitRD::TarHeader* InitRD::get_block(int block_index)
inline InitRD::TarHeader* InitRD::get_block(uint64_t block_index)
{
return (TarHeader*)((uintptr_t)initrd_base + block_index * TAR_BLOCKSIZE);
}
@ -63,8 +63,8 @@ InitRD::File InitRD::get_file(TarHeader* header)
InitRD::File InitRD::open(const char* filename)
{
int block = 0;
int total_blocks = get_total_blocks();
uint64_t block = 0;
uint64_t total_blocks = get_total_blocks();
while (block < total_blocks)
{
TarHeader* hdr = (TarHeader*)get_block(block);
@ -83,7 +83,7 @@ InitRD::File InitRD::open(const char* filename)
block += get_file_size_in_blocks(f) + 1;
}
File nullFile;
nullFile.addr = NULL;
nullFile.addr = 0;
nullFile.size = 0;
memcpy(nullFile.name, "NULL", 5);
return nullFile;
@ -91,8 +91,8 @@ InitRD::File InitRD::open(const char* filename)
void InitRD::for_each(void (*callback)(File& f))
{
int block = 0;
int total_blocks = get_total_blocks();
uint64_t block = 0;
uint64_t total_blocks = get_total_blocks();
while (block < total_blocks)
{
TarHeader* hdr = (TarHeader*)get_block(block);

View File

@ -28,6 +28,6 @@ void IRQ::interrupt_handler(Context* context)
default: kwarnln("Unhandled IRQ: %ld", context->irq_number); break;
}
Mersenne::reseed();
PIC::send_eoi(context->irq_number);
PIC::send_eoi((unsigned char)(context->irq_number & 0xFF));
return;
}

View File

@ -106,7 +106,7 @@ void Interrupts::install()
INSTALL_ISR(46);
INSTALL_ISR(47);
kdbgln("Installing unused handler stubs for the rest of the IDT");
for (int i = 48; i < 256; i++) { INSTALL_UNUSED(i); }
for (short i = 48; i < 256; i++) { INSTALL_UNUSED(i); }
kdbgln("Installing syscall handler stub");
INSTALL_USER_ISR(66);
}

View File

@ -40,7 +40,6 @@ extern common_handler
section .text
global asm_common
asm_common:
cli
cld
push rax
push rbx

View File

@ -36,13 +36,13 @@ void PCI::raw_write32(uint32_t bus, uint32_t slot, uint32_t function, int32_t of
uint8_t PCI::raw_read8(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
{
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
return IO::inl(PCI_VALUE + (offset & 3));
return (uint8_t)(IO::inl(PCI_VALUE + (offset & 3)) & 0xFF);
}
uint16_t PCI::raw_read16(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
{
IO::outl(PCI_ADDRESS, raw_address(bus, slot, function, offset));
return IO::inl(PCI_VALUE + (offset & 2));
return (uint16_t)(IO::inl(PCI_VALUE + (offset & 2)) & 0xFFFF);
}
uint32_t PCI::raw_read32(uint32_t bus, uint32_t slot, uint32_t function, int32_t offset)
@ -112,7 +112,7 @@ void PCI::scan(void (*callback)(PCI::Device&))
// Multiple PCI host controllers
for (function = 0; function < 8; function++)
{
if (get_device_id(0, 0, function).vendor != 0xFFFF) break;
if (get_device_id(0, 0, function).vendor == 0xFFFF) break;
bus = function;
pci_scan_bus(bus, callback);
}

View File

@ -124,7 +124,32 @@ extern "C" void _start()
}
});
Scheduler::load_user_task("bin/init");
uint64_t demo = Mersenne::get() % 5;
switch (demo)
{
case 0:
kinfoln("Loading demo: example init program");
Scheduler::load_user_task("bin/init");
break;
case 1:
kinfoln("Loading demo: first 50 fibonacci numbers");
Scheduler::load_user_task("bin/fib");
break;
case 2:
kinfoln("Loading demo: leap year calculator");
Scheduler::load_user_task("bin/leap");
break;
case 3:
kinfoln("Loading demo: painting program");
Scheduler::load_user_task("bin/art");
break;
case 4:
kinfoln("Loading demo: memory eating program");
Scheduler::load_user_task("bin/memeater");
break;
default: break;
}
kinfoln("Prepared scheduler tasks");

View File

@ -13,6 +13,7 @@ void MemoryManager::init()
{
PMM::init();
kernelVMM.init();
PMM::map_bitmap_to_virtual();
}
void* MemoryManager::get_mapping(void* physicalAddress, int flags)

View File

@ -5,6 +5,7 @@
#include "bootboot.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/string.h"
extern BOOTBOOT bootboot;
@ -61,7 +62,7 @@ void PMM::init()
else
{
free_mem += MMapEnt_Size(ptr);
for (uint64_t i = 0; i < (MMapEnt_Size(ptr) / 4096); i++) { bitmap_set(index + i, false); }
for (uint64_t j = 0; j < (MMapEnt_Size(ptr) / 4096); j++) { bitmap_set(index + j, false); }
}
ptr++;
}
@ -78,7 +79,7 @@ static void bitmap_set(uint64_t index, bool value)
{
uint64_t byteIndex = index / 8;
uint8_t bitIndexer = 0b10000000 >> (index % 8);
virtual_bitmap_addr[byteIndex] &= ~bitIndexer;
virtual_bitmap_addr[byteIndex] &= (uint8_t)(~bitIndexer);
if (value) { virtual_bitmap_addr[byteIndex] |= bitIndexer; }
}
@ -169,4 +170,15 @@ uint64_t PMM::get_used()
uint64_t PMM::get_reserved()
{
return reserved_mem;
}
uint64_t PMM::get_bitmap_size()
{
return bitmap_size;
}
void PMM::map_bitmap_to_virtual()
{
virtual_bitmap_addr =
(char*)MemoryManager::get_unaligned_mappings(bitmap_addr, Utilities::get_blocks_from_size(4096, bitmap_size));
}

View File

@ -0,0 +1,11 @@
#include "memory/Paging.h"
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wconversion"
void Paging::PageDirectoryEntry::set_address(uint64_t addr)
{
this->Address = (addr >> 12);
}
#pragma GCC pop_options

View File

@ -12,9 +12,9 @@ namespace Paging
asm volatile("mov %%cr3, %0" : "=r"(PML4));
}
void VirtualMemoryManager::init(PageTable* PML4)
void VirtualMemoryManager::init(PageTable* cr3)
{
this->PML4 = PML4;
PML4 = cr3;
}
void VirtualMemoryManager::unmap(uint64_t virtualAddress)
@ -165,7 +165,7 @@ namespace Paging
PDP = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PDP)));
memset(PDP, 0, 0x1000);
PDE.Address = (uint64_t)PDP >> 12;
PDE.set_address((uint64_t)PDP);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
@ -185,7 +185,7 @@ namespace Paging
PD = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PD)));
memset(PD, 0, 0x1000);
PDE.Address = (uint64_t)PD >> 12;
PDE.set_address((uint64_t)PD);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
@ -205,7 +205,7 @@ namespace Paging
PT = (PageTable*)PMM::request_page();
ASSERT(!(PMM_DID_FAIL(PT)));
memset(PT, 0, 0x1000);
PDE.Address = (uint64_t)PT >> 12;
PDE.set_address((uint64_t)PT);
PDE.Present = true;
PDE.ReadWrite = true;
if (flags & User) PDE.UserSuper = true;
@ -222,7 +222,7 @@ namespace Paging
PDE.Present = true;
PDE.ReadWrite = flags & ReadWrite;
PDE.UserSuper = flags & User;
PDE.Address = physicalAddress >> 12;
PDE.set_address(physicalAddress);
PT->entries[P_i] = PDE;
}
}

View File

@ -2,6 +2,10 @@
#include <stdint.h>
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wsign-conversion" // FIXME: Actually solve these warnings.
/** Durand's Amazing Super Duper Memory functions. */
#define VERSION "1.1"
@ -24,22 +28,22 @@
#define ALIGN(ptr) \
if (ALIGNMENT > 1) \
{ \
uintptr_t diff; \
uintptr_t align_diff; \
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
if (diff != 0) \
align_diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
if (align_diff != 0) \
{ \
diff = ALIGNMENT - diff; \
ptr = (void*)((uintptr_t)ptr + diff); \
align_diff = ALIGNMENT - align_diff; \
ptr = (void*)((uintptr_t)ptr + align_diff); \
} \
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = diff + ALIGN_INFO; \
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = align_diff + ALIGN_INFO; \
}
#define UNALIGN(ptr) \
if (ALIGNMENT > 1) \
{ \
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
if (diff < (ALIGNMENT + ALIGN_INFO)) { ptr = (void*)((uintptr_t)ptr - diff); } \
uintptr_t align_diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
if (align_diff < (ALIGNMENT + ALIGN_INFO)) { ptr = (void*)((uintptr_t)ptr - align_diff); } \
}
#define LIBALLOC_MAGIC 0xc001c0de
@ -104,9 +108,9 @@ static void* liballoc_memset(void* s, int c, size_t n)
static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
{
char* cdest;
char* csrc;
const char* csrc;
unsigned int* ldest = (unsigned int*)s1;
unsigned int* lsrc = (unsigned int*)s2;
const unsigned int* lsrc = (const unsigned int*)s2;
while (n >= sizeof(unsigned int))
{
@ -115,7 +119,7 @@ static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
}
cdest = (char*)ldest;
csrc = (char*)lsrc;
csrc = (const char*)lsrc;
while (n > 0)
{
@ -739,3 +743,5 @@ void* PREFIX(realloc)(void* p, size_t size)
return ptr;
}
#pragma GCC pop_options

View File

@ -3,7 +3,7 @@
void MSR::write_to(uint32_t msr_num, uint64_t value)
{
uint32_t lo = value & 0xFFFFFFFF;
uint32_t hi = value << 32;
uint32_t hi = (uint32_t)(value >> 32);
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr_num));
}

View File

@ -8,7 +8,7 @@
#endif
#ifndef MOON_MINOR
#define MOON_MINOR 8
#define MOON_MINOR 9
#endif
#ifndef _MOON_SUFFIX

View File

@ -47,12 +47,12 @@ static void try_acpi_reboot()
case ACPI::SystemIO:
kdbgln("Attempting ACPI Reset via SystemIO: sending byte %d to port %lx", fadt->ResetValue,
fadt->ResetReg.Address);
IO::outb(fadt->ResetReg.Address, fadt->ResetValue);
IO::outb((uint16_t)fadt->ResetReg.Address, fadt->ResetValue);
break;
case ACPI::GeneralPurposeIO:
kdbgln("Attempting ACPI Reset via GeneralPurposeIO: sending byte %d to port %lx", fadt->ResetValue,
fadt->ResetReg.Address);
IO::outb(fadt->ResetReg.Address, fadt->ResetValue);
IO::outb((uint16_t)fadt->ResetReg.Address, fadt->ResetValue);
break;
default: kwarnln("This method of rebooting via ACPI is not yet implemented"); return;
}

View File

@ -57,7 +57,7 @@ extern "C" [[noreturn]] void __do_int_panic(Context* context, const char* file,
{
asm volatile("cli");
if (context->number >= 0x20 && context->number < 0x30) { PIC::send_eoi(context->irq_number); }
if (context->number >= 0x20 && context->number < 0x30) { PIC::send_eoi((uint8_t)(context->irq_number & 0xFF)); }
Task* task;
if ((task = Scheduler::current_task()))

View File

@ -3,7 +3,6 @@
#include "render/TextRenderer.h"
#include "std/stdlib.h"
#include "std/string.h"
#include <string.h>
typedef long int ssize_t;
@ -65,7 +64,7 @@ static int internal_printf(const char* format, PutString put_string_callback, ss
switch (current_char)
{
case 'c': {
buffer[buffer_insert_index++] = va_arg(ap, int);
buffer[buffer_insert_index++] = (char)va_arg(ap, int);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
@ -194,7 +193,7 @@ static int internal_printf(const char* format, PutString put_string_callback, ss
}
if (buffer_insert_index > 0) flush_buffer();
return written;
return (int)written;
}
int printf(const char* fmt, ...)

View File

@ -36,7 +36,7 @@ char* itoa(int32_t number, char* arr, int base)
while (number != 0)
{
r = number % base;
arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0';
arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0');
i++;
number /= base;
}
@ -56,7 +56,8 @@ char* itoa(int32_t number, char* arr, int base)
char* ltoa(int64_t number, char* arr, int base)
{
int i = 0, r, negative = 0;
int i = 0, negative = 0;
int64_t r;
if (number == 0)
{
@ -74,7 +75,7 @@ char* ltoa(int64_t number, char* arr, int base)
while (number != 0)
{
r = number % base;
arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0';
arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0');
i++;
number /= base;
}
@ -94,7 +95,8 @@ char* ltoa(int64_t number, char* arr, int base)
char* utoa(uint32_t number, char* arr, int base)
{
int i = 0, r;
int i = 0;
uint32_t r;
if (number == 0)
{
@ -106,7 +108,7 @@ char* utoa(uint32_t number, char* arr, int base)
while (number != 0)
{
r = number % base;
arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0';
arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0');
i++;
number /= base;
}
@ -120,7 +122,8 @@ char* utoa(uint32_t number, char* arr, int base)
char* ultoa(uint64_t number, char* arr, int base)
{
int i = 0, r;
int i = 0;
uint64_t r;
if (number == 0)
{
@ -132,7 +135,7 @@ char* ultoa(uint64_t number, char* arr, int base)
while (number != 0)
{
r = number % base;
arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0';
arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0');
i++;
number /= base;
}

View File

@ -47,7 +47,7 @@ char* strncat(char* dest, const char* src, size_t n)
size_t dest_len = strlen(dest);
size_t i;
for (i = 0; i < n && *(src + i); i++) *(char*)(dest + dest_len + i) = *(char*)(src + i);
for (i = 0; i < n && *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i);
*(char*)(dest + dest_len + i) = '\0';
@ -59,7 +59,7 @@ char* strcat(char* dest, const char* src)
size_t dest_len = strlen(dest);
size_t i;
for (i = 0; *(src + i); i++) *(char*)(dest + dest_len + i) = *(char*)(src + i);
for (i = 0; *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i);
*(char*)(dest + dest_len + i) = '\0';
@ -88,7 +88,7 @@ char* strstr(char* haystack, const char* needle)
void* memcpy(void* dest, const void* src, size_t n)
{
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = *((char*)src + i); }
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = *((const char*)src + i); }
return dest;
}

View File

@ -23,7 +23,7 @@ void Syscall::entry(Context* context)
case SYS_rand: sys_rand(context); break;
case SYS_getversion: sys_getversion(context, (char*)context->rdi, context->rsi); break;
case SYS_gettid: sys_gettid(context); break;
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, context->rdx); break;
case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break;
default: context->rax = -1; break;
}

View File

@ -5,6 +5,7 @@
#include "log/Log.h"
#include "memory/MemoryManager.h"
#include "misc/utils.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "sys/elf/ELF.h"
@ -18,7 +19,7 @@ static const char* format_permissions(uint32_t flags)
return perms;
}
void* ELFLoader::load_elf_from_initrd(const char* filename)
ELFImage* ELFLoader::load_elf_from_initrd(const char* filename)
{
InitRD::File elf_file = InitRD::open(filename);
if (!elf_file.addr)
@ -30,7 +31,7 @@ void* ELFLoader::load_elf_from_initrd(const char* filename)
return load_elf_from_address((uintptr_t)elf_file.addr);
}
void* ELFLoader::load_elf_from_address(uintptr_t addr)
ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)
{
Elf64_Ehdr* elf_ehdr = (Elf64_Ehdr*)addr;
if (strncmp((const char*)elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0)
@ -63,6 +64,9 @@ void* ELFLoader::load_elf_from_address(uintptr_t addr)
kwarnln("ELF file has no PHDRS");
return 0;
}
ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection));
memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection));
image->entry = elf_ehdr->e_entry;
int i;
Elf64_Phdr* phdr;
for (phdr = (Elf64_Phdr*)((uint64_t)addr + elf_ehdr->e_phoff), i = 0; i < elf_ehdr->e_phnum;
@ -77,13 +81,24 @@ void* ELFLoader::load_elf_from_address(uintptr_t addr)
kerrorln("Address is NULL, this is invalid :(");
return 0;
}
int pages = Utilities::get_blocks_from_size(0x1000, phdr->p_memsz);
uint64_t pages = Utilities::get_blocks_from_size(0x1000, phdr->p_memsz);
void* buffer = MemoryManager::get_pages_at(phdr->p_vaddr, pages,
phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
memcpy(buffer, (void*)(addr + phdr->p_offset), phdr->p_filesz);
memset((void*)((uint64_t)buffer + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
(image->section_count + 1) * sizeof(ELFSection));
ELFSection& section = image->sections[image->section_count];
section.base = (uintptr_t)buffer;
section.pages = pages;
image->section_count++;
}
else { kdbgln("skipping non-loadable segment"); }
}
return (void*)elf_ehdr->e_entry;
if (!image->section_count)
{
kfree(image);
return 0;
}
return image;
}

View File

@ -66,7 +66,7 @@ void sys_munmap(Context* context, void* address, size_t size)
context->rax = -1;
return;
}
int flags = kernelVMM.getFlags((uint64_t)address);
uint64_t flags = kernelVMM.getFlags((uint64_t)address);
if (!(flags & MAP_USER))
{
kdbgln("munmap failed: attempted to unmap a kernel page");

View File

@ -20,7 +20,7 @@ void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h,
uint32_t color = (uint32_t)c;
framebuffer0.paint_rect(x, y, w, h, Color::from_integer(color));
framebuffer0.paint_rect((uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h, Color::from_integer(color));
context->rax = 0;
}

View File

@ -11,7 +11,7 @@ static uint16_t divisor = 65535;
void PIT::initialize(uint64_t frequency)
{
divisor = base_frequency / frequency;
divisor = (uint16_t)(base_frequency / frequency);
kdbgln("Configuring PIT to use divisor %d (will tick %lu times per second)", divisor, frequency);
if (divisor < 100) divisor = 100;
IO::outb(PIT_CHANNEL_0_PORT, (uint8_t)(divisor & 0xFF));

View File

@ -117,7 +117,14 @@ void Scheduler::load_user_task(const char* filename)
Task* new_task = new Task;
ASSERT(new_task);
new_task->id = free_tid++;
new_task->regs.rip = (uint64_t)ELFLoader::load_elf_from_initrd(filename);
ELFImage* image = ELFLoader::load_elf_from_initrd(filename);
if (!image)
{
kerrorln("Failed to load %s from initrd", filename);
return;
}
new_task->regs.rip = image->entry;
new_task->image = image;
if (!new_task->regs.rip)
{
kwarnln("Failed to load user task %s", filename);
@ -154,6 +161,15 @@ void Scheduler::reap_task(Task* task)
kinfoln("reaping task %ld", exiting_task->id);
if (exiting_task->allocated_stack)
MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK);
if (exiting_task->image)
{
for (uint64_t i = 0; i < exiting_task->image->section_count; i++)
{
ELFSection& section = exiting_task->image->sections[i];
kdbgln("Task was using region %lx, which used %ld pages", section.base, section.pages);
}
kfree(exiting_task->image);
}
delete exiting_task;
}

View File

@ -5,8 +5,8 @@ LIBC_BIN := $(LIBC_DIR)/bin
DESTDIR ?= $(LUNA_BASE)/usr/lib
CFLAGS := -Wall -Wextra -Werror -Os -nostdlib -fno-omit-frame-pointer
CXXFLAGS := -fno-rtti -fno-exceptions
CFLAGS := -Os -nostdlib -fno-omit-frame-pointer -pedantic -Wall -Wextra -Werror -Wfloat-equal -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wcast-qual -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wredundant-decls -Wshadow -Wconversion
CXXFLAGS := -fno-rtti -fno-exceptions -Wsign-promo -Wstrict-null-sentinel -Wctor-dtor-privacy
ASMFLAGS := -felf64
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))

View File

@ -0,0 +1,8 @@
#ifndef __MACROS_H
#define __MACROS_H
#define noreturn __attribute__((noreturn))
#define align(n) __attribute__((aligned(n)))
#define deprecated(msg) __attribute__((deprecated(msg)))
#endif

View File

@ -1,10 +1,9 @@
#ifndef _LUNA_H
#define _LUNA_H
#include <bits/macros.h>
#include <sys/types.h>
#define noreturn __attribute__((noreturn))
#ifdef __cplusplus
extern "C"
{

View File

@ -18,13 +18,13 @@ extern "C"
{
#endif
long int __luna_syscall0(int sys_num);
long int __luna_syscall1(int sys_num, unsigned long int arg0);
long int __luna_syscall2(int sys_num, unsigned long int arg0, unsigned long int arg1);
long int __luna_syscall3(int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2);
long int __luna_syscall4(int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
long int __luna_syscall0(long int sys_num);
long int __luna_syscall1(long int sys_num, unsigned long int arg0);
long int __luna_syscall2(long int sys_num, unsigned long int arg0, unsigned long int arg1);
long int __luna_syscall3(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2);
long int __luna_syscall4(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3);
long int __luna_syscall5(int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
long int __luna_syscall5(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3, unsigned long int arg4);
#ifdef __cplusplus

View File

@ -28,6 +28,13 @@ extern "C"
size_t fwrite(const void*, size_t, size_t, FILE*);
void setbuf(FILE*, char*);
int vfprintf(FILE*, const char*, va_list);
int printf(const char*, ...);
int vprintf(const char*, va_list);
int sprintf(char*, const char*, ...);
int snprintf(char*, size_t, const char*, ...);
int vsprintf(char*, const char*, va_list);
int vsnprintf(char*, size_t, const char*, va_list);
int puts(const char*);
#ifdef __cplusplus
}

View File

@ -1,10 +1,9 @@
#ifndef _STDLIB_H
#define _STDLIB_H
#include <bits/macros.h>
#include <stddef.h>
#define noreturn __attribute__((noreturn))
#ifdef __cplusplus
extern "C"
{

View File

@ -1,6 +1,7 @@
#ifndef _STRING_H
#define _STRING_H
#include <bits/macros.h>
#include <stddef.h>
#ifdef __cplusplus
@ -10,13 +11,18 @@ extern "C"
void* memcpy(void*, const void*, size_t);
void* memset(void*, int, size_t);
char* strcpy(char*, const char*);
size_t strlen(const char*);
char* strcpy(char*, const char*);
char* strchr(const char*, int);
char* strcat(char*, const char*);
void* memclr(void*, size_t);
size_t strlen(const char*);
deprecated("strcpy is unsafe and should not be used; use strncpy instead") char* strcpy(char*, const char*);
char* strncpy(char*, const char*, size_t);
char* strchr(const char*, int);
deprecated("strcat is unsafe and should not be used; use strncat instead") char* strcat(char*, const char*);
char* strncat(char*, const char*, size_t);
#ifdef __cplusplus
}
#endif

View File

@ -20,7 +20,7 @@ void* liballoc_alloc(size_t size)
int liballoc_free(void* address, size_t size)
{
int result = syscall(SYS_munmap, address, size * 4096);
int result = (int)syscall(SYS_munmap, address, size * 4096);
if (result < 0) return 1;
else
return 0;

View File

@ -1,4 +1,8 @@
#include <_/liballoc.h>
#include <bits/liballoc.h>
#pragma GCC push_options
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wsign-conversion" // FIXME: Actually solve these warnings.
#include <stddef.h>
#include <stdint.h>
@ -25,22 +29,22 @@
#define ALIGN(ptr) \
if (ALIGNMENT > 1) \
{ \
uintptr_t diff; \
uintptr_t align_diff; \
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
if (diff != 0) \
align_diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
if (align_diff != 0) \
{ \
diff = ALIGNMENT - diff; \
ptr = (void*)((uintptr_t)ptr + diff); \
align_diff = ALIGNMENT - align_diff; \
ptr = (void*)((uintptr_t)ptr + align_diff); \
} \
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = diff + ALIGN_INFO; \
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = align_diff + ALIGN_INFO; \
}
#define UNALIGN(ptr) \
if (ALIGNMENT > 1) \
{ \
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
if (diff < (ALIGNMENT + ALIGN_INFO)) { ptr = (void*)((uintptr_t)ptr - diff); } \
uintptr_t align_diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
if (align_diff < (ALIGNMENT + ALIGN_INFO)) { ptr = (void*)((uintptr_t)ptr - align_diff); } \
}
#define LIBALLOC_MAGIC 0xc001c0de
@ -105,9 +109,9 @@ static void* liballoc_memset(void* s, int c, size_t n)
static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
{
char* cdest;
char* csrc;
const char* csrc;
unsigned int* ldest = (unsigned int*)s1;
unsigned int* lsrc = (unsigned int*)s2;
const unsigned int* lsrc = (const unsigned int*)s2;
while (n >= sizeof(unsigned int))
{
@ -116,7 +120,7 @@ static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
}
cdest = (char*)ldest;
csrc = (char*)lsrc;
csrc = (const char*)lsrc;
while (n > 0)
{
@ -740,3 +744,5 @@ void* PREFIX(realloc)(void* p, size_t size)
return ptr;
}
#pragma GCC pop_options

View File

@ -14,7 +14,7 @@ extern "C"
unsigned int msleep(unsigned int ms)
{
return syscall(SYS_sleep, ms);
return (unsigned int)syscall(SYS_sleep, ms);
}
noreturn void __luna_abort(const char* message)

View File

@ -1,34 +1,34 @@
#include <luna/syscall.h>
long int __luna_syscall0(int sys_num)
long int __luna_syscall0(long int sys_num)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num));
return result;
}
long int __luna_syscall1(int sys_num, unsigned long int arg0)
long int __luna_syscall1(long int sys_num, unsigned long int arg0)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0));
return result;
}
long int __luna_syscall2(int sys_num, unsigned long int arg0, unsigned long int arg1)
long int __luna_syscall2(long int sys_num, unsigned long int arg0, unsigned long int arg1)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0), "S"(arg1));
return result;
}
long int __luna_syscall3(int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2)
long int __luna_syscall3(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2)
{
long int result;
asm volatile("int $0x42" : "=a"(result) : "a"(sys_num), "D"(arg0), "S"(arg1), "d"(arg2));
return result;
}
long int __luna_syscall4(int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
long int __luna_syscall4(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3)
{
long int result;
@ -37,7 +37,7 @@ long int __luna_syscall4(int sys_num, unsigned long int arg0, unsigned long int
return result;
}
long int __luna_syscall5(int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
long int __luna_syscall5(long int sys_num, unsigned long int arg0, unsigned long int arg1, unsigned long int arg2,
unsigned long int arg3, unsigned long int arg4)
{
long int result;

307
libs/libc/src/printf.cpp Normal file
View File

@ -0,0 +1,307 @@
#include <luna.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
typedef long int ssize_t;
static void __strrev(char* arr, int size)
{
int left = 0;
int right = size - 1;
for (int i = left; i < right; i++)
{
char temp = arr[i];
arr[i] = arr[right];
arr[right] = temp;
right--;
}
}
template <typename IntegerType> static char* __unsignedtoa(IntegerType number, char* arr, int base)
{
int i = 0;
if (number == 0)
{
arr[i] = '0';
arr[i + 1] = '\0';
return arr;
}
while (number != 0)
{
IntegerType r = number % (IntegerType)base;
arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0');
i++;
number /= base;
}
__strrev(arr, i);
arr[i] = '\0';
return arr;
}
template <typename IntegerType> static char* __signedtoa(IntegerType number, char* arr, int base)
{
int i = 0, negative = 0;
if (number == 0)
{
arr[i] = '0';
arr[i + 1] = '\0';
return arr;
}
if (number < 0 && base == 10)
{
number *= -1;
negative = 1;
}
while (number != 0)
{
IntegerType r = number % base;
arr[i] = (char)((r > 9) ? (r - 10) + 'a' : r + '0');
i++;
number /= base;
}
if (negative)
{
arr[i] = '-';
i++;
}
__strrev(arr, i);
arr[i] = '\0';
return arr;
}
#pragma GCC push_options
#pragma GCC optimize("O0")
template <typename PutString>
static int internal_printf(const char* format, PutString put_string_callback, ssize_t max, va_list ap)
{
char buffer[1025]; // 1024 with null terminator
size_t format_size = strlen(format);
size_t format_index = 0;
size_t buffer_insert_index = 0;
ssize_t max_remaining = max;
size_t written = 0;
auto flush_buffer = [&]() {
size_t buffer_length = buffer_insert_index;
written += buffer_length;
buffer_insert_index = 0;
if (max_remaining < 0)
{
buffer[buffer_length] = 0;
put_string_callback(buffer);
return;
}
if (max_remaining == 0) { return; }
if (buffer_length <= (size_t)max_remaining)
{
max_remaining -= buffer_length;
buffer[buffer_length] = 0;
put_string_callback(buffer);
}
else
{
buffer[max_remaining] = 0;
max_remaining = 0;
put_string_callback(buffer);
}
};
bool is_long = false;
bool is_unsigned_long = false;
bool preserve_format = false;
while (format_index < format_size)
{
char current_char = format[format_index];
if (current_char == '%' || preserve_format)
{
if (!preserve_format && format_index + 1 == format_size) // end of format string
{
format_index++;
continue;
}
else
{
if (!preserve_format) format_index++;
preserve_format = false;
current_char = format[format_index];
switch (current_char)
{
case 'c': {
buffer[buffer_insert_index++] = (char)va_arg(ap, int);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case '%': {
buffer[buffer_insert_index++] = '%';
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case 'z': {
is_unsigned_long = true;
preserve_format = true;
break;
}
case 'l': {
is_long = true;
preserve_format = true;
break;
}
case 'd': {
if (is_unsigned_long)
{
char result[25];
__unsignedtoa<unsigned long>(va_arg(ap, uint64_t), result, 10);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
is_unsigned_long = is_long = false;
}
else if (is_long)
{
char result[25];
__signedtoa<long>(va_arg(ap, int64_t), result, 10);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
is_unsigned_long = is_long = false;
}
else
{
char result[25];
__signedtoa<int>(va_arg(ap, int32_t), result, 10);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
}
break;
}
case 'u': {
if (is_unsigned_long || is_long)
{
char result[25];
__unsignedtoa<unsigned long>(va_arg(ap, uint64_t), result, 10);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
is_unsigned_long = is_long = false;
}
else
{
char result[25];
__unsignedtoa<unsigned int>(va_arg(ap, uint32_t), result, 10);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
}
break;
}
case 'x': {
if (is_unsigned_long || is_long)
{
char result[25];
__unsignedtoa<unsigned long>(va_arg(ap, uint64_t), result, 16);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
is_unsigned_long = is_long = false;
}
else
{
char result[25];
__unsignedtoa<unsigned int>(va_arg(ap, uint32_t), result, 16);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
}
break;
}
case 's': {
const char* str = va_arg(ap, const char*);
while (strlen(str) > 1024)
{
flush_buffer();
memcpy(buffer, str, 1024);
str += 1024;
buffer_insert_index = 1024;
}
if (buffer_insert_index + strlen(str) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, str, strlen(str));
buffer_insert_index += strlen(str);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
default: {
NOT_IMPLEMENTED("internal_printf: unknown format specifier");
}
}
}
}
else
{
buffer[buffer_insert_index++] = current_char;
if (buffer_insert_index == 1024) flush_buffer();
}
format_index++;
}
if (buffer_insert_index > 0) flush_buffer();
return (int)written;
}
#pragma GCC pop_options
extern "C"
{
int vprintf(const char* format, va_list ap)
{
return internal_printf(
format, [](const char* s) { syscall(SYS_write, s, strlen(s)); }, -1, ap);
}
int vsprintf(char* str, const char* format, va_list ap)
{
return internal_printf(
format,
[&](const char* s) {
if (str) strncat(str, s, 1025);
},
-1, ap);
}
int vsnprintf(char* str, size_t max, const char* format, va_list ap)
{
return internal_printf(
format,
[&](const char* s) {
if (str) strncat(str, s, 1025);
},
max == 0 ? 0 : max - 1, ap);
}
}

View File

@ -1,5 +1,9 @@
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
@ -43,4 +47,34 @@ extern "C"
{
NOT_IMPLEMENTED("vfprintf");
}
int puts(const char* s)
{
long nwritten = syscall(SYS_write, s, strlen(s));
nwritten += syscall(SYS_write, "\n", 1);
return (int)nwritten;
}
int snprintf(char* str, size_t max, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vsnprintf(str, max, format, ap);
va_end(ap);
return written;
}
int sprintf(char* str, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vsprintf(str, format, ap);
va_end(ap);
return written;
}
int printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int written = vprintf(format, ap);
va_end(ap);
return written;
}
}

View File

@ -5,7 +5,7 @@ extern "C"
{
void* memcpy(void* dest, const void* src, size_t n)
{
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = *((char*)src + i); }
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = *((const char*)src + i); }
return dest;
}
@ -29,12 +29,31 @@ extern "C"
return dest;
}
char* strncpy(char* dest, const char* src, size_t n)
{
size_t src_len = strlen(src) + 1; // NULL byte
memcpy(dest, src, src_len > n ? n : src_len);
return dest;
}
char* strcat(char* dest, const char* src)
{
size_t dest_len = strlen(dest);
size_t i;
for (i = 0; *(src + i); i++) *(char*)(dest + dest_len + i) = *(char*)(src + i);
for (i = 0; *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i);
*(char*)(dest + dest_len + i) = '\0';
return dest;
}
char* strncat(char* dest, const char* src, size_t n)
{
size_t dest_len = strlen(dest);
size_t i;
for (i = 0; i < n && *(src + i); i++) *(char*)(dest + dest_len + i) = *(const char*)(src + i);
*(char*)(dest + dest_len + i) = '\0';