Compare commits
25 Commits
dae2ff8d50
...
8bf1aac961
Author | SHA1 | Date | |
---|---|---|---|
8bf1aac961 | |||
028a1b1a3c | |||
b7ee746da3 | |||
dc389da74e | |||
b2d43d66c4 | |||
13f69bc4fc | |||
1ee5deb0f0 | |||
3fd24133e9 | |||
4a50a9e027 | |||
594d79143e | |||
952d8fa294 | |||
560b0a1705 | |||
48b858af5a | |||
a050ed9133 | |||
c6ed8d2abb | |||
3bfdad7a75 | |||
25928a2a8d | |||
7a998dda4d | |||
8f310dd307 | |||
5d8b825659 | |||
885e39f60f | |||
cb60e418b2 | |||
9420484c9b | |||
34aa953dbc | |||
fc9868819f |
25
LICENSE
Normal file
25
LICENSE
Normal 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
72
README.md
Normal 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).
|
@ -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
18
apps/src/art.c
Normal 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
34
apps/src/fib.c
Normal 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");
|
||||
}
|
@ -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
38
apps/src/leap.c
Normal 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
17
apps/src/memeater.c
Normal 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.
@ -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:
|
@ -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);
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
15
kernel/include/sys/elf/Image.h
Normal file
15
kernel/include/sys/elf/Image.h
Normal 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];
|
||||
};
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -40,7 +40,6 @@ extern common_handler
|
||||
section .text
|
||||
global asm_common
|
||||
asm_common:
|
||||
cli
|
||||
cld
|
||||
push rax
|
||||
push rbx
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
||||
|
@ -13,6 +13,7 @@ void MemoryManager::init()
|
||||
{
|
||||
PMM::init();
|
||||
kernelVMM.init();
|
||||
PMM::map_bitmap_to_virtual();
|
||||
}
|
||||
|
||||
void* MemoryManager::get_mapping(void* physicalAddress, int flags)
|
||||
|
@ -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));
|
||||
}
|
11
kernel/src/memory/Paging.cpp
Normal file
11
kernel/src/memory/Paging.cpp
Normal 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
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef MOON_MINOR
|
||||
#define MOON_MINOR 8
|
||||
#define MOON_MINOR 9
|
||||
#endif
|
||||
|
||||
#ifndef _MOON_SUFFIX
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()))
|
||||
|
@ -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, ...)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
8
libs/libc/include/bits/macros.h
Normal file
8
libs/libc/include/bits/macros.h
Normal 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
|
@ -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"
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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
|
@ -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)
|
||||
|
@ -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
307
libs/libc/src/printf.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user